FreeBSD/Linux Kernel Cross Reference
sys/port/devkprof.c
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
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
56 kprofinit(void)
57 {
58 if(SZ != sizeof kprof.buf[0])
59 panic("kprof size");
60 kproftimer = _kproftimer;
61 }
62
63 static Chan*
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*
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
89 kprofstat(Chan *c, uchar *db, int n)
90 {
91 return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
92 }
93
94 static Chan*
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
108 kprofclose(Chan*)
109 {
110 }
111
112 static long
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
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 };
Cache object: 49a5b66657e22b3199dabca6dfa45543
|