xref: /plan9/sys/src/cmd/prof.c (revision 4e47a2bae186af79a55734a785d2843fa45765ae)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <mach.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier typedef struct Data	Data;
73e12c5d1SDavid du Colombier typedef struct Pc	Pc;
83e12c5d1SDavid du Colombier typedef struct Acc	Acc;
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier struct Data
113e12c5d1SDavid du Colombier {
123e12c5d1SDavid du Colombier 	ushort	down;
133e12c5d1SDavid du Colombier 	ushort	right;
143e12c5d1SDavid du Colombier 	ulong	pc;
153e12c5d1SDavid du Colombier 	ulong	count;
163e12c5d1SDavid du Colombier 	ulong	time;
173e12c5d1SDavid du Colombier };
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier struct Pc
203e12c5d1SDavid du Colombier {
213e12c5d1SDavid du Colombier 	Pc	*next;
223e12c5d1SDavid du Colombier 	ulong	pc;
233e12c5d1SDavid du Colombier };
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier struct Acc
263e12c5d1SDavid du Colombier {
273e12c5d1SDavid du Colombier 	char	*name;
283e12c5d1SDavid du Colombier 	ulong	pc;
293e12c5d1SDavid du Colombier 	ulong	ms;
303e12c5d1SDavid du Colombier 	ulong	calls;
313e12c5d1SDavid du Colombier };
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier Data*	data;
343e12c5d1SDavid du Colombier Acc*	acc;
353e12c5d1SDavid du Colombier ulong	ms;
363e12c5d1SDavid du Colombier long	nsym;
373e12c5d1SDavid du Colombier long	ndata;
383e12c5d1SDavid du Colombier int	dflag;
393e12c5d1SDavid du Colombier int	rflag;
403e12c5d1SDavid du Colombier Biobuf	bout;
4159cc4ca5SDavid du Colombier int	tabstop = 4;
42e288d156SDavid du Colombier int	verbose;
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier void	syms(char*);
453e12c5d1SDavid du Colombier void	datas(char*);
463e12c5d1SDavid du Colombier void	graph(int, ulong, Pc*);
473e12c5d1SDavid du Colombier void	plot(void);
483e12c5d1SDavid du Colombier char*	name(ulong);
493e12c5d1SDavid du Colombier void	indent(int);
503e12c5d1SDavid du Colombier char*	defaout(void);
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier void
main(int argc,char * argv[])533e12c5d1SDavid du Colombier main(int argc, char *argv[])
543e12c5d1SDavid du Colombier {
5559cc4ca5SDavid du Colombier 	char *s;
563e12c5d1SDavid du Colombier 
5759cc4ca5SDavid du Colombier 	s = getenv("tabstop");
5816941224SDavid du Colombier 	if(s!=nil && strtol(s,0,0)>0)
5916941224SDavid du Colombier 		tabstop = strtol(s,0,0);
603e12c5d1SDavid du Colombier 	ARGBEGIN{
61e288d156SDavid du Colombier 	case 'v':
62e288d156SDavid du Colombier 		verbose = 1;
63e288d156SDavid du Colombier 		break;
643e12c5d1SDavid du Colombier 	case 'd':
653e12c5d1SDavid du Colombier 		dflag = 1;
663e12c5d1SDavid du Colombier 		break;
673e12c5d1SDavid du Colombier 	case 'r':
683e12c5d1SDavid du Colombier 		rflag = 1;
693e12c5d1SDavid du Colombier 		break;
703e12c5d1SDavid du Colombier 	default:
717dd7cddfSDavid du Colombier 		fprint(2, "usage: prof [-dr] [8.out] [prof.out]\n");
723e12c5d1SDavid du Colombier 		exits("usage");
733e12c5d1SDavid du Colombier 	}ARGEND
743e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
753e12c5d1SDavid du Colombier 	if(argc > 0)
763e12c5d1SDavid du Colombier 		syms(argv[0]);
773e12c5d1SDavid du Colombier 	else
783e12c5d1SDavid du Colombier 		syms(defaout());
793e12c5d1SDavid du Colombier 	if(argc > 1)
803e12c5d1SDavid du Colombier 		datas(argv[1]);
813e12c5d1SDavid du Colombier 	else
823e12c5d1SDavid du Colombier 		datas("prof.out");
833e12c5d1SDavid du Colombier 	if(ndata){
843e12c5d1SDavid du Colombier 		if(dflag)
853e12c5d1SDavid du Colombier 			graph(0, data[0].down, 0);
863e12c5d1SDavid du Colombier 		else
873e12c5d1SDavid du Colombier 			plot();
883e12c5d1SDavid du Colombier 	}
893e12c5d1SDavid du Colombier 	exits(0);
903e12c5d1SDavid du Colombier }
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier void
swapdata(Data * dp)933e12c5d1SDavid du Colombier swapdata(Data *dp)
943e12c5d1SDavid du Colombier {
953e12c5d1SDavid du Colombier 	dp->down = beswab(dp->down);
963e12c5d1SDavid du Colombier 	dp->right = beswab(dp->right);
973e12c5d1SDavid du Colombier 	dp->pc = beswal(dp->pc);
983e12c5d1SDavid du Colombier 	dp->count = beswal(dp->count);
993e12c5d1SDavid du Colombier 	dp->time = beswal(dp->time);
1003e12c5d1SDavid du Colombier }
1013e12c5d1SDavid du Colombier 
1023e12c5d1SDavid du Colombier int
acmp(void * va,void * vb)1037dd7cddfSDavid du Colombier acmp(void *va, void *vb)
1043e12c5d1SDavid du Colombier {
1057dd7cddfSDavid du Colombier 	Acc *a, *b;
1067dd7cddfSDavid du Colombier 	ulong ua, ub;
1073e12c5d1SDavid du Colombier 
1087dd7cddfSDavid du Colombier 	a = va;
1097dd7cddfSDavid du Colombier 	b = vb;
1107dd7cddfSDavid du Colombier 	ua = a->ms;
1117dd7cddfSDavid du Colombier 	ub = b->ms;
1123e12c5d1SDavid du Colombier 
1137dd7cddfSDavid du Colombier 	if(ua > ub)
1143e12c5d1SDavid du Colombier 		return 1;
1157dd7cddfSDavid du Colombier 	if(ua < ub)
1163e12c5d1SDavid du Colombier 		return -1;
1173e12c5d1SDavid du Colombier 	return 0;
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier void
syms(char * cout)1213e12c5d1SDavid du Colombier syms(char *cout)
1223e12c5d1SDavid du Colombier {
1233e12c5d1SDavid du Colombier 	Fhdr f;
1243e12c5d1SDavid du Colombier 	int fd;
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier 	if((fd = open(cout, 0)) < 0){
1273e12c5d1SDavid du Colombier 		perror(cout);
1283e12c5d1SDavid du Colombier 		exits("open");
1293e12c5d1SDavid du Colombier 	}
1303e12c5d1SDavid du Colombier 	if (!crackhdr(fd, &f)) {
1313e12c5d1SDavid du Colombier 		fprint(2, "can't read text file header\n");
1323e12c5d1SDavid du Colombier 		exits("read");
1333e12c5d1SDavid du Colombier 	}
1343e12c5d1SDavid du Colombier 	if (f.type == FNONE) {
1353e12c5d1SDavid du Colombier 		fprint(2, "text file not an a.out\n");
1363e12c5d1SDavid du Colombier 		exits("file type");
1373e12c5d1SDavid du Colombier 	}
1383e12c5d1SDavid du Colombier 	if (syminit(fd, &f) < 0) {
139219b2ee8SDavid du Colombier 		fprint(2, "syminit: %r\n");
1403e12c5d1SDavid du Colombier 		exits("syms");
1413e12c5d1SDavid du Colombier 	}
1423e12c5d1SDavid du Colombier 	close(fd);
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier void
datas(char * dout)1463e12c5d1SDavid du Colombier datas(char *dout)
1473e12c5d1SDavid du Colombier {
1483e12c5d1SDavid du Colombier 	int fd;
1499a747e4fSDavid du Colombier 	Dir *d;
1503e12c5d1SDavid du Colombier 	int i;
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	if((fd = open(dout, 0)) < 0){
1533e12c5d1SDavid du Colombier 		perror(dout);
1543e12c5d1SDavid du Colombier 		exits("open");
1553e12c5d1SDavid du Colombier 	}
1569a747e4fSDavid du Colombier 	d = dirfstat(fd);
1579a747e4fSDavid du Colombier 	if(d == nil){
1589a747e4fSDavid du Colombier 		perror(dout);
1599a747e4fSDavid du Colombier 		exits("stat");
1609a747e4fSDavid du Colombier 	}
1619a747e4fSDavid du Colombier 	ndata = d->length/sizeof(data[0]);
1623e12c5d1SDavid du Colombier 	data = malloc(ndata*sizeof(Data));
1633e12c5d1SDavid du Colombier 	if(data == 0){
1643e12c5d1SDavid du Colombier 		fprint(2, "prof: can't malloc data\n");
1653e12c5d1SDavid du Colombier 		exits("data malloc");
1663e12c5d1SDavid du Colombier 	}
1679a747e4fSDavid du Colombier 	if(read(fd, data, d->length) != d->length){
1683e12c5d1SDavid du Colombier 		fprint(2, "prof: can't read data file\n");
1693e12c5d1SDavid du Colombier 		exits("data read");
1703e12c5d1SDavid du Colombier 	}
1719a747e4fSDavid du Colombier 	free(d);
1723e12c5d1SDavid du Colombier 	close(fd);
1733e12c5d1SDavid du Colombier 	for (i = 0; i < ndata; i++)
1743e12c5d1SDavid du Colombier 		swapdata(data+i);
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier char*
name(ulong pc)1783e12c5d1SDavid du Colombier name(ulong pc)
1793e12c5d1SDavid du Colombier {
1803e12c5d1SDavid du Colombier 	Symbol s;
1813e12c5d1SDavid du Colombier 	static char buf[16];
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	if (findsym(pc, CTEXT, &s))
1843e12c5d1SDavid du Colombier 		return(s.name);
18516941224SDavid du Colombier 	snprint(buf, sizeof(buf), "#%lux", pc);
1863e12c5d1SDavid du Colombier 	return buf;
1873e12c5d1SDavid du Colombier }
1883e12c5d1SDavid du Colombier 
1893e12c5d1SDavid du Colombier void
graph(int ind,ulong i,Pc * pc)1903e12c5d1SDavid du Colombier graph(int ind, ulong i, Pc *pc)
1913e12c5d1SDavid du Colombier {
1923e12c5d1SDavid du Colombier 	long time, count, prgm;
1933e12c5d1SDavid du Colombier 	Pc lpc;
1943e12c5d1SDavid du Colombier 
1953e12c5d1SDavid du Colombier 	if(i >= ndata){
1967dd7cddfSDavid du Colombier 		fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata);
1973e12c5d1SDavid du Colombier 		return;
1983e12c5d1SDavid du Colombier 	}
1993e12c5d1SDavid du Colombier 	count = data[i].count;
2003e12c5d1SDavid du Colombier 	time = data[i].time;
2013e12c5d1SDavid du Colombier 	prgm = data[i].pc;
2023e12c5d1SDavid du Colombier 	if(time < 0)
2033e12c5d1SDavid du Colombier 		time += data[0].time;
2043e12c5d1SDavid du Colombier 	if(data[i].right != 0xFFFF)
2053e12c5d1SDavid du Colombier 		graph(ind, data[i].right, pc);
2063e12c5d1SDavid du Colombier 	indent(ind);
2073e12c5d1SDavid du Colombier 	if(count == 1)
2083e12c5d1SDavid du Colombier 		Bprint(&bout, "%s:%lud\n", name(prgm), time);
2093e12c5d1SDavid du Colombier 	else
2103e12c5d1SDavid du Colombier 		Bprint(&bout, "%s:%lud/%lud\n", name(prgm), time, count);
2113e12c5d1SDavid du Colombier 	if(data[i].down == 0xFFFF)
2123e12c5d1SDavid du Colombier 		return;
2133e12c5d1SDavid du Colombier 	lpc.next = pc;
2143e12c5d1SDavid du Colombier 	lpc.pc = prgm;
2153e12c5d1SDavid du Colombier 	if(!rflag){
2163e12c5d1SDavid du Colombier 		while(pc){
2173e12c5d1SDavid du Colombier 			if(pc->pc == prgm){
2183e12c5d1SDavid du Colombier 				indent(ind+1);
2193e12c5d1SDavid du Colombier 				Bprint(&bout, "...\n");
2203e12c5d1SDavid du Colombier 				return;
2213e12c5d1SDavid du Colombier 			}
2223e12c5d1SDavid du Colombier 			pc = pc->next;
2233e12c5d1SDavid du Colombier 		}
2243e12c5d1SDavid du Colombier 	}
2253e12c5d1SDavid du Colombier 	graph(ind+1, data[i].down, &lpc);
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier /*
2283e12c5d1SDavid du Colombier  *	assume acc is ordered by increasing text address.
2293e12c5d1SDavid du Colombier  */
2303e12c5d1SDavid du Colombier long
symind(ulong pc)2313e12c5d1SDavid du Colombier symind(ulong pc)
2323e12c5d1SDavid du Colombier {
2333e12c5d1SDavid du Colombier 	int top, bot, mid;
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier 	bot = 0;
2363e12c5d1SDavid du Colombier 	top = nsym;
2373e12c5d1SDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
2383e12c5d1SDavid du Colombier 		if (pc < acc[mid].pc)
2393e12c5d1SDavid du Colombier 			top = mid;
2403e12c5d1SDavid du Colombier 		else
2413e12c5d1SDavid du Colombier 		if (mid != nsym-1 && pc >= acc[mid+1].pc)
2423e12c5d1SDavid du Colombier 			bot = mid;
2433e12c5d1SDavid du Colombier 		else
2443e12c5d1SDavid du Colombier 			return mid;
2453e12c5d1SDavid du Colombier 	}
2463e12c5d1SDavid du Colombier 	return -1;
2473e12c5d1SDavid du Colombier }
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier ulong
sum(ulong i)2503e12c5d1SDavid du Colombier sum(ulong i)
2513e12c5d1SDavid du Colombier {
2523e12c5d1SDavid du Colombier 	long j, dtime, time;
253e288d156SDavid du Colombier 	int k;
254e288d156SDavid du Colombier 	static indent;
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier 	if(i >= ndata){
2577dd7cddfSDavid du Colombier 		fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata);
2583e12c5d1SDavid du Colombier 		return 0;
2593e12c5d1SDavid du Colombier 	}
260e288d156SDavid du Colombier 	j = symind(data[i].pc);
2613e12c5d1SDavid du Colombier 	time = data[i].time;
2623e12c5d1SDavid du Colombier 	if(time < 0)
2633e12c5d1SDavid du Colombier 		time += data[0].time;
264e288d156SDavid du Colombier 	if (verbose){
265e288d156SDavid du Colombier 		for(k = 0; k < indent; k++)
266e288d156SDavid du Colombier 			print("	");
267e288d156SDavid du Colombier 		print("%lud: %ld/%lud", i, data[i].time, data[i].count);
268e288d156SDavid du Colombier 		if (j >= 0)
269e288d156SDavid du Colombier 			print("	%s\n", acc[j].name);
270e288d156SDavid du Colombier 		else
271e288d156SDavid du Colombier 			print("	0x%lux\n", data[i].pc);
272e288d156SDavid du Colombier 	}
2733e12c5d1SDavid du Colombier 	dtime = 0;
274e288d156SDavid du Colombier 	if(data[i].down != 0xFFFF){
275e288d156SDavid du Colombier 		indent++;
2763e12c5d1SDavid du Colombier 		dtime = sum(data[i].down);
277e288d156SDavid du Colombier 		indent--;
278e288d156SDavid du Colombier 	}
2793e12c5d1SDavid du Colombier 	j = symind(data[i].pc);
2803e12c5d1SDavid du Colombier 	if (j >= 0) {
2813e12c5d1SDavid du Colombier 		acc[j].ms += time - dtime;
2823e12c5d1SDavid du Colombier 		ms += time - dtime;
2833e12c5d1SDavid du Colombier 		acc[j].calls += data[i].count;
2843e12c5d1SDavid du Colombier 	}
2853e12c5d1SDavid du Colombier 	if(data[i].right == 0xFFFF)
2863e12c5d1SDavid du Colombier 		return time;
2873e12c5d1SDavid du Colombier 	return time + sum(data[i].right);
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier void
plot(void)2913e12c5d1SDavid du Colombier plot(void)
2923e12c5d1SDavid du Colombier {
2933e12c5d1SDavid du Colombier 	Symbol s;
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier 	for (nsym = 0; textsym(&s, nsym); nsym++) {
2963e12c5d1SDavid du Colombier 		acc = realloc(acc, (nsym+1)*sizeof(Acc));
2973e12c5d1SDavid du Colombier 		if(acc == 0){
2983e12c5d1SDavid du Colombier 			fprint(2, "prof: malloc fail\n");
2993e12c5d1SDavid du Colombier 			exits("acc malloc");
3003e12c5d1SDavid du Colombier 		}
3013e12c5d1SDavid du Colombier 		acc[nsym].name = s.name;
3023e12c5d1SDavid du Colombier 		acc[nsym].pc = s.value;
3033e12c5d1SDavid du Colombier 		acc[nsym].calls = acc[nsym].ms = 0;
3043e12c5d1SDavid du Colombier 	}
3053e12c5d1SDavid du Colombier 	sum(data[0].down);
3063e12c5d1SDavid du Colombier 	qsort(acc, nsym, sizeof(Acc), acmp);
3073801c5d3SDavid du Colombier 	Bprint(&bout, "  %%     Time     Calls  Name\n");
3083e12c5d1SDavid du Colombier 	if(ms == 0)
3093e12c5d1SDavid du Colombier 		ms = 1;
3103e12c5d1SDavid du Colombier 	while (--nsym >= 0) {
3113e12c5d1SDavid du Colombier 		if(acc[nsym].calls)
3127dd7cddfSDavid du Colombier 			Bprint(&bout, "%4.1f %8.3f %8lud\t%s\n",
3133e12c5d1SDavid du Colombier 				(100.0*acc[nsym].ms)/ms,
3143e12c5d1SDavid du Colombier 				acc[nsym].ms/1000.0,
3153e12c5d1SDavid du Colombier 				acc[nsym].calls,
3163e12c5d1SDavid du Colombier 				acc[nsym].name);
3173e12c5d1SDavid du Colombier 	}
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier void
indent(int ind)3213e12c5d1SDavid du Colombier indent(int ind)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	int j;
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier 	j = 2*ind;
32659cc4ca5SDavid du Colombier 	while(j >= tabstop){
3273e12c5d1SDavid du Colombier 		Bwrite(&bout, ".\t", 2);
32859cc4ca5SDavid du Colombier 		j -= tabstop;
3293e12c5d1SDavid du Colombier 	}
3303e12c5d1SDavid du Colombier 	if(j)
3313e12c5d1SDavid du Colombier 		Bwrite(&bout, ".                            ", j);
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier char*	trans[] =
3353e12c5d1SDavid du Colombier {
3363e12c5d1SDavid du Colombier 	"386",		"8.out",
3377dd7cddfSDavid du Colombier 	"68020",		"2.out",
3387dd7cddfSDavid du Colombier 	"alpha",		"7.out",
339*4e47a2baSDavid du Colombier 	"amd64",	"6.out",
3407dd7cddfSDavid du Colombier 	"arm",		"5.out",
3417dd7cddfSDavid du Colombier 	"mips",		"v.out",
3427dd7cddfSDavid du Colombier 	"power",		"q.out",
3437dd7cddfSDavid du Colombier 	"sparc",		"k.out",
3447dd7cddfSDavid du Colombier 	"spim",		"0.out",
3453e12c5d1SDavid du Colombier 	0,0
3463e12c5d1SDavid du Colombier };
3473e12c5d1SDavid du Colombier 
3483e12c5d1SDavid du Colombier char*
defaout(void)3493e12c5d1SDavid du Colombier defaout(void)
3503e12c5d1SDavid du Colombier {
3513e12c5d1SDavid du Colombier 	char *p;
3523e12c5d1SDavid du Colombier 	int i;
3533e12c5d1SDavid du Colombier 
3543e12c5d1SDavid du Colombier 	p = getenv("objtype");
3553e12c5d1SDavid du Colombier 	if(p)
3563e12c5d1SDavid du Colombier 	for(i=0; trans[i]; i+=2)
3573e12c5d1SDavid du Colombier 		if(strcmp(p, trans[i]) == 0)
3583e12c5d1SDavid du Colombier 			return trans[i+1];
3593e12c5d1SDavid du Colombier 	return trans[1];
3603e12c5d1SDavid du Colombier }
361