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