summaryrefslogtreecommitdiff
path: root/sys/src/9/port/devkprof.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/9/port/devkprof.c192
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,
+};