xref: /plan9-contrib/sys/src/9/port/devkprof.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier #define	LRES	3		/* log of PC resolution */
103e12c5d1SDavid du Colombier #define	SZ	4		/* sizeof of count cell; well known as 4 */
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier struct
133e12c5d1SDavid du Colombier {
143e12c5d1SDavid du Colombier 	int	minpc;
153e12c5d1SDavid du Colombier 	int	maxpc;
163e12c5d1SDavid du Colombier 	int	nbuf;
173e12c5d1SDavid du Colombier 	int	time;
183e12c5d1SDavid du Colombier 	ulong	*buf;
193e12c5d1SDavid du Colombier }kprof;
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier enum{
223e12c5d1SDavid du Colombier 	Kprofdirqid,
233e12c5d1SDavid du Colombier 	Kprofdataqid,
243e12c5d1SDavid du Colombier 	Kprofctlqid,
253e12c5d1SDavid du Colombier };
267dd7cddfSDavid du Colombier Dirtab kproftab[]={
27*9a747e4fSDavid du Colombier 	".",	{Kprofdirqid, 0, QTDIR},		0,	DMDIR|0550,
283e12c5d1SDavid du Colombier 	"kpdata",	{Kprofdataqid},		0,	0600,
293e12c5d1SDavid du Colombier 	"kpctl",	{Kprofctlqid},		0,	0600,
303e12c5d1SDavid du Colombier };
313e12c5d1SDavid du Colombier 
327dd7cddfSDavid du Colombier static void
_kproftimer(ulong pc)337dd7cddfSDavid du Colombier _kproftimer(ulong pc)
343e12c5d1SDavid du Colombier {
357dd7cddfSDavid du Colombier 	extern void spldone(void);
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier 	if(kprof.time == 0)
387dd7cddfSDavid du Colombier 		return;
397dd7cddfSDavid du Colombier 	/*
407dd7cddfSDavid du Colombier 	 *  if the pc is coming out of spllo or splx,
417dd7cddfSDavid du Colombier 	 *  use the pc saved when we went splhi.
427dd7cddfSDavid du Colombier 	 */
437dd7cddfSDavid du Colombier 	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
447dd7cddfSDavid du Colombier 		pc = m->splpc;
45*9a747e4fSDavid du Colombier 
467dd7cddfSDavid du Colombier 	kprof.buf[0] += TK2MS(1);
477dd7cddfSDavid du Colombier 	if(kprof.minpc<=pc && pc<kprof.maxpc){
487dd7cddfSDavid du Colombier 		pc -= kprof.minpc;
497dd7cddfSDavid du Colombier 		pc >>= LRES;
507dd7cddfSDavid du Colombier 		kprof.buf[pc] += TK2MS(1);
517dd7cddfSDavid du Colombier 	}else
527dd7cddfSDavid du Colombier 		kprof.buf[1] += TK2MS(1);
533e12c5d1SDavid du Colombier }
543e12c5d1SDavid du Colombier 
557dd7cddfSDavid du Colombier static void
kprofinit(void)563e12c5d1SDavid du Colombier kprofinit(void)
573e12c5d1SDavid du Colombier {
583e12c5d1SDavid du Colombier 	if(SZ != sizeof kprof.buf[0])
593e12c5d1SDavid du Colombier 		panic("kprof size");
607dd7cddfSDavid du Colombier 	kproftimer = _kproftimer;
613e12c5d1SDavid du Colombier }
623e12c5d1SDavid du Colombier 
637dd7cddfSDavid du Colombier static Chan*
kprofattach(char * spec)643e12c5d1SDavid du Colombier kprofattach(char *spec)
653e12c5d1SDavid du Colombier {
663e12c5d1SDavid du Colombier 	ulong n;
673e12c5d1SDavid du Colombier 
683e12c5d1SDavid du Colombier 	/* allocate when first used */
693e12c5d1SDavid du Colombier 	kprof.minpc = KTZERO;
703e12c5d1SDavid du Colombier 	kprof.maxpc = (ulong)etext;
713e12c5d1SDavid du Colombier 	kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES;
723e12c5d1SDavid du Colombier 	n = kprof.nbuf*SZ;
733e12c5d1SDavid du Colombier 	if(kprof.buf == 0) {
743e12c5d1SDavid du Colombier 		kprof.buf = xalloc(n);
753e12c5d1SDavid du Colombier 		if(kprof.buf == 0)
763e12c5d1SDavid du Colombier 			error(Enomem);
773e12c5d1SDavid du Colombier 	}
78*9a747e4fSDavid du Colombier 	kproftab[1].length = n;
79*9a747e4fSDavid du Colombier 	return devattach('K', spec);
80*9a747e4fSDavid du Colombier }
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier static Walkqid*
kprofwalk(Chan * c,Chan * nc,char ** name,int nname)83*9a747e4fSDavid du Colombier kprofwalk(Chan *c, Chan *nc, char **name, int nname)
84*9a747e4fSDavid du Colombier {
85*9a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, kproftab, nelem(kproftab), devgen);
863e12c5d1SDavid du Colombier }
873e12c5d1SDavid du Colombier 
887dd7cddfSDavid du Colombier static int
kprofstat(Chan * c,uchar * db,int n)89*9a747e4fSDavid du Colombier kprofstat(Chan *c, uchar *db, int n)
903e12c5d1SDavid du Colombier {
91*9a747e4fSDavid du Colombier 	return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier 
947dd7cddfSDavid du Colombier static Chan*
kprofopen(Chan * c,int omode)953e12c5d1SDavid du Colombier kprofopen(Chan *c, int omode)
963e12c5d1SDavid du Colombier {
97*9a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR){
983e12c5d1SDavid du Colombier 		if(omode != OREAD)
993e12c5d1SDavid du Colombier 			error(Eperm);
1003e12c5d1SDavid du Colombier 	}
1013e12c5d1SDavid du Colombier 	c->mode = openmode(omode);
1023e12c5d1SDavid du Colombier 	c->flag |= COPEN;
1033e12c5d1SDavid du Colombier 	c->offset = 0;
1043e12c5d1SDavid du Colombier 	return c;
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier 
1077dd7cddfSDavid du Colombier static void
kprofclose(Chan *)1087dd7cddfSDavid du Colombier kprofclose(Chan*)
1093e12c5d1SDavid du Colombier {
1103e12c5d1SDavid du Colombier }
1113e12c5d1SDavid du Colombier 
1127dd7cddfSDavid du Colombier static long
kprofread(Chan * c,void * va,long n,vlong off)1137dd7cddfSDavid du Colombier kprofread(Chan *c, void *va, long n, vlong off)
1143e12c5d1SDavid du Colombier {
1157dd7cddfSDavid du Colombier 	ulong end;
1163e12c5d1SDavid du Colombier 	ulong w, *bp;
1173e12c5d1SDavid du Colombier 	uchar *a, *ea;
1187dd7cddfSDavid du Colombier 	ulong offset = off;
1193e12c5d1SDavid du Colombier 
120*9a747e4fSDavid du Colombier 	switch((int)c->qid.path){
1213e12c5d1SDavid du Colombier 	case Kprofdirqid:
1227dd7cddfSDavid du Colombier 		return devdirread(c, va, n, kproftab, nelem(kproftab), devgen);
1233e12c5d1SDavid du Colombier 
1243e12c5d1SDavid du Colombier 	case Kprofdataqid:
1257dd7cddfSDavid du Colombier 		end = kprof.nbuf*SZ;
1263e12c5d1SDavid du Colombier 		if(offset & (SZ-1))
1273e12c5d1SDavid du Colombier 			error(Ebadarg);
1287dd7cddfSDavid du Colombier 		if(offset >= end){
1293e12c5d1SDavid du Colombier 			n = 0;
1303e12c5d1SDavid du Colombier 			break;
1313e12c5d1SDavid du Colombier 		}
1327dd7cddfSDavid du Colombier 		if(offset+n > end)
1337dd7cddfSDavid du Colombier 			n = end-offset;
1343e12c5d1SDavid du Colombier 		n &= ~(SZ-1);
1353e12c5d1SDavid du Colombier 		a = va;
1363e12c5d1SDavid du Colombier 		ea = a + n;
1373e12c5d1SDavid du Colombier 		bp = kprof.buf + offset/SZ;
1383e12c5d1SDavid du Colombier 		while(a < ea){
1393e12c5d1SDavid du Colombier 			w = *bp++;
1403e12c5d1SDavid du Colombier 			*a++ = w>>24;
1413e12c5d1SDavid du Colombier 			*a++ = w>>16;
1423e12c5d1SDavid du Colombier 			*a++ = w>>8;
1433e12c5d1SDavid du Colombier 			*a++ = w>>0;
1443e12c5d1SDavid du Colombier 		}
1453e12c5d1SDavid du Colombier 		break;
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier 	default:
1483e12c5d1SDavid du Colombier 		n = 0;
1493e12c5d1SDavid du Colombier 		break;
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 	return n;
1523e12c5d1SDavid du Colombier }
1533e12c5d1SDavid du Colombier 
1547dd7cddfSDavid du Colombier static long
kprofwrite(Chan * c,void * a,long n,vlong)1557dd7cddfSDavid du Colombier kprofwrite(Chan *c, void *a, long n, vlong)
1563e12c5d1SDavid du Colombier {
157*9a747e4fSDavid du Colombier 	switch((int)(c->qid.path)){
1583e12c5d1SDavid du Colombier 	case Kprofctlqid:
1593e12c5d1SDavid du Colombier 		if(strncmp(a, "startclr", 8) == 0){
1603e12c5d1SDavid du Colombier 			memset((char *)kprof.buf, 0, kprof.nbuf*SZ);
1613e12c5d1SDavid du Colombier 			kprof.time = 1;
1623e12c5d1SDavid du Colombier 		}else if(strncmp(a, "start", 5) == 0)
1633e12c5d1SDavid du Colombier 			kprof.time = 1;
1643e12c5d1SDavid du Colombier 		else if(strncmp(a, "stop", 4) == 0)
1653e12c5d1SDavid du Colombier 			kprof.time = 0;
1663e12c5d1SDavid du Colombier 		break;
1673e12c5d1SDavid du Colombier 	default:
1683e12c5d1SDavid du Colombier 		error(Ebadusefd);
1693e12c5d1SDavid du Colombier 	}
1703e12c5d1SDavid du Colombier 	return n;
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1737dd7cddfSDavid du Colombier Dev kprofdevtab = {
174*9a747e4fSDavid du Colombier 	'K',
1757dd7cddfSDavid du Colombier 	"kprof",
1763e12c5d1SDavid du Colombier 
1777dd7cddfSDavid du Colombier 	devreset,
1787dd7cddfSDavid du Colombier 	kprofinit,
179*9a747e4fSDavid du Colombier 	devshutdown,
1807dd7cddfSDavid du Colombier 	kprofattach,
1817dd7cddfSDavid du Colombier 	kprofwalk,
1827dd7cddfSDavid du Colombier 	kprofstat,
1837dd7cddfSDavid du Colombier 	kprofopen,
1847dd7cddfSDavid du Colombier 	devcreate,
1857dd7cddfSDavid du Colombier 	kprofclose,
1867dd7cddfSDavid du Colombier 	kprofread,
1877dd7cddfSDavid du Colombier 	devbread,
1887dd7cddfSDavid du Colombier 	kprofwrite,
1897dd7cddfSDavid du Colombier 	devbwrite,
1907dd7cddfSDavid du Colombier 	devremove,
1917dd7cddfSDavid du Colombier 	devwstat,
1927dd7cddfSDavid du Colombier };
193