xref: /inferno-os/os/port/devkprof.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
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 #ifndef LRES
9 #define	LRES	3		/* log of PC resolution */
10 #endif
11 
12 #define	SZ	4		/* sizeof of count cell; well known as 4 */
13 
14 enum {
15 	SpecialTotalTicks,
16 	SpecialOutsideTicks,
17 	SpecialMicroSecondsPerTick,
18 	SpecialSamples,
19 	SpecialSampleSize,
20 	SpecialSampleLogBucketSize,
21 	SpecialMax
22 };
23 
24 struct
25 {
26 	int	minpc;
27 	int	maxpc;
28 	int	nbuf;
29 	int	time;
30 	ulong	*buf;
31 }kprof;
32 
33 enum{
34 	Qdir,
35 	Qdata,
36 	Qctl,
37 	Kprofmaxqid,
38 };
39 
40 Dirtab kproftab[]={
41 	".",		{Qdir, 0, QTDIR},	0,	0500,
42 	"kpdata",	{Qdata},		0,	0600,
43 	"kpctl",	{Qctl},		0,	0600,
44 };
45 
46 void kproftimer(ulong);
47 void	(*kproftick)(ulong);
48 
49 static void
50 kprofinit(void)
51 {
52 	if(SZ != sizeof kprof.buf[0])
53 		panic("kprof size");
54 }
55 
56 static void
57 kprofbufinit(void)
58 {
59 	kprof.buf[SpecialMicroSecondsPerTick] = archkprofmicrosecondspertick();
60 	kprof.buf[SpecialSamples] = kprof.nbuf;
61 	kprof.buf[SpecialSampleSize] = SZ;
62 	kprof.buf[SpecialSampleLogBucketSize] = LRES;
63 }
64 
65 static Chan *
66 kprofattach(char *spec)
67 {
68 	ulong n;
69 
70 	/* allocate when first used */
71 	kproftick = kproftimer;
72 	kprof.minpc = KTZERO;
73 	kprof.maxpc = (ulong)etext;
74 	kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES;
75 	n = kprof.nbuf*SZ;
76 	if(kprof.buf == 0) {
77 		kprof.buf = xalloc(n);
78 		if(kprof.buf == 0)
79 			error(Enomem);
80 	}
81 	kproftab[0].length = n;
82 	kprofbufinit();
83 	return devattach('K', spec);
84 }
85 
86 static Walkqid*
87 kprofwalk(Chan *c, Chan *nc, char **name, int nname)
88 {
89 	return devwalk(c, nc, name, nname, kproftab, nelem(kproftab), devgen);
90 }
91 
92 static int
93 kprofstat(Chan *c, uchar *db, int n)
94 {
95 	return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
96 }
97 
98 static Chan *
99 kprofopen(Chan *c, int omode)
100 {
101 	if(c->qid.type & QTDIR){
102 		if(omode != OREAD)
103 			error(Eperm);
104 	}
105 	c->mode = openmode(omode);
106 	c->flag |= COPEN;
107 	c->offset = 0;
108 	return c;
109 }
110 
111 void
112 kprofclose(Chan*)
113 {
114 }
115 
116 static long
117 kprofread(Chan *c, void *va, long n, vlong offset)
118 {
119 	ulong tabend;
120 	ulong w, *bp;
121 	uchar *a, *ea;
122 
123 	switch((ulong)c->qid.path){
124 	case Qdir:
125 		return devdirread(c, va, n, kproftab, nelem(kproftab), devgen);
126 
127 	case Qdata:
128 		tabend = kprof.nbuf*SZ;
129 		if(offset & (SZ-1))
130 			error(Ebadarg);
131 		if(offset >= tabend){
132 			n = 0;
133 			break;
134 		}
135 		if(offset+n > tabend)
136 			n = tabend-offset;
137 		n &= ~(SZ-1);
138 		a = va;
139 		ea = a + n;
140 		bp = kprof.buf + offset/SZ;
141 		while(a < ea){
142 			w = *bp++;
143 			*a++ = w>>24;
144 			*a++ = w>>16;
145 			*a++ = w>>8;
146 			*a++ = w>>0;
147 		}
148 		break;
149 
150 	default:
151 		n = 0;
152 		break;
153 	}
154 	return n;
155 }
156 
157 static long
158 kprofwrite(Chan *c, void *vp, long n, vlong offset)
159 {
160 	char *a;
161 	USED(offset);
162 
163 	a = vp;
164 	switch((ulong)c->qid.path){
165 	case Qctl:
166 		if(strncmp(a, "startclr", 8) == 0){
167 			memset((char *)kprof.buf, 0, kprof.nbuf*SZ);
168 			kprofbufinit();
169 			archkprofenable(1);
170 			kprof.time = 1;
171 		}else if(strncmp(a, "start", 5) == 0) {
172 			archkprofenable(1);
173 			kprof.time = 1;
174 		}
175 		else if(strncmp(a, "stop", 4) == 0) {
176 			archkprofenable(0);
177 			kprof.time = 0;
178 		}
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[SpecialTotalTicks]++;
203 	if(kprof.minpc + (SpecialMax << LRES) <= pc && pc < kprof.maxpc){
204 		pc -= kprof.minpc;
205 		pc >>= LRES;
206 		kprof.buf[pc]++;
207 	}else
208 		kprof.buf[SpecialOutsideTicks]++;
209 }
210 
211 Dev kprofdevtab = {
212 	'K',
213 	"kprof",
214 
215 	devreset,
216 	kprofinit,
217 	devshutdown,
218 	kprofattach,
219 	kprofwalk,
220 	kprofstat,
221 	kprofopen,
222 	devcreate,
223 	kprofclose,
224 	kprofread,
225 	devbread,
226 	kprofwrite,
227 	devbwrite,
228 	devremove,
229 	devwstat,
230 };
231