xref: /plan9-contrib/sys/src/9k/port/devkprof.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
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