forsyth20121205-174063a80cc13 years agoHistory
722 lines · 11.7 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include	"../port/error.h"#include	<interp.h>#include	<isa.h>#include	"runt.h" static void	cpxec(Prog *);static void memprof(int, Heap*, ulong); extern	Inst*	pc2dispc(Inst*, Module*); static	int	interval = 100;	/* Sampling interval in milliseconds */ enum{	HSIZE	= 32,}; #define HASH(m)	((m)%HSIZE) /* cope with  multiple profilers some day */ typedef struct Record Record;struct Record{	int	id;	char*	name;	char*	path;	Inst*	base;	int	size;	/*Module*	m;	*/	ulong	mtime;	Qid	qid;	Record*	hash;	Record*	link;	ulong	bucket[1];}; struct{	Lock	l;	vlong	time;	Record*	hash[HSIZE];	Record*	list;} profile; typedef struct Pmod Pmod;struct Pmod{	char*	name;	Pmod*	link;} *pmods;	#define QSHIFT	4#define QID(q)		((ulong)(q).path&0xf)#define QPID(pid)	((pid)<<QSHIFT)#define PID(q)		((q).vers)#define PATH(q)	((ulong)(q).path&~((1<<QSHIFT)-1)) enum{	Qdir,	Qname,	Qpath,	Qhist,	Qpctl,	Qctl,}; Dirtab profdir[] ={	".",			{Qdir, 0, QTDIR},	0,	DMDIR|0555,	"name",		{Qname},	0,			0444,	"path",		{Qpath},	0,			0444,	"histogram",	{Qhist},	0,			0444,	"pctl",		{Qpctl},	0,			0222,	"ctl",			{Qctl},	0,			0222,}; enum{	Pnil,	/* null profiler */	Psam,	/* sampling profiler */	Pcov,	/* coverage profiler */	Pmem,	/* memory profiler */}; static int profiler = Pnil; static int ids;static int samplefn; static void sampler(void*); static Record*getrec(int id){	Record *r; 	for(r = profile.list; r != nil; r = r->link)		if(r->id == id)			break;	return r;} static voidaddpmod(char *m){	Pmod *p = malloc(sizeof(Pmod)); 	if(p == nil)		return;	p->name = malloc(strlen(m)+1);	if(p->name == nil){		free(p);		return;	}	strcpy(p->name, m);	p->link = pmods;	pmods = p;} static voidfreepmods(void){	Pmod *p, *np; 	for(p = pmods; p != nil; p = np){		free(p->name);		np = p->link;		free(p);	}	pmods = nil;} static intinpmods(char *m){	Pmod *p; 	for(p = pmods; p != nil; p = p->link)		if(strcmp(p->name, m) == 0)			return 1;	return 0;} static voidfreeprof(void){	int i;	Record *r, *nr; 	ids = 0;	profiler = Pnil;	freepmods();	for(r = profile.list; r != nil; r = nr){		free(r->path);		nr = r->link;		free(r);	}	profile.list = nil;	profile.time = 0;	for(i = 0; i < HSIZE; i++)		profile.hash[i] = nil;} static intprofgen(Chan *c, char *name, Dirtab *d, int nd, int s, Dir *dp){	Qid qid;	Record *r;	ulong path, perm, len;	Dirtab *tab; 	USED(name);	USED(d);	USED(nd); 	if(s == DEVDOTDOT) {		mkqid(&qid, Qdir, 0, QTDIR);		devdir(c, qid, "#P", 0, eve, 0555, dp);		return 1;	} 	if(c->qid.path == Qdir && c->qid.type & QTDIR) {		acquire();		if(s-- == 0){			tab = &profdir[Qctl];			mkqid(&qid, PATH(c->qid)|tab->qid.path, c->qid.vers, QTFILE);			devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);			release();			return 1;		}		r = profile.list;		while(s-- && r != nil)			r = r->link;		if(r == nil) {			release();			return -1;		}		sprint(up->genbuf, "%.8lux", (ulong)r->id);		mkqid(&qid, (r->id<<QSHIFT), r->id, QTDIR);		devdir(c, qid, up->genbuf, 0, eve, DMDIR|0555, dp);		release();		return 1;	}	if(s >= nelem(profdir)-1)		error(Enonexist);	/* was return -1; */	tab = &profdir[s];	path = PATH(c->qid); 	acquire();	r = getrec(PID(c->qid));	if(r == nil) {		release();		error(Enonexist);	/* was return -1; */	} 	perm = tab->perm;	len = tab->length;	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);	devdir(c, qid, tab->name, len, eve, perm, dp);	release();	return 1;} static Chan*profattach(char *spec){	return devattach('P', spec);} static Walkqid*profwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, 0, 0, profgen);} static intprofstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, profgen);} static Chan*profopen(Chan *c, int omode){	int qid;	Record *r; 	if(c->qid.type & QTDIR) {		if(omode != OREAD)			error(Eisdir);		c->mode = openmode(omode);		c->flag |= COPEN;		c->offset = 0;		return c;	} 	if(omode&OTRUNC)		error(Eperm); 	qid = QID(c->qid);	if(qid == Qctl || qid == Qpctl){		if (omode != OWRITE)			error(Eperm);	}	else{		if(omode != OREAD)			error(Eperm);	} 	if(qid != Qctl){		acquire();		r = getrec(PID(c->qid));		release();		if(r == nil)			error(Ethread);	} 	c->offset = 0;	c->flag |= COPEN;	c->mode = openmode(omode);	if(QID(c->qid) == Qhist)		c->aux = nil;	return c;} static intprofwstat(Chan *c, uchar *dp, int n){	Dir d;	Record *r; 	if(strcmp(up->env->user, eve))		error(Eperm);	if(c->qid.type & QTDIR)		error(Eperm);	acquire();	r = getrec(PID(c->qid));	release();	if(r == nil)		error(Ethread);	n = convM2D(dp, n, &d, nil);	if(n == 0)		error(Eshortstat);	d.mode &= 0777;	/* TO DO: copy to c->aux->perm, once that exists */	return n;} static voidprofclose(Chan *c){	USED(c);} static longprofread(Chan *c, void *va, long n, vlong offset){	int i;	Record *r;	char *a = va; 	if(c->qid.type & QTDIR)		return devdirread(c, a, n, 0, 0, profgen);	acquire();	r = getrec(PID(c->qid));	release();	if(r == nil)		error(Ethread);	switch(QID(c->qid)){	case Qname:		return readstr(offset, va, n, r->name);	case Qpath:		return readstr(offset, va, n, r->path);	case Qhist:		i = (int)c->aux;		while(i < r->size && r->bucket[i] == 0)			i++;		if(i >= r->size)			return 0;		c->aux = (void*)(i+1);		if(n < 20)			error(Etoosmall);		return sprint(a, "%d %lud", i, r->bucket[i]);	case Qctl:		error(Eperm);	}	return 0;} static longprofwrite(Chan *c, void *va, long n, vlong offset){	int i;	char *a = va;	char buf[128], *fields[128]; 	USED(va);	USED(n);	USED(offset); 	if(c->qid.type & QTDIR)		error(Eisdir);	switch(QID(c->qid)){	case Qctl:		if(n > sizeof(buf)-1)			n = sizeof(buf)-1;		memmove(buf, a, n);		buf[n] = 0;		i = getfields(buf, fields, nelem(fields), 1, " \t\n");		if(i > 0 && strcmp(fields[0], "module") == 0){			freepmods();			while(--i > 0)				addpmod(fields[i]);			return n;		}		if(i == 1){			if(strcmp(fields[0], "start") == 0){				if(profiler == Pnil) {					profiler = Psam;					if(!samplefn){						samplefn = 1;						kproc("prof", sampler, 0, 0);					}				}			}			else if(strcmp(fields[0], "startmp") == 0){				if(profiler == Pnil){					profiler = Pmem;					heapmonitor = memprof;				}			}			else if(strcmp(fields[0], "stop") == 0)				profiler = Pnil;			else if(strcmp(fields[0], "end") == 0){				profiler = Pnil;				freeprof();				interval = 100;			}			else				error(Ebadarg);		}		else if (i == 2){			if(strcmp(fields[0], "interval") == 0)				interval = strtoul(fields[1], nil, 0);			else if(strcmp(fields[0], "startcp") == 0){				Prog *p; 				acquire();				p = progpid(strtoul(fields[1], nil, 0));				if(p == nil){					release();					return -1;				}				if(profiler == Pnil){					profiler = Pcov;					p->xec = cpxec;				}				release();			}			else				error(Ebadarg);		}		else			error(Ebadarg);		return n;	default:		error(Eperm);	}	return 0;} static Record*newmodule(Module *m, int vm, int scale, int origin){	int dsize;	Record *r, **l; 	if(!vm)		acquire();	if((m->compiled && m->pctab == nil) || m->prog == nil) {		if(!vm)			release();		return nil;	}/* print("newmodule %x %s %s %d %d %d\n", m, m->name, m->path, m->mtime, m->qid.path, m->qid.vers); */	if(m->compiled)		dsize = m->nprog * sizeof(r->bucket[0]);	else		dsize = (msize(m->prog)/sizeof(Inst)) * sizeof(r->bucket[0]);	dsize *= scale;	dsize += origin;	r = malloc(sizeof(Record)+dsize);	if(r == nil) {		if(!vm)			release();		return nil;	} 	r->id = ++ids;	if(ids == (1<<8)-1)		ids = 0;	kstrdup(&r->name, m->name);	kstrdup(&r->path, m->path);	r->base = m->prog;	r->size = dsize/sizeof(r->bucket[0]);	// r->m = m;	r->mtime = m->mtime;	r->qid.path = m->qid.path;	r->qid.vers = m->qid.vers;	memset(r->bucket, 0, dsize);	r->link = profile.list;	profile.list = r; 	l = &profile.hash[HASH(m->mtime)];	r->hash = *l;	*l = r; 	if(!vm)		release();	return r;} static Record*mlook(Module *m, int vm, int scale, int origin){	Record *r; 	for(r = profile.hash[HASH(m->mtime)]; r; r = r->hash){		/* if(r->m == m){	/* bug - r->m could be old exited module */		if(r->mtime == m->mtime && r->qid.path == m->qid.path && r->qid.vers == m->qid.vers && strcmp(r->name, m->name) == 0 && strcmp(r->path, m->path) == 0){			r->base = m->prog;			return r;		}	}

Lines 1–500 of 722.