|
|
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.