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