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