|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)gprof.c 1.22 (Berkeley) 5/11/83";
3: #endif lint
4:
5: #include "gprof.h"
6:
7: char *whoami = "gprof";
8:
9: /*
10: * things which get -E excluded by default.
11: */
12: char *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
13:
14: main(argc, argv)
15: int argc;
16: char **argv;
17: {
18: char **sp;
19:
20: --argc;
21: argv++;
22: debug = 0;
23: bflag = TRUE;
24: while ( *argv != 0 && **argv == '-' ) {
25: (*argv)++;
26: switch ( **argv ) {
27: case 'a':
28: aflag = TRUE;
29: break;
30: case 'b':
31: bflag = FALSE;
32: break;
33: case 'c':
34: cflag = TRUE;
35: break;
36: case 'd':
37: dflag = TRUE;
38: (*argv)++;
39: debug |= atoi( *argv );
40: debug |= ANYDEBUG;
41: # ifdef DEBUG
42: printf("[main] debug = %d\n", debug);
43: # else not DEBUG
44: printf("%s: -d ignored\n", whoami);
45: # endif DEBUG
46: break;
47: case 'E':
48: ++argv;
49: addlist( Elist , *argv );
50: Eflag = TRUE;
51: addlist( elist , *argv );
52: eflag = TRUE;
53: break;
54: case 'e':
55: addlist( elist , *++argv );
56: eflag = TRUE;
57: break;
58: case 'F':
59: ++argv;
60: addlist( Flist , *argv );
61: Fflag = TRUE;
62: addlist( flist , *argv );
63: fflag = TRUE;
64: break;
65: case 'f':
66: addlist( flist , *++argv );
67: fflag = TRUE;
68: break;
69: case 's':
70: sflag = TRUE;
71: break;
72: case 'z':
73: zflag = TRUE;
74: break;
75: }
76: argv++;
77: }
78: if ( *argv != 0 ) {
79: a_outname = *argv;
80: argv++;
81: } else {
82: a_outname = A_OUTNAME;
83: }
84: if ( *argv != 0 ) {
85: gmonname = *argv;
86: argv++;
87: } else {
88: gmonname = GMONNAME;
89: }
90: /*
91: * turn off default functions
92: */
93: for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
94: Eflag = TRUE;
95: addlist( Elist , *sp );
96: eflag = TRUE;
97: addlist( elist , *sp );
98: }
99: /*
100: * how long is a clock tick?
101: */
102: hz = hertz();
103: /*
104: * get information about a.out file.
105: */
106: getnfile();
107: /*
108: * get information about mon.out file(s).
109: */
110: do {
111: getpfile( gmonname );
112: if ( *argv != 0 ) {
113: gmonname = *argv;
114: }
115: } while ( *argv++ != 0 );
116: /*
117: * dump out a gmon.sum file if requested
118: */
119: if ( sflag ) {
120: dumpsum( GMONSUM );
121: }
122: /*
123: * assign samples to procedures
124: */
125: asgnsamples();
126: /*
127: * print the usual profile
128: */
129: printprof();
130: /*
131: * assemble and print the dynamic profile
132: */
133: doarcs();
134: done();
135: }
136:
137: /*
138: * Set up string and symbol tables from a.out.
139: * and optionally the text space.
140: * On return symbol table is sorted by value.
141: */
142: getnfile()
143: {
144: FILE *nfile;
145:
146: nfile = fopen( a_outname ,"r");
147: if (nfile == NULL) {
148: perror( a_outname );
149: done();
150: }
151: fread(&xbuf, 1, sizeof(xbuf), nfile);
152: if (N_BADMAG(xbuf)) {
153: fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
154: done();
155: }
156: getstrtab(nfile);
157: getsymtab(nfile);
158: gettextspace( nfile );
159: qsort(nl, nname, sizeof(nltype), valcmp);
160: fclose(nfile);
161: # ifdef DEBUG
162: if ( debug & AOUTDEBUG ) {
163: register int j;
164:
165: for (j = 0; j < nname; j++){
166: printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
167: }
168: }
169: # endif DEBUG
170: }
171:
172: getstrtab(nfile)
173: FILE *nfile;
174: {
175:
176: fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
177: if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
178: fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
179: whoami , a_outname );
180: done();
181: }
182: strtab = (char *)calloc(ssiz, 1);
183: if (strtab == NULL) {
184: fprintf(stderr, "%s: %s: no room for %d bytes of string table",
185: whoami , a_outname , ssiz);
186: done();
187: }
188: if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
189: fprintf(stderr, "%s: %s: error reading string table\n",
190: whoami , a_outname );
191: done();
192: }
193: }
194:
195: /*
196: * Read in symbol table
197: */
198: getsymtab(nfile)
199: FILE *nfile;
200: {
201: register long i;
202: int askfor;
203: struct nlist nbuf;
204:
205: /* pass1 - count symbols */
206: fseek(nfile, (long)N_SYMOFF(xbuf), 0);
207: nname = 0;
208: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
209: fread(&nbuf, sizeof(nbuf), 1, nfile);
210: if ( ! funcsymbol( &nbuf ) ) {
211: continue;
212: }
213: nname++;
214: }
215: if (nname == 0) {
216: fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
217: done();
218: }
219: askfor = nname + 1;
220: nl = (nltype *) calloc( askfor , sizeof(nltype) );
221: if (nl == 0) {
222: fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
223: whoami, askfor * sizeof(nltype) );
224: done();
225: }
226:
227: /* pass2 - read symbols */
228: fseek(nfile, (long)N_SYMOFF(xbuf), 0);
229: npe = nl;
230: nname = 0;
231: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
232: fread(&nbuf, sizeof(nbuf), 1, nfile);
233: if ( ! funcsymbol( &nbuf ) ) {
234: # ifdef DEBUG
235: if ( debug & AOUTDEBUG ) {
236: printf( "[getsymtab] rejecting: 0x%x %s\n" ,
237: nbuf.n_type , strtab + nbuf.n_un.n_strx );
238: }
239: # endif DEBUG
240: continue;
241: }
242: npe->value = nbuf.n_value;
243: npe->name = strtab+nbuf.n_un.n_strx;
244: # ifdef DEBUG
245: if ( debug & AOUTDEBUG ) {
246: printf( "[getsymtab] %d %s 0x%08x\n" ,
247: nname , npe -> name , npe -> value );
248: }
249: # endif DEBUG
250: npe++;
251: nname++;
252: }
253: npe->value = -1;
254: }
255:
256: /*
257: * read in the text space of an a.out file
258: */
259: gettextspace( nfile )
260: FILE *nfile;
261: {
262: unsigned char *malloc();
263:
264: if ( cflag == 0 ) {
265: return;
266: }
267: textspace = malloc( xbuf.a_text );
268: if ( textspace == 0 ) {
269: fprintf( stderr , "%s: ran out room for %d bytes of text space: " ,
270: whoami , xbuf.a_text );
271: fprintf( stderr , "can't do -c\n" );
272: return;
273: }
274: (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
275: if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
276: fprintf( stderr , "%s: couldn't read text space: " , whoami );
277: fprintf( stderr , "can't do -c\n" );
278: free( textspace );
279: textspace = 0;
280: return;
281: }
282: }
283: /*
284: * information from a gmon.out file is in two parts:
285: * an array of sampling hits within pc ranges,
286: * and the arcs.
287: */
288: getpfile(filename)
289: char *filename;
290: {
291: FILE *pfile;
292: FILE *openpfile();
293: struct rawarc arc;
294:
295: pfile = openpfile(filename);
296: readsamples(pfile);
297: /*
298: * the rest of the file consists of
299: * a bunch of <from,self,count> tuples.
300: */
301: while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
302: # ifdef DEBUG
303: if ( debug & SAMPLEDEBUG ) {
304: printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
305: arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
306: }
307: # endif DEBUG
308: /*
309: * add this arc
310: */
311: tally( &arc );
312: }
313: fclose(pfile);
314: }
315:
316: FILE *
317: openpfile(filename)
318: char *filename;
319: {
320: struct hdr tmp;
321: FILE *pfile;
322:
323: if((pfile = fopen(filename, "r")) == NULL) {
324: perror(filename);
325: done();
326: }
327: fread(&tmp, sizeof(struct hdr), 1, pfile);
328: if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
329: tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
330: fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
331: done();
332: }
333: h = tmp;
334: s_lowpc = (unsigned long) h.lowpc;
335: s_highpc = (unsigned long) h.highpc;
336: lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
337: highpc = (unsigned long)h.highpc / sizeof(UNIT);
338: sampbytes = h.ncnt - sizeof(struct hdr);
339: nsamples = sampbytes / sizeof (unsigned UNIT);
340: # ifdef DEBUG
341: if ( debug & SAMPLEDEBUG ) {
342: printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
343: h.lowpc , h.highpc , h.ncnt );
344: printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" ,
345: s_lowpc , s_highpc );
346: printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" ,
347: lowpc , highpc );
348: printf( "[openpfile] sampbytes %d nsamples %d\n" ,
349: sampbytes , nsamples );
350: }
351: # endif DEBUG
352: return(pfile);
353: }
354:
355: tally( rawp )
356: struct rawarc *rawp;
357: {
358: nltype *parentp;
359: nltype *childp;
360:
361: parentp = nllookup( rawp -> raw_frompc );
362: childp = nllookup( rawp -> raw_selfpc );
363: childp -> ncall += rawp -> raw_count;
364: # ifdef DEBUG
365: if ( debug & TALLYDEBUG ) {
366: printf( "[tally] arc from %s to %s traversed %d times\n" ,
367: parentp -> name , childp -> name , rawp -> raw_count );
368: }
369: # endif DEBUG
370: addarc( parentp , childp , rawp -> raw_count );
371: }
372:
373: /*
374: * dump out the gmon.sum file
375: */
376: dumpsum( sumfile )
377: char *sumfile;
378: {
379: register nltype *nlp;
380: register arctype *arcp;
381: struct rawarc arc;
382: FILE *sfile;
383:
384: if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
385: perror( sumfile );
386: done();
387: }
388: /*
389: * dump the header; use the last header read in
390: */
391: if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
392: perror( sumfile );
393: done();
394: }
395: /*
396: * dump the samples
397: */
398: if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
399: perror( sumfile );
400: done();
401: }
402: /*
403: * dump the normalized raw arc information
404: */
405: for ( nlp = nl ; nlp < npe ; nlp++ ) {
406: for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
407: arc.raw_frompc = arcp -> arc_parentp -> value;
408: arc.raw_selfpc = arcp -> arc_childp -> value;
409: arc.raw_count = arcp -> arc_count;
410: if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
411: perror( sumfile );
412: done();
413: }
414: # ifdef DEBUG
415: if ( debug & SAMPLEDEBUG ) {
416: printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
417: arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
418: }
419: # endif DEBUG
420: }
421: }
422: fclose( sfile );
423: }
424:
425: valcmp(p1, p2)
426: nltype *p1, *p2;
427: {
428: if ( p1 -> value < p2 -> value ) {
429: return LESSTHAN;
430: }
431: if ( p1 -> value > p2 -> value ) {
432: return GREATERTHAN;
433: }
434: return EQUALTO;
435: }
436:
437: readsamples(pfile)
438: FILE *pfile;
439: {
440: register i;
441: unsigned UNIT sample;
442:
443: if (samples == 0) {
444: samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
445: if (samples == 0) {
446: fprintf( stderr , "%s: No room for %d sample pc's\n",
447: whoami , sampbytes / sizeof (unsigned UNIT));
448: done();
449: }
450: }
451: for (i = 0; i < nsamples; i++) {
452: fread(&sample, sizeof (unsigned UNIT), 1, pfile);
453: if (feof(pfile))
454: break;
455: samples[i] += sample;
456: }
457: if (i != nsamples) {
458: fprintf(stderr,
459: "%s: unexpected EOF after reading %d/%d samples\n",
460: whoami , --i , nsamples );
461: done();
462: }
463: }
464:
465: /*
466: * Assign samples to the procedures to which they belong.
467: *
468: * There are three cases as to where pcl and pch can be
469: * with respect to the routine entry addresses svalue0 and svalue1
470: * as shown in the following diagram. overlap computes the
471: * distance between the arrows, the fraction of the sample
472: * that is to be credited to the routine which starts at svalue0.
473: *
474: * svalue0 svalue1
475: * | |
476: * v v
477: *
478: * +-----------------------------------------------+
479: * | |
480: * | ->| |<- ->| |<- ->| |<- |
481: * | | | | | |
482: * +---------+ +---------+ +---------+
483: *
484: * ^ ^ ^ ^ ^ ^
485: * | | | | | |
486: * pcl pch pcl pch pcl pch
487: *
488: * For the vax we assert that samples will never fall in the first
489: * two bytes of any routine, since that is the entry mask,
490: * thus we give call alignentries() to adjust the entry points if
491: * the entry mask falls in one bucket but the code for the routine
492: * doesn't start until the next bucket. In conjunction with the
493: * alignment of routine addresses, this should allow us to have
494: * only one sample for every four bytes of text space and never
495: * have any overlap (the two end cases, above).
496: */
497: asgnsamples()
498: {
499: register int j;
500: unsigned UNIT ccnt;
501: double time;
502: unsigned long pcl, pch;
503: register int i;
504: unsigned long overlap;
505: unsigned long svalue0, svalue1;
506:
507: /* read samples and assign to namelist symbols */
508: scale = highpc - lowpc;
509: scale /= nsamples;
510: alignentries();
511: for (i = 0, j = 1; i < nsamples; i++) {
512: ccnt = samples[i];
513: if (ccnt == 0)
514: continue;
515: pcl = lowpc + scale * i;
516: pch = lowpc + scale * (i + 1);
517: time = ccnt;
518: # ifdef DEBUG
519: if ( debug & SAMPLEDEBUG ) {
520: printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
521: pcl , pch , ccnt );
522: }
523: # endif DEBUG
524: totime += time;
525: for (j = j - 1; j < nname; j++) {
526: svalue0 = nl[j].svalue;
527: svalue1 = nl[j+1].svalue;
528: /*
529: * if high end of tick is below entry address,
530: * go for next tick.
531: */
532: if (pch < svalue0)
533: break;
534: /*
535: * if low end of tick into next routine,
536: * go for next routine.
537: */
538: if (pcl >= svalue1)
539: continue;
540: overlap = min(pch, svalue1) - max(pcl, svalue0);
541: if (overlap > 0) {
542: # ifdef DEBUG
543: if (debug & SAMPLEDEBUG) {
544: printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
545: nl[j].value/sizeof(UNIT), svalue0, svalue1,
546: nl[j].name,
547: overlap * time / scale, overlap);
548: }
549: # endif DEBUG
550: nl[j].time += overlap * time / scale;
551: }
552: }
553: }
554: # ifdef DEBUG
555: if (debug & SAMPLEDEBUG) {
556: printf("[asgnsamples] totime %f\n", totime);
557: }
558: # endif DEBUG
559: }
560:
561:
562: unsigned long
563: min(a, b)
564: unsigned long a,b;
565: {
566: if (a<b)
567: return(a);
568: return(b);
569: }
570:
571: unsigned long
572: max(a, b)
573: unsigned long a,b;
574: {
575: if (a>b)
576: return(a);
577: return(b);
578: }
579:
580: /*
581: * calculate scaled entry point addresses (to save time in asgnsamples),
582: * and possibly push the scaled entry points over the entry mask,
583: * if it turns out that the entry point is in one bucket and the code
584: * for a routine is in the next bucket.
585: */
586: alignentries()
587: {
588: register struct nl *nlp;
589: unsigned long bucket_of_entry;
590: unsigned long bucket_of_code;
591:
592: for (nlp = nl; nlp < npe; nlp++) {
593: nlp -> svalue = nlp -> value / sizeof(UNIT);
594: bucket_of_entry = (nlp->svalue - lowpc) / scale;
595: bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
596: if (bucket_of_entry < bucket_of_code) {
597: # ifdef DEBUG
598: if (debug & SAMPLEDEBUG) {
599: printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
600: nlp->svalue, nlp->svalue + UNITS_TO_CODE);
601: }
602: # endif DEBUG
603: nlp->svalue += UNITS_TO_CODE;
604: }
605: }
606: }
607:
608: bool
609: funcsymbol( nlistp )
610: struct nlist *nlistp;
611: {
612: extern char *strtab; /* string table from a.out */
613: extern int aflag; /* if static functions aren't desired */
614: char *name;
615:
616: /*
617: * must be a text symbol,
618: * and static text symbols don't qualify if aflag set.
619: */
620: if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
621: || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
622: return FALSE;
623: }
624: /*
625: * can't have any `funny' characters in name,
626: * where `funny' includes `.', .o file names
627: * and `$', pascal labels.
628: */
629: for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
630: if ( *name == '.' || *name == '$' ) {
631: return FALSE;
632: }
633: }
634: return TRUE;
635: }
636:
637: done()
638: {
639:
640: exit(0);
641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.