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