xref: /plan9-contrib/sys/src/cmd/prof.c (revision 20dbf3aaef8463f6410c21e852ddb015455d99ae)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 typedef struct Data	Data;
7 typedef struct Pc	Pc;
8 typedef struct Acc	Acc;
9 
10 struct Data
11 {
12 	ushort	down;
13 	ushort	right;
14 	ulong	pc;
15 	ulong	count;
16 	ulong	time;
17 };
18 
19 struct Pc
20 {
21 	Pc	*next;
22 	ulong	pc;
23 };
24 
25 struct Acc
26 {
27 	char	*name;
28 	ulong	pc;
29 	ulong	ms;
30 	ulong	calls;
31 };
32 
33 Data*	data;
34 Acc*	acc;
35 ulong	ms;
36 long	nsym;
37 long	ndata;
38 int	dflag;
39 int	rflag;
40 Biobuf	bout;
41 int	tabstop = 4;
42 int	verbose;
43 
44 void	syms(char*);
45 void	datas(char*);
46 void	graph(int, ulong, Pc*);
47 void	plot(void);
48 char*	name(ulong);
49 void	indent(int);
50 char*	defaout(void);
51 
52 void
main(int argc,char * argv[])53 main(int argc, char *argv[])
54 {
55 	char *s;
56 
57 	s = getenv("tabstop");
58 	if(s!=nil && strtol(s,0,0)>0)
59 		tabstop = strtol(s,0,0);
60 	ARGBEGIN{
61 	case 'v':
62 		verbose = 1;
63 		break;
64 	case 'd':
65 		dflag = 1;
66 		break;
67 	case 'r':
68 		rflag = 1;
69 		break;
70 	default:
71 		fprint(2, "usage: prof [-dr] [8.out] [prof.out]\n");
72 		exits("usage");
73 	}ARGEND
74 	Binit(&bout, 1, OWRITE);
75 	if(argc > 0)
76 		syms(argv[0]);
77 	else
78 		syms(defaout());
79 	if(argc > 1)
80 		datas(argv[1]);
81 	else
82 		datas("prof.out");
83 	if(ndata){
84 		if(dflag)
85 			graph(0, data[0].down, 0);
86 		else
87 			plot();
88 	}
89 	exits(0);
90 }
91 
92 void
swapdata(Data * dp)93 swapdata(Data *dp)
94 {
95 	dp->down = beswab(dp->down);
96 	dp->right = beswab(dp->right);
97 	dp->pc = beswal(dp->pc);
98 	dp->count = beswal(dp->count);
99 	dp->time = beswal(dp->time);
100 }
101 
102 int
acmp(void * va,void * vb)103 acmp(void *va, void *vb)
104 {
105 	Acc *a, *b;
106 	ulong ua, ub;
107 
108 	a = va;
109 	b = vb;
110 	ua = a->ms;
111 	ub = b->ms;
112 
113 	if(ua > ub)
114 		return 1;
115 	if(ua < ub)
116 		return -1;
117 	return 0;
118 }
119 
120 void
syms(char * cout)121 syms(char *cout)
122 {
123 	Fhdr f;
124 	int fd;
125 
126 	if((fd = open(cout, 0)) < 0){
127 		perror(cout);
128 		exits("open");
129 	}
130 	if (!crackhdr(fd, &f)) {
131 		fprint(2, "can't read text file header\n");
132 		exits("read");
133 	}
134 	if (f.type == FNONE) {
135 		fprint(2, "text file not an a.out\n");
136 		exits("file type");
137 	}
138 	if (syminit(fd, &f) < 0) {
139 		fprint(2, "syminit: %r\n");
140 		exits("syms");
141 	}
142 	close(fd);
143 }
144 
145 void
datas(char * dout)146 datas(char *dout)
147 {
148 	int fd;
149 	Dir *d;
150 	int i;
151 
152 	if((fd = open(dout, 0)) < 0){
153 		perror(dout);
154 		exits("open");
155 	}
156 	d = dirfstat(fd);
157 	if(d == nil){
158 		perror(dout);
159 		exits("stat");
160 	}
161 	ndata = d->length/sizeof(data[0]);
162 	data = malloc(ndata*sizeof(Data));
163 	if(data == 0){
164 		fprint(2, "prof: can't malloc data\n");
165 		exits("data malloc");
166 	}
167 	if(read(fd, data, d->length) != d->length){
168 		fprint(2, "prof: can't read data file\n");
169 		exits("data read");
170 	}
171 	free(d);
172 	close(fd);
173 	for (i = 0; i < ndata; i++)
174 		swapdata(data+i);
175 }
176 
177 char*
name(ulong pc)178 name(ulong pc)
179 {
180 	Symbol s;
181 	static char buf[16];
182 
183 	if (findsym(pc, CTEXT, &s))
184 		return(s.name);
185 	snprint(buf, sizeof(buf), "#%lux", pc);
186 	return buf;
187 }
188 
189 void
graph(int ind,ulong i,Pc * pc)190 graph(int ind, ulong i, Pc *pc)
191 {
192 	long time, count, prgm;
193 	Pc lpc;
194 
195 	if(i >= ndata){
196 		fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata);
197 		return;
198 	}
199 	count = data[i].count;
200 	time = data[i].time;
201 	prgm = data[i].pc;
202 	if(time < 0)
203 		time += data[0].time;
204 	if(data[i].right != 0xFFFF)
205 		graph(ind, data[i].right, pc);
206 	indent(ind);
207 	if(count == 1)
208 		Bprint(&bout, "%s:%lud\n", name(prgm), time);
209 	else
210 		Bprint(&bout, "%s:%lud/%lud\n", name(prgm), time, count);
211 	if(data[i].down == 0xFFFF)
212 		return;
213 	lpc.next = pc;
214 	lpc.pc = prgm;
215 	if(!rflag){
216 		while(pc){
217 			if(pc->pc == prgm){
218 				indent(ind+1);
219 				Bprint(&bout, "...\n");
220 				return;
221 			}
222 			pc = pc->next;
223 		}
224 	}
225 	graph(ind+1, data[i].down, &lpc);
226 }
227 /*
228  *	assume acc is ordered by increasing text address.
229  */
230 long
symind(ulong pc)231 symind(ulong pc)
232 {
233 	int top, bot, mid;
234 
235 	bot = 0;
236 	top = nsym;
237 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
238 		if (pc < acc[mid].pc)
239 			top = mid;
240 		else
241 		if (mid != nsym-1 && pc >= acc[mid+1].pc)
242 			bot = mid;
243 		else
244 			return mid;
245 	}
246 	return -1;
247 }
248 
249 ulong
sum(ulong i)250 sum(ulong i)
251 {
252 	long j, dtime, time;
253 	int k;
254 	static indent;
255 
256 	if(i >= ndata){
257 		fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata);
258 		return 0;
259 	}
260 	j = symind(data[i].pc);
261 	time = data[i].time;
262 	if(time < 0)
263 		time += data[0].time;
264 	if (verbose){
265 		for(k = 0; k < indent; k++)
266 			print("	");
267 		print("%lud: %ld/%lud", i, data[i].time, data[i].count);
268 		if (j >= 0)
269 			print("	%s\n", acc[j].name);
270 		else
271 			print("	0x%lux\n", data[i].pc);
272 	}
273 	dtime = 0;
274 	if(data[i].down != 0xFFFF){
275 		indent++;
276 		dtime = sum(data[i].down);
277 		indent--;
278 	}
279 	j = symind(data[i].pc);
280 	if (j >= 0) {
281 		acc[j].ms += time - dtime;
282 		ms += time - dtime;
283 		acc[j].calls += data[i].count;
284 	}
285 	if(data[i].right == 0xFFFF)
286 		return time;
287 	return time + sum(data[i].right);
288 }
289 
290 void
plot(void)291 plot(void)
292 {
293 	Symbol s;
294 
295 	for (nsym = 0; textsym(&s, nsym); nsym++) {
296 		acc = realloc(acc, (nsym+1)*sizeof(Acc));
297 		if(acc == 0){
298 			fprint(2, "prof: malloc fail\n");
299 			exits("acc malloc");
300 		}
301 		acc[nsym].name = s.name;
302 		acc[nsym].pc = s.value;
303 		acc[nsym].calls = acc[nsym].ms = 0;
304 	}
305 	sum(data[0].down);
306 	qsort(acc, nsym, sizeof(Acc), acmp);
307 	Bprint(&bout, "  %%     Time     Calls  Name\n");
308 	if(ms == 0)
309 		ms = 1;
310 	while (--nsym >= 0) {
311 		if(acc[nsym].calls)
312 			Bprint(&bout, "%4.1f %8.3f %8lud\t%s\n",
313 				(100.0*acc[nsym].ms)/ms,
314 				acc[nsym].ms/1000.0,
315 				acc[nsym].calls,
316 				acc[nsym].name);
317 	}
318 }
319 
320 void
indent(int ind)321 indent(int ind)
322 {
323 	int j;
324 
325 	j = 2*ind;
326 	while(j >= tabstop){
327 		Bwrite(&bout, ".\t", 2);
328 		j -= tabstop;
329 	}
330 	if(j)
331 		Bwrite(&bout, ".                            ", j);
332 }
333 
334 char*	trans[] =
335 {
336 	"386",		"8.out",
337 	"68020",	"2.out",
338 	"alpha",	"7.out",
339 	"amd64",	"6.out",
340 	"arm",		"5.out",
341 	"mips",		"v.out",
342 	"power",	"q.out",
343 	"power64",	"9.out",
344 	"sparc",	"k.out",
345 	"spim",		"0.out",
346 	0,0
347 };
348 
349 char*
defaout(void)350 defaout(void)
351 {
352 	char *p;
353 	int i;
354 
355 	p = getenv("objtype");
356 	if(p)
357 	for(i=0; trans[i]; i+=2)
358 		if(strcmp(p, trans[i]) == 0)
359 			return trans[i+1];
360 	return trans[1];
361 }
362