322 lines · 5.7 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <draw.h>#include <mouse.h>#include <keyboard.h>#include <bio.h>#include <mach.h>#include <plumb.h> typedef struct Data	Data; struct Data{	ushort	down;	ushort	right;	ulong	pc;	ulong	count;	uvlong	time;	uint 	rec;};enum { Datasz = 2+2+4+4+8 }; Data*	data;long	ndata;uvlong	cyclefreq; voidsyms(char *cout){	Fhdr f;	int fd; 	if((fd = open(cout, 0)) < 0)		sysfatal("%r");	if(!crackhdr(fd, &f))		sysfatal("can't read text file header: %r");	if(f.type == FNONE)		sysfatal("text file not an a.out");	if(syminit(fd, &f) < 0)		sysfatal("syminit: %r");	close(fd);} #define GET2(p) (u16int)(p)[1] | (u16int)(p)[0]<<8#define GET4(p) (u32int)(p)[3] | (u32int)(p)[2]<<8 | (u32int)(p)[1]<<16 | (u32int)(p)[0]<<24#define GET8(p) (u64int)(p)[7] | (u64int)(p)[6]<<8 | (u64int)(p)[5]<<16 | (u64int)(p)[4]<<24 | \		(u64int)(p)[3]<<32 | (u64int)(p)[2]<<40 | (u64int)(p)[1]<<48 | (u64int)(p)[0]<<56 voiddatas(char *dout){	int fd;	Dir *d;	int i;	uchar hdr[3+1+8], *buf, *p; 	if((fd = open(dout, 0)) < 0){		perror(dout);		exits("open");	}	d = dirfstat(fd);	if(d == nil){		perror(dout);		exits("stat");	}	d->length -= sizeof hdr;	ndata = d->length/Datasz;	data = malloc(ndata*sizeof(Data));	buf = malloc(d->length);	if(buf == 0 || data == 0)		sysfatal("malloc");	if(read(fd, hdr, sizeof hdr) != sizeof hdr)		sysfatal("read data header: %r");	if(memcmp(hdr, "pr\x0f", 3) != 0)		sysfatal("bad magic");	cyclefreq = GET8(hdr+4);	if(readn(fd, buf, d->length) != d->length)		sysfatal("data file read: %r");	for(p = buf, i = 0; i < ndata; i++){		data[i].down = GET2(p); p += 2;		data[i].right = GET2(p); p += 2;		data[i].pc = GET4(p); p += 4;		data[i].count = GET4(p); p += 4;		data[i].time = GET8(p); p += 8;	}	free(buf);	free(d);	close(fd);} char*name(ulong pc){	Symbol s;	static char buf[16]; 	if (findsym(pc, CTEXT, &s))		return(s.name);	snprint(buf, sizeof(buf), "#%lux", pc);	return buf;} static voidplumbpc(ulong pc){	Symbol s;	char buf[256], wd[256];	int fd; 	if(!findsym(pc, CTEXT, &s))		return;		fileline(buf, sizeof buf, pc);	fd = plumbopen("send", OWRITE);	if(fd < 0)		return;	getwd(wd, sizeof wd);	plumbsendtext(fd, "flambe", "edit", wd, buf);	close(fd);} int rowh;Image **cols;int ncols;uvlong total;Rectangle *clicks; voidgencols(void){	int i, h;	ulong col, step; 	h = Dy(screen->r) / rowh + 1;	if(ncols == h)		return;	for(i = 0; i < ncols; i++)		freeimage(cols[i]);	free(cols); 	ncols = h;	cols = malloc(sizeof(Image*)*ncols);	col = DRed;	step = (0xFF/ncols)<<16;	for(i = 0; i < ncols; i++){		cols[i] = allocimagemix(display, DWhite, col);		col += step;	}} Image*colfor(int h){	if(h % 2 == 0)		h += (ncols/3);	return cols[h % ncols];} voidonhover(int i){	Rectangle r;	char buf[128]; 	r = screen->r;	r.max.y = r.min.y + (font->height+2)*2;	draw(screen, r, display->white, nil, ZP);	string(screen, r.min, display->black, ZP, font, name(data[i].pc)); 	r.min.y += font->height + 1;	snprint(buf, sizeof buf, "Time: %.8f(s) %.2f%%, Calls: %lud", (double)data[i].time/cyclefreq, (double)data[i].time/total * 100, data[i].count);	string(screen, r.min, display->black, ZP, font, buf);	flushimage(display, 1);} voidgraph(int i, int x, int h){	Rectangle r, r2; 	if(i >= ndata)		sysfatal("corrupted profile data");	r.min = (Point){x, screen->r.max.y - rowh*h};	r.max = (Point){		x + ((double)data[i].time * Dx(screen->r)) / total,		r.min.y + rowh	};	clicks[i] = r;	if(Dx(r) > 6){		draw(screen, r, colfor(h), nil, ZP);		r2 = r;		r2.min.x  = r2.max.x - 2;		draw(screen, r2, display->black, nil, ZP);		screen->clipr = r;		r2.min = r.min;		r2.min.x += 4;		string(screen, r2.min, display->black, ZP, font, name(data[i].pc));		screen->clipr = screen->r;	}	if(data[i].right != 0xFFFF)		graph(data[i].right, r.max.x, h);	if(data[i].down != 0xFFFF)		graph(data[i].down, x, h + 1);} voidredraw(int i){	total = data[i].time;	memset(clicks, 0, ndata * sizeof(Rectangle));	gencols();	draw(screen, screen->r, display->white, nil, ZP);	graph(i, screen->r.min.x, 1);	flushimage(display, 1);} enum{	Ckey,	Cmouse,	Cresize,	Numchan,}; voidusage(void){	fprint(2, "%s: $O.out prof\n", argv0);	exits("usage");} /* syminit has a Biobuf on the stack */mainstacksize = 64*1024; voidthreadmain(int argc, char **argv){	Mousectl *mctl;	Keyboardctl *kctl;	Mouse m;	Rune r;	vlong t;	int i;	Alt a[Numchan+1] = {		[Ckey] = {nil, &r, CHANRCV},		[Cmouse] = {nil, &m, CHANRCV },		[Cresize] = {nil, nil, CHANRCV},		{nil, nil, CHANEND},	}; 	ARGBEGIN{	default:		usage();		break;	}ARGEND;	if(argc != 2)		usage();	syms(argv[0]);	datas(argv[1]);	for(int i = 1; i < ndata; i++){		t = data[i].time;		if(t < 0)			data[i].time =  t + data[0].time;	} 	if(initdraw(nil, nil, "flambe") < 0)		sysfatal("initdraw: %r");	if((kctl = initkeyboard(nil)) == nil)		sysfatal("initkeyboard: %r");	a[Ckey].c = kctl->c;	if((mctl = initmouse(nil, screen)) == nil)		sysfatal("initmouse: %r");	a[Cmouse].c = mctl->c;	a[Cresize].c = mctl->resizec; 	rowh = font->height + 2;	clicks = malloc(sizeof(Rectangle)*ndata); 	redraw(1);	for(;;)	switch(alt(a)){		case Ckey:			switch(r){				case Kesc:					redraw(1);					break;				case Kdel:				case 'q':					threadexitsall(nil);				default:					break;			}			break;		case Cmouse:			if(m.buttons == 16){				redraw(1);				break;			}			for(i = 0; i < ndata; i++){				if(!ptinrect(m.xy, clicks[i]))					continue;				switch(m.buttons){				case 0:					onhover(i);					break;				case 1: case 8:					redraw(i);					break;				case 4:					plumbpc(data[i].pc);					break;				}				break;			}			break;		case Cresize:			getwindow(display, Refnone);			redraw(1);			break;	}}