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