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