xref: /plan9/sys/src/cmd/prof.c (revision 4e47a2bae186af79a55734a785d2843fa45765ae)
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 	"sparc",		"k.out",
344 	"spim",		"0.out",
345 	0,0
346 };
347 
348 char*
defaout(void)349 defaout(void)
350 {
351 	char *p;
352 	int i;
353 
354 	p = getenv("objtype");
355 	if(p)
356 	for(i=0; trans[i]; i+=2)
357 		if(strcmp(p, trans[i]) == 0)
358 			return trans[i+1];
359 	return trans[1];
360 }
361