xref: /plan9/sys/src/9/port/devkprof.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 
9 #define	LRES	3		/* log of PC resolution */
10 #define	SZ	4		/* sizeof of count cell; well known as 4 */
11 
12 struct
13 {
14 	int	minpc;
15 	int	maxpc;
16 	int	nbuf;
17 	int	time;
18 	ulong	*buf;
19 }kprof;
20 
21 enum{
22 	Kprofdirqid,
23 	Kprofdataqid,
24 	Kprofctlqid,
25 };
26 Dirtab kproftab[]={
27 	".",	{Kprofdirqid, 0, QTDIR},		0,	DMDIR|0550,
28 	"kpdata",	{Kprofdataqid},		0,	0600,
29 	"kpctl",	{Kprofctlqid},		0,	0600,
30 };
31 
32 static void
_kproftimer(ulong pc)33 _kproftimer(ulong pc)
34 {
35 	extern void spldone(void);
36 
37 	if(kprof.time == 0)
38 		return;
39 	/*
40 	 *  if the pc is coming out of spllo or splx,
41 	 *  use the pc saved when we went splhi.
42 	 */
43 	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
44 		pc = m->splpc;
45 
46 	kprof.buf[0] += TK2MS(1);
47 	if(kprof.minpc<=pc && pc<kprof.maxpc){
48 		pc -= kprof.minpc;
49 		pc >>= LRES;
50 		kprof.buf[pc] += TK2MS(1);
51 	}else
52 		kprof.buf[1] += TK2MS(1);
53 }
54 
55 static void
kprofinit(void)56 kprofinit(void)
57 {
58 	if(SZ != sizeof kprof.buf[0])
59 		panic("kprof size");
60 	kproftimer = _kproftimer;
61 }
62 
63 static Chan*
kprofattach(char * spec)64 kprofattach(char *spec)
65 {
66 	ulong n;
67 
68 	/* allocate when first used */
69 	kprof.minpc = KTZERO;
70 	kprof.maxpc = (ulong)etext;
71 	kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES;
72 	n = kprof.nbuf*SZ;
73 	if(kprof.buf == 0) {
74 		kprof.buf = xalloc(n);
75 		if(kprof.buf == 0)
76 			error(Enomem);
77 	}
78 	kproftab[1].length = n;
79 	return devattach('K', spec);
80 }
81 
82 static Walkqid*
kprofwalk(Chan * c,Chan * nc,char ** name,int nname)83 kprofwalk(Chan *c, Chan *nc, char **name, int nname)
84 {
85 	return devwalk(c, nc, name, nname, kproftab, nelem(kproftab), devgen);
86 }
87 
88 static int
kprofstat(Chan * c,uchar * db,int n)89 kprofstat(Chan *c, uchar *db, int n)
90 {
91 	return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
92 }
93 
94 static Chan*
kprofopen(Chan * c,int omode)95 kprofopen(Chan *c, int omode)
96 {
97 	if(c->qid.type == QTDIR){
98 		if(omode != OREAD)
99 			error(Eperm);
100 	}
101 	c->mode = openmode(omode);
102 	c->flag |= COPEN;
103 	c->offset = 0;
104 	return c;
105 }
106 
107 static void
kprofclose(Chan *)108 kprofclose(Chan*)
109 {
110 }
111 
112 static long
kprofread(Chan * c,void * va,long n,vlong off)113 kprofread(Chan *c, void *va, long n, vlong off)
114 {
115 	ulong end;
116 	ulong w, *bp;
117 	uchar *a, *ea;
118 	ulong offset = off;
119 
120 	switch((int)c->qid.path){
121 	case Kprofdirqid:
122 		return devdirread(c, va, n, kproftab, nelem(kproftab), devgen);
123 
124 	case Kprofdataqid:
125 		end = kprof.nbuf*SZ;
126 		if(offset & (SZ-1))
127 			error(Ebadarg);
128 		if(offset >= end){
129 			n = 0;
130 			break;
131 		}
132 		if(offset+n > end)
133 			n = end-offset;
134 		n &= ~(SZ-1);
135 		a = va;
136 		ea = a + n;
137 		bp = kprof.buf + offset/SZ;
138 		while(a < ea){
139 			w = *bp++;
140 			*a++ = w>>24;
141 			*a++ = w>>16;
142 			*a++ = w>>8;
143 			*a++ = w>>0;
144 		}
145 		break;
146 
147 	default:
148 		n = 0;
149 		break;
150 	}
151 	return n;
152 }
153 
154 static long
kprofwrite(Chan * c,void * a,long n,vlong)155 kprofwrite(Chan *c, void *a, long n, vlong)
156 {
157 	switch((int)(c->qid.path)){
158 	case Kprofctlqid:
159 		if(strncmp(a, "startclr", 8) == 0){
160 			memset((char *)kprof.buf, 0, kprof.nbuf*SZ);
161 			kprof.time = 1;
162 		}else if(strncmp(a, "start", 5) == 0)
163 			kprof.time = 1;
164 		else if(strncmp(a, "stop", 4) == 0)
165 			kprof.time = 0;
166 		break;
167 	default:
168 		error(Ebadusefd);
169 	}
170 	return n;
171 }
172 
173 Dev kprofdevtab = {
174 	'K',
175 	"kprof",
176 
177 	devreset,
178 	kprofinit,
179 	devshutdown,
180 	kprofattach,
181 	kprofwalk,
182 	kprofstat,
183 	kprofopen,
184 	devcreate,
185 	kprofclose,
186 	kprofread,
187 	devbread,
188 	kprofwrite,
189 	devbwrite,
190 	devremove,
191 	devwstat,
192 };
193