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