diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/port/devkprof.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/port/devkprof.c')
-rwxr-xr-x | sys/src/9/port/devkprof.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/sys/src/9/port/devkprof.c b/sys/src/9/port/devkprof.c new file mode 100755 index 000000000..85ca17a58 --- /dev/null +++ b/sys/src/9/port/devkprof.c @@ -0,0 +1,192 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + + +#define LRES 3 /* log of PC resolution */ +#define SZ 4 /* sizeof of count cell; well known as 4 */ + +struct +{ + int minpc; + int maxpc; + int nbuf; + int time; + ulong *buf; +}kprof; + +enum{ + Kprofdirqid, + Kprofdataqid, + Kprofctlqid, +}; +Dirtab kproftab[]={ + ".", {Kprofdirqid, 0, QTDIR}, 0, DMDIR|0550, + "kpdata", {Kprofdataqid}, 0, 0600, + "kpctl", {Kprofctlqid}, 0, 0600, +}; + +static void +_kproftimer(ulong pc) +{ + extern void spldone(void); + + if(kprof.time == 0) + return; + /* + * if the pc is coming out of spllo or splx, + * use the pc saved when we went splhi. + */ + if(pc>=(ulong)spllo && pc<=(ulong)spldone) + pc = m->splpc; + + kprof.buf[0] += TK2MS(1); + if(kprof.minpc<=pc && pc<kprof.maxpc){ + pc -= kprof.minpc; + pc >>= LRES; + kprof.buf[pc] += TK2MS(1); + }else + kprof.buf[1] += TK2MS(1); +} + +static void +kprofinit(void) +{ + if(SZ != sizeof kprof.buf[0]) + panic("kprof size"); + kproftimer = _kproftimer; +} + +static Chan* +kprofattach(char *spec) +{ + ulong n; + + /* allocate when first used */ + kprof.minpc = KTZERO; + kprof.maxpc = (ulong)etext; + kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES; + n = kprof.nbuf*SZ; + if(kprof.buf == 0) { + kprof.buf = xalloc(n); + if(kprof.buf == 0) + error(Enomem); + } + kproftab[1].length = n; + return devattach('K', spec); +} + +static Walkqid* +kprofwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, kproftab, nelem(kproftab), devgen); +} + +static int +kprofstat(Chan *c, uchar *db, int n) +{ + return devstat(c, db, n, kproftab, nelem(kproftab), devgen); +} + +static Chan* +kprofopen(Chan *c, int omode) +{ + if(c->qid.type == QTDIR){ + if(omode != OREAD) + error(Eperm); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +kprofclose(Chan*) +{ +} + +static long +kprofread(Chan *c, void *va, long n, vlong off) +{ + ulong end; + ulong w, *bp; + uchar *a, *ea; + ulong offset = off; + + switch((int)c->qid.path){ + case Kprofdirqid: + return devdirread(c, va, n, kproftab, nelem(kproftab), devgen); + + case Kprofdataqid: + end = kprof.nbuf*SZ; + if(offset & (SZ-1)) + error(Ebadarg); + if(offset >= end){ + n = 0; + break; + } + if(offset+n > end) + n = end-offset; + n &= ~(SZ-1); + a = va; + ea = a + n; + bp = kprof.buf + offset/SZ; + while(a < ea){ + w = *bp++; + *a++ = w>>24; + *a++ = w>>16; + *a++ = w>>8; + *a++ = w>>0; + } + break; + + default: + n = 0; + break; + } + return n; +} + +static long +kprofwrite(Chan *c, void *a, long n, vlong) +{ + switch((int)(c->qid.path)){ + case Kprofctlqid: + if(strncmp(a, "startclr", 8) == 0){ + memset((char *)kprof.buf, 0, kprof.nbuf*SZ); + kprof.time = 1; + }else if(strncmp(a, "start", 5) == 0) + kprof.time = 1; + else if(strncmp(a, "stop", 4) == 0) + kprof.time = 0; + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev kprofdevtab = { + 'K', + "kprof", + + devreset, + kprofinit, + devshutdown, + kprofattach, + kprofwalk, + kprofstat, + kprofopen, + devcreate, + kprofclose, + kprofread, + devbread, + kprofwrite, + devbwrite, + devremove, + devwstat, +}; |