|
|
1.1 root 1: /*
2: * prof
3: */
4: #include <stdio.h>
5: #include <sys/types.h>
6: #include <sys/stat.h>
7: #include <a.out.h>
8:
9: typedef short UNIT; /* unit of profiling */
10: #define PCFUDGE 11
11: #define A_OUTNAME "a.out"
12: #define MON_OUTNAME "mon.out"
13: #define MON_SUMNAME "mon.sum"
14:
15: /*
16: * The symbol table;
17: * for each external in the specified file we gather
18: * its address, the number of calls and compute its share of cpu time.
19: */
20: struct nl {
21: char *name;
22: unsigned value;
23: float time;
24: long ncall;
25: } *nl;
26: int nname;
27: struct nl *np;
28: struct nl *npe;
29:
30: /*
31: * The header on the mon.out file.
32: * Mon.out consists of one of these headers, an array of ncount
33: * cnt structures (as below) and then an array of samples
34: * representing the discretized program counter values.
35: */
36: struct hdr {
37: UNIT *lowpc, *highpc;
38: int ncount;
39: } h;
40:
41: /*
42: * Each counter has an address and a number of calls.
43: */
44: struct cnt {
45: unsigned cvalue;
46: long cncall;
47: } *cbuf;
48:
49: /*
50: * Each discretized pc sample has
51: * a count of the number of samples in its range
52: */
53: unsigned UNIT *samples;
54:
55: FILE *pfile, *nfile;
56:
57: unsigned lowpc, highpc; /* range profiled */
58: double ransca, ranoff; /* scaling for blowing up plots */
59: unsigned sampbytes; /* number of bytes of samples */
60: int nsamples; /* number of samples */
61: double totime; /* total time for all routines */
62: double maxtime; /* maximum time of any routine (for plot) */
63: double scale; /* scale factor converting samples to pc
64: values: each sample covers scale bytes */
65: char *strtab; /* string table in core */
66: off_t ssiz; /* size of the string table */
67: struct exec xbuf; /* exec header of a.out */
68:
69: int aflg;
70: int nflg;
71: int vflg;
72: int lflg;
73: int zflg;
74: int sflag;
75:
76: char *namfil;
77:
78: int timcmp(), valcmp(), cntcmp();
79:
80: main(argc, argv)
81: char **argv;
82: {
83: int lowpct, highpct;
84:
85: /*
86: * Use highpct and lowpc as percentages, temporarily
87: * for graphing options involving blow-up
88: */
89: lowpct = -1;
90: highpct = -1;
91: argv++;
92: while ( *argv != 0 && **argv == '-' ) {
93: *argv += 1;
94: if (**argv == 'l')
95: lflg++;
96: else if (**argv == 'a')
97: aflg++;
98: else if (**argv == 'n')
99: nflg++;
100: else if (**argv == 'z')
101: zflg++;
102: else if (**argv == 'v')
103: vflg++;
104: else if ( **argv == 's' )
105: sflag++;
106: else if (**argv >= '0' && **argv <= '9') {
107: int i = atoi(*argv);
108: if (lowpct == -1)
109: lowpct = i;
110: else
111: highpct = i;
112: }
113: argv++;
114: }
115: if ( *argv != 0 ) {
116: namfil = *argv;
117: argv++;
118: } else {
119: namfil = A_OUTNAME;
120: }
121: if (lowpct >= 100)
122: lowpct = 0;
123: if (highpct <= lowpct || highpct > 100)
124: highpct = 100;
125: ransca = 100./(highpct-lowpct);
126: ranoff = 2040. + 40.8*lowpc*ransca;
127: /*
128: * get information about a.out file.
129: */
130: getnfile();
131: /*
132: * get information about mon.out file(s).
133: */
134: if ( *argv == 0 ) {
135: getpfile( MON_OUTNAME );
136: } else {
137: do {
138: getpfile( *argv );
139: argv++;
140: } while ( *argv != 0 );
141: }
142: asgnsamples(); /* assign samples to procedures */
143: #ifdef plot
144: if (vflg)
145: plotprof(); /* a plotted or ... */
146: else
147: #endif
148: printprof(); /* a printed profile */
149: if ( sflag != 0 ) {
150: putprof();
151: }
152: done();
153: }
154:
155: printprof()
156: {
157: double time, actime;
158:
159: actime = 0;
160: printf(" %%time cumsecs #call ms/call name\n");
161: if (!lflg)
162: qsort(nl, nname, sizeof(struct nl), timcmp);
163: for (np = nl; np<npe-1; np++) {
164: if (zflg == 0 && np->time == 0 && np->ncall == 0)
165: continue;
166: time = np->time/totime;
167: actime += np->time;
168: printf("%6.1f%9.2f", 100*time, actime/60);
169: if (np->ncall != 0)
170: printf("%7ld %8.2f",
171: np->ncall, np->time/(np->ncall*.06));
172: else
173: printf("%7.7s %8.8s", "", "");
174: printf(" %s\n", np->name);
175: }
176: }
177:
178: /*
179: * Set up string and symbol tables from a.out.
180: * On return symbol table is sorted by value.
181: */
182: getnfile()
183: {
184:
185: nfile = fopen(namfil,"r");
186: if (nfile == NULL) {
187: perror(namfil);
188: done();
189: }
190: fread(&xbuf, 1, sizeof(xbuf), nfile);
191: if (N_BADMAG(xbuf)) {
192: fprintf(stderr, "%s: bad format\n", namfil);
193: done();
194: }
195: getstrtab();
196: getsymtab();
197: qsort(nl, nname, sizeof(struct nl), valcmp);
198: }
199:
200: getstrtab()
201: {
202:
203: fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0);
204: if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
205: fprintf(stderr, "%s: no string table (old format?)\n", namfil);
206: done();
207: }
208: strtab = (char *)calloc(ssiz, 1);
209: if (strtab == NULL) {
210: fprintf(stderr, "%s: no room for %d bytes of string table",
211: namfil, ssiz);
212: done();
213: }
214: if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
215: fprintf(stderr, "%s: error reading string table\n", namfil);
216: done();
217: }
218: }
219:
220: /*
221: * Read in symbol table
222: */
223: getsymtab()
224: {
225: register int i;
226:
227: /* pass1 - count symbols */
228: fseek(nfile, N_SYMOFF(xbuf), 0);
229: nname = 0;
230: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
231: struct nlist nbuf;
232: fread(&nbuf, sizeof(nbuf), 1, nfile);
233: if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
234: continue;
235: if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
236: continue;
237: nname++;
238: }
239: if (nname == 0) {
240: fprintf(stderr, "%s: no symbols\n", namfil);
241: done();
242: }
243: nl = (struct nl *)calloc((nname+1), sizeof (struct nl));
244: if (nl == 0) {
245: fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
246: (nname+1) * sizeof (struct nlist));
247: done();
248: }
249:
250: /* pass2 - read symbols */
251: fseek(nfile, N_SYMOFF(xbuf), 0);
252: npe = nl;
253: nname = 0;
254: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
255: struct nlist nbuf;
256: fread(&nbuf, sizeof(nbuf), 1, nfile);
257: if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
258: continue;
259: if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
260: continue;
261: npe->value = nbuf.n_value/sizeof(UNIT);
262: npe->name = strtab+nbuf.n_un.n_strx;
263: npe++;
264: nname++;
265: }
266: npe->value = -1;
267: npe++;
268: }
269:
270: /*
271: * information from a mon.out file is in two parts:
272: * the counters of how many times each procedure was called,
273: * if it was called at all;
274: * and an array of sampling hits within pc ranges.
275: * the counters must be dealt with on a file-by-file basis,
276: * since which procedures are represented may vary.
277: * the samples ranges are fixed, but must be summed across
278: * files, and then distributed among procedures, because
279: * of the wierd way the plotting is done.
280: */
281: getpfile(filename)
282: char *filename;
283: {
284:
285: openpfile(filename);
286: readcntrs();
287: asgncntrs(); /* assign counts to procedures */
288: readsamples();
289: closepfile();
290: }
291:
292: openpfile(filename)
293: char *filename;
294: {
295: struct stat stb;
296:
297: if((pfile = fopen(filename, "r")) == NULL) {
298: perror(filename);
299: done();
300: }
301: fstat(fileno(pfile), &stb);
302: fread(&h, sizeof(struct hdr), 1, pfile);
303: lowpc = h.lowpc - (UNIT *)0;
304: highpc = h.highpc - (UNIT *)0;
305: sampbytes =
306: stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt) - sizeof(int);
307: nsamples = sampbytes / sizeof (unsigned UNIT);
308: }
309:
310: closepfile()
311: {
312:
313: fclose(pfile);
314: free(cbuf);
315: }
316:
317: readcntrs()
318: {
319: struct cnt *kp;
320:
321: cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt));
322: if (cbuf == 0) {
323: fprintf(stderr, "prof: No room for %d bytes of count buffer\n",
324: (h.ncount+1) * sizeof (struct cnt));
325: exit(1);
326: }
327: fread(cbuf, sizeof(struct cnt), h.ncount, pfile);
328: /* skip end marker */
329: fseek(pfile, sizeof(int), 1);
330: /* eliminate zero counters and scale counter pc values */
331: if (h.ncount) {
332: kp = &cbuf[h.ncount - 1];
333: for (;;) {
334: if (kp->cvalue==0) {
335: h.ncount=kp-cbuf;
336: ++kp;
337: break;
338: }
339: if (kp == cbuf) {
340: h.ncount = 0;
341: break;
342: }
343: --kp;
344: }
345: for (; --kp>=cbuf; )
346: kp->cvalue /= sizeof(UNIT);
347: }
348: /* sort counters */
349: qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp);
350: }
351:
352: /*
353: * Assign counters to the procedures to which they belong
354: */
355: asgncntrs()
356: {
357: register int i;
358: struct cnt *kp;
359:
360: kp = &cbuf[h.ncount-1];
361: np = npe;
362: while (--np>=nl) {
363: if (kp<cbuf || np->value > kp->cvalue)
364: continue;
365: /* skip ``static'' functions */
366: while (kp >= cbuf && kp->cvalue > np->value + PCFUDGE)
367: --kp;
368: if (kp->cvalue >= np->value) {
369: np->ncall += kp->cncall;
370: --kp;
371: }
372: }
373: }
374:
375: readsamples()
376: {
377: register int i;
378: unsigned UNIT sample;
379: int totalt;
380:
381: if (samples == 0) {
382: samples = (unsigned UNIT *)
383: calloc(sampbytes, sizeof (unsigned UNIT));
384: if (samples == 0) {
385: printf("prof: No room for %d sample pc's\n",
386: sampbytes / sizeof (unsigned UNIT));
387: done();
388: }
389: }
390: for (i = 0; ; i++) {
391: fread(&sample, sizeof (unsigned UNIT), 1, pfile);
392: if (feof(pfile))
393: break;
394: samples[i] += sample;
395: totalt += sample;
396: }
397: if (i != nsamples) {
398: fprintf(stderr,
399: "prof: unexpected EOF after reading %d/%d samples\n",
400: --i, nsamples);
401: done();
402: }
403: }
404:
405: /*
406: * Assign samples to the procedures to which they belong.
407: */
408: asgnsamples()
409: {
410: register int j;
411: unsigned UNIT ccnt;
412: double time;
413: unsigned pcl, pch;
414: register int i;
415: int overlap;
416:
417: /* read samples and assign to namelist symbols */
418: scale = highpc - lowpc;
419: scale /= nsamples;
420: for (i=0; i < nsamples; i++) {
421: ccnt = samples[i];
422: if (ccnt == 0)
423: continue;
424: pcl = lowpc + scale*i;
425: pch = lowpc + scale*(i+1);
426: time = ccnt;
427: totime += time;
428: if(time > maxtime)
429: maxtime = time;
430: for (j=0; j<nname; j++) {
431: if (pch < nl[j].value)
432: break;
433: if (pcl >= nl[j+1].value)
434: continue;
435: overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value));
436: if (overlap>0)
437: nl[j].time += overlap*time/scale;
438: }
439: }
440: if (totime==0.0) {
441: fprintf(stderr, "No time accumulated\n");
442: /*
443: done();
444: */
445: totime=1.0;
446: }
447: }
448:
449: /*
450: * dump what you have out to a mon.out style file.
451: */
452: putprof()
453: {
454: FILE *sfile;
455: struct nl *np;
456: struct cnt kp;
457: int i;
458:
459: sfile = fopen(MON_SUMNAME, "w");
460: if (sfile == NULL) {
461: perror(MON_SUMNAME);
462: done();
463: }
464: /*
465: * build a new header.
466: * h.lowpc and h.highpc are already fine.
467: * fix h.ncount to count non-zero calls,
468: * and the one zero call which marks the end.
469: */
470: h.ncount = 0;
471: for (np = nl; np < npe-1 ; np++)
472: if (np->ncall > 0)
473: h.ncount++;
474: h.ncount++;
475: fwrite(&h, sizeof (struct hdr), 1, sfile);
476: for (np = nl; np < npe-1; np++) {
477: if (np->ncall > 0) {
478: kp.cvalue = np->value * sizeof (unsigned UNIT);
479: kp.cncall = np->ncall;
480: fwrite(&kp, sizeof (struct cnt), 1, sfile);
481: }
482: }
483: kp.cvalue = 0;
484: kp.cncall = 0;
485: fwrite(&kp, sizeof (struct cnt), 1, sfile);
486: fwrite(samples, sizeof (unsigned UNIT), nsamples, sfile);
487: fclose(sfile);
488: }
489:
490: min(a, b)
491: {
492: if (a<b)
493: return(a);
494: return(b);
495: }
496:
497: max(a, b)
498: {
499: if (a>b)
500: return(a);
501: return(b);
502: }
503:
504: valcmp(p1, p2)
505: struct nl *p1, *p2;
506: {
507:
508: return(p1->value - p2->value);
509: }
510:
511: timcmp(p1, p2)
512: struct nl *p1, *p2;
513: {
514: float d;
515:
516: if (nflg && p2->ncall != p1->ncall)
517: return (p2->ncall - p1->ncall);
518: d = p2->time - p1->time;
519: if (d > 0.0)
520: return(1);
521: if (d < 0.0)
522: return(-1);
523: return(strcmp(p1->name,p2->name));
524: }
525:
526: cntcmp(p1, p2)
527: struct cnt *p1, *p2;
528: {
529:
530: return(p1->cvalue - p2->cvalue);
531: }
532:
533: done()
534: {
535:
536: #ifdef plot
537: if(vflg) {
538: point(0, -2040);
539: closepl();
540: }
541: #endif
542: exit(0);
543: }
544:
545: #ifdef plot
546: plotprof()
547: {
548: double time, lastx, lasty, lastsx;
549: register int i;
550:
551: openpl();
552: erase();
553: space(-2048, -2048, 2048, 2048);
554: line(-2040, -2040, -2040, 2040);
555: line(0, 2040, 0, -2040);
556: for(i=0; i<11; i++)
557: line(-2040, 2040-i*408, 0, 2040-i*408);
558: lastx = 0.;
559: lasty = ranoff;
560: scale = (4080.*ransca)/(sampbytes/sizeof(UNIT));
561: lastsx = 0.0;
562: for(i = 0; i < nsamples; i++) {
563: unsigned UNIT ccnt;
564: double tx, ty;
565: ccnt = samples[i];
566: time = ccnt;
567: tx = lastsx;
568: ty = lasty;
569: lastsx -= 2000.*time/totime;
570: lasty -= scale;
571: if(lasty >= -2040. && ty <= 2040.) {
572: line((int)tx, (int)ty, (int)lastsx, (int)lasty);
573: if (ccnt!=0 || lastx!=0.0) {
574: tx = lastx;
575: lastx = -time*2000./maxtime;
576: ty += scale/2;
577: line(0, (int)ty, (int)tx, (int)ty);
578: }
579: }
580: }
581: scale = (4080.*ransca)/(highpc-lowpc);
582: lastx = 50.;
583: for(np = nl; np<npe; np++) {
584: if(np->value < lowpc)
585: continue;
586: if(np->value >= highpc)
587: continue;
588: if(zflg == 0 && np->time == 0 && np->ncall == 0)
589: continue;
590: time = np->time/totime;
591: lasty = ranoff - (np->value - lowpc)*scale;
592: if(lasty >= -2040. && lasty <= 2040.) {
593: char bufl[BUFSIZ], *namp;
594: register int j;
595: line(0, (int)lasty, 50, (int)lasty);
596: line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty);
597: move((int)(lastx+30), (int)(lasty+10));
598: sprintf(bufl, "%s", np->name + (np->name[0] == '_'));
599: label(bufl);
600: }
601: lastx += 500.;
602: if(lastx > 2000.)
603: lastx = 50.;
604: }
605: }
606: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.