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
kprofinit(void)50 kprofinit(void)
51 {
52 if(SZ != sizeof kprof.buf[0])
53 panic("kprof size");
54 }
55
56 static void
kprofbufinit(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 *
kprofattach(char * spec)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*
kprofwalk(Chan * c,Chan * nc,char ** name,int nname)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
kprofstat(Chan * c,uchar * db,int n)93 kprofstat(Chan *c, uchar *db, int n)
94 {
95 return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
96 }
97
98 static Chan *
kprofopen(Chan * c,int omode)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
kprofclose(Chan *)112 kprofclose(Chan*)
113 {
114 }
115
116 static long
kprofread(Chan * c,void * va,long n,vlong offset)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
kprofwrite(Chan * c,void * vp,long n,vlong offset)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
kproftimer(ulong pc)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