14510Speter #ifndef lint 2*7128Speter static char *sccsid = "@(#)gprof.c 1.11 (Berkeley) 06/08/82"; 34510Speter #endif lint 44510Speter 54563Speter #include "gprof.h" 64510Speter 7*7128Speter char *whoami = "gprof"; 8*7128Speter 94510Speter main(argc, argv) 104510Speter int argc; 114510Speter char **argv; 124510Speter { 134510Speter 144510Speter --argc; 154510Speter argv++; 164510Speter debug = 0; 174510Speter while ( *argv != 0 && **argv == '-' ) { 184510Speter (*argv)++; 194866Smckusic switch ( **argv ) { 204866Smckusic case 'd': 214510Speter (*argv)++; 224510Speter debug |= atoi( *argv ); 234510Speter debug |= ANYDEBUG; 244510Speter # ifdef DEBUG 254510Speter printf( "[main] debug = %d\n" , debug ); 264510Speter # endif DEBUG 274866Smckusic break; 284866Smckusic case 'a': 294845Speter aflag++; 304866Smckusic break; 314866Smckusic case 'b': 324853Speter bflag++; 334866Smckusic break; 344866Smckusic case 'c': 354845Speter cflag++; 364866Smckusic break; 374866Smckusic case 's': 384866Smckusic sflag++; 394866Smckusic break; 404866Smckusic case 'z': 414853Speter zflag++; 424866Smckusic break; 434510Speter } 444510Speter argv++; 454510Speter } 464510Speter if ( *argv != 0 ) { 474510Speter a_outname = *argv; 484510Speter argv++; 494510Speter } else { 504510Speter a_outname = A_OUTNAME; 514510Speter } 524510Speter if ( *argv != 0 ) { 534563Speter gmonname = *argv; 544510Speter argv++; 554510Speter } else { 564563Speter gmonname = GMONNAME; 574510Speter } 584510Speter /* 594510Speter * get information about a.out file. 604510Speter */ 614510Speter getnfile(); 624510Speter /* 634510Speter * get information about mon.out file(s). 644510Speter */ 654866Smckusic do { 664866Smckusic getpfile( gmonname ); 674866Smckusic if ( *argv != 0 ) { 684866Smckusic gmonname = *argv; 694866Smckusic } 70*7128Speter } while ( *argv++ != 0 ); 714510Speter /* 724866Smckusic * dump out a gmon.sum file if requested 734866Smckusic */ 74*7128Speter if ( sflag ) { 75*7128Speter dumpsum( GMONSUM ); 76*7128Speter } 774866Smckusic /* 784510Speter * assign samples to procedures 794510Speter */ 804510Speter asgnsamples(); 814510Speter /* 824510Speter * print the usual profile 834510Speter */ 844510Speter printprof(); 854510Speter /* 864510Speter * assemble and print the dynamic profile 874510Speter */ 884510Speter doarcs(); 894510Speter done(); 904510Speter } 914510Speter 92*7128Speter /* 93*7128Speter * Set up string and symbol tables from a.out. 94*7128Speter * and optionally the text space. 95*7128Speter * On return symbol table is sorted by value. 96*7128Speter */ 974510Speter getnfile() 984510Speter { 994510Speter FILE *nfile; 1004510Speter 1014510Speter nfile = fopen( a_outname ,"r"); 1024510Speter if (nfile == NULL) { 1034510Speter perror( a_outname ); 1044510Speter done(); 1054510Speter } 1064510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1074510Speter if (N_BADMAG(xbuf)) { 108*7128Speter fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 1094510Speter done(); 1104510Speter } 1114510Speter getstrtab(nfile); 1124510Speter getsymtab(nfile); 1134720Speter gettextspace( nfile ); 1144510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1154510Speter fclose(nfile); 1164510Speter # ifdef DEBUG 1174510Speter if ( debug & AOUTDEBUG ) { 1184510Speter register int j; 1194510Speter 1204510Speter for (j = 0; j < nname; j++){ 1214510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1224510Speter } 1234510Speter } 1244510Speter # endif DEBUG 1254510Speter } 1264510Speter 1274510Speter getstrtab(nfile) 1284510Speter FILE *nfile; 1294510Speter { 1304510Speter 1314510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1324510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 133*7128Speter fprintf(stderr, "%s: %s: no string table (old format?)\n" , 134*7128Speter whoami , a_outname ); 1354510Speter done(); 1364510Speter } 1374510Speter strtab = (char *)calloc(ssiz, 1); 1384510Speter if (strtab == NULL) { 139*7128Speter fprintf(stderr, "%s: %s: no room for %d bytes of string table", 140*7128Speter whoami , a_outname , ssiz); 1414510Speter done(); 1424510Speter } 1434510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 144*7128Speter fprintf(stderr, "%s: %s: error reading string table\n", 145*7128Speter whoami , a_outname ); 1464510Speter done(); 1474510Speter } 1484510Speter } 1494510Speter 1504510Speter /* 1514510Speter * Read in symbol table 1524510Speter */ 1534510Speter getsymtab(nfile) 1544510Speter FILE *nfile; 1554510Speter { 1564510Speter register long i; 1574510Speter int askfor; 1584510Speter struct nlist nbuf; 1594510Speter 1604510Speter /* pass1 - count symbols */ 1614510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1624510Speter nname = 0; 1634510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1644510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1654845Speter if ( ! funcsymbol( &nbuf ) ) { 1664510Speter continue; 1674510Speter } 1684510Speter nname++; 1694510Speter } 1704510Speter if (nname == 0) { 171*7128Speter fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 1724510Speter done(); 1734510Speter } 174*7128Speter askfor = nname + 1; 1754510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 1764510Speter if (nl == 0) { 177*7128Speter fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 178*7128Speter whoami, askfor * sizeof(nltype) ); 1794510Speter done(); 1804510Speter } 1814510Speter 1824510Speter /* pass2 - read symbols */ 1834510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1844510Speter npe = nl; 1854510Speter nname = 0; 1864510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1874510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1884845Speter if ( ! funcsymbol( &nbuf ) ) { 1894845Speter # ifdef DEBUG 1904845Speter if ( debug & AOUTDEBUG ) { 1914845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 1924845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 1934845Speter } 1944845Speter # endif DEBUG 1954510Speter continue; 1964510Speter } 1974510Speter npe->value = nbuf.n_value; 1984510Speter npe->name = strtab+nbuf.n_un.n_strx; 1994510Speter # ifdef DEBUG 2004510Speter if ( debug & AOUTDEBUG ) { 2014510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2024510Speter nname , npe -> name , npe -> value ); 2034510Speter } 2044510Speter # endif DEBUG 2054510Speter npe++; 2064510Speter nname++; 2074510Speter } 2084510Speter npe->value = -1; 2094510Speter npe++; 2104510Speter } 2114510Speter 2124510Speter /* 2134720Speter * read in the text space of an a.out file 2144720Speter */ 2154720Speter gettextspace( nfile ) 2164720Speter FILE *nfile; 2174720Speter { 2184720Speter unsigned char *malloc(); 2194720Speter 2204720Speter if ( cflag == 0 ) { 2214720Speter return; 2224720Speter } 2234720Speter textspace = malloc( xbuf.a_text ); 2244720Speter if ( textspace == 0 ) { 225*7128Speter fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 226*7128Speter whoami , xbuf.a_text ); 227*7128Speter fprintf( stderr , "can't do -c\n" ); 2284720Speter return; 2294720Speter } 2304720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2314720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 232*7128Speter fprintf( stderr , "%s: couldn't read text space: " , whoami ); 233*7128Speter fprintf( stderr , "can't do -c\n" ); 2344720Speter free( textspace ); 2354720Speter textspace = 0; 2364720Speter return; 2374720Speter } 2384720Speter } 2394720Speter /* 2404563Speter * information from a gmon.out file is in two parts: 2414510Speter * an array of sampling hits within pc ranges, 2424510Speter * and the arcs. 2434510Speter */ 2444510Speter getpfile(filename) 2454510Speter char *filename; 2464510Speter { 2474510Speter FILE *pfile; 2484510Speter FILE *openpfile(); 2494510Speter struct rawarc arc; 2504510Speter 2514510Speter pfile = openpfile(filename); 2524510Speter readsamples(pfile); 2534510Speter /* 2544510Speter * the rest of the file consists of 2554510Speter * a bunch of <from,self,count> tuples. 2564510Speter */ 2574510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2584510Speter # ifdef DEBUG 2594510Speter if ( debug & SAMPLEDEBUG ) { 2604752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2614510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2624510Speter } 2634510Speter # endif DEBUG 2644510Speter /* 2654510Speter * add this arc 2664510Speter */ 2674510Speter tally( &arc ); 2684510Speter } 2694510Speter fclose(pfile); 2704510Speter } 2714510Speter 2724841Speter FILE * 2734841Speter openpfile(filename) 2744510Speter char *filename; 2754510Speter { 2764866Smckusic struct hdr tmp; 2774510Speter FILE *pfile; 2784510Speter 2794510Speter if((pfile = fopen(filename, "r")) == NULL) { 2804510Speter perror(filename); 2814510Speter done(); 2824510Speter } 2834866Smckusic fread(&tmp, sizeof(struct hdr), 1, pfile); 2844866Smckusic if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc || 2854866Smckusic tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) { 2864866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 2874866Smckusic done(); 2884866Smckusic } 2894866Smckusic h = tmp; 2904752Speter s_lowpc = (unsigned long) h.lowpc; 2914752Speter s_highpc = (unsigned long) h.highpc; 2924510Speter lowpc = h.lowpc - (UNIT *)0; 2934510Speter highpc = h.highpc - (UNIT *)0; 2944510Speter sampbytes = h.ncnt - sizeof(struct hdr); 2954510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 2964510Speter return(pfile); 2974510Speter } 2984510Speter 2994510Speter tally( rawp ) 3004510Speter struct rawarc *rawp; 3014510Speter { 3024510Speter nltype *parentp; 3034510Speter nltype *childp; 3044510Speter 3054510Speter parentp = nllookup( rawp -> raw_frompc ); 3064510Speter childp = nllookup( rawp -> raw_selfpc ); 3074510Speter childp -> ncall += rawp -> raw_count; 3084510Speter # ifdef DEBUG 3094510Speter if ( debug & TALLYDEBUG ) { 3104510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3114510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3124510Speter } 3134510Speter # endif DEBUG 3144720Speter addarc( parentp , childp , rawp -> raw_count ); 3154510Speter } 3164510Speter 3174866Smckusic /* 3184866Smckusic * dump out the gmon.sum file 3194866Smckusic */ 3204866Smckusic dumpsum( sumfile ) 3214866Smckusic char *sumfile; 3224866Smckusic { 3234866Smckusic register nltype *nlp; 3244866Smckusic register arctype *arcp; 3254866Smckusic struct rawarc arc; 3264866Smckusic FILE *sfile; 3274866Smckusic 3284866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3294866Smckusic perror( sumfile ); 3304866Smckusic done(); 3314866Smckusic } 3324866Smckusic /* 3334866Smckusic * dump the header; use the last header read in 3344866Smckusic */ 3354866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 3364866Smckusic perror( sumfile ); 3374866Smckusic done(); 3384866Smckusic } 3394866Smckusic /* 3404866Smckusic * dump the samples 3414866Smckusic */ 3424866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 3434866Smckusic perror( sumfile ); 3444866Smckusic done(); 3454866Smckusic } 3464866Smckusic /* 3474866Smckusic * dump the normalized raw arc information 3484866Smckusic */ 3494866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 3504866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3514866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 3524866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 3534866Smckusic arc.raw_count = arcp -> arc_count; 3544866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3554866Smckusic perror( sumfile ); 3564866Smckusic done(); 3574866Smckusic } 3584866Smckusic # ifdef DEBUG 3594866Smckusic if ( debug & SAMPLEDEBUG ) { 3604866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 3614866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3624866Smckusic } 3634866Smckusic # endif DEBUG 3644866Smckusic } 3654866Smckusic } 3664866Smckusic fclose( sfile ); 3674866Smckusic } 3684866Smckusic 3694510Speter valcmp(p1, p2) 3704510Speter nltype *p1, *p2; 3714510Speter { 3724510Speter if ( p1 -> value < p2 -> value ) { 3734510Speter return LESSTHAN; 3744510Speter } 3754510Speter if ( p1 -> value > p2 -> value ) { 3764510Speter return GREATERTHAN; 3774510Speter } 3784510Speter return EQUALTO; 3794510Speter } 3804510Speter 3814510Speter readsamples(pfile) 3824510Speter FILE *pfile; 3834510Speter { 3844510Speter register i; 3854510Speter unsigned UNIT sample; 3864510Speter 3874510Speter if (samples == 0) { 3884510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 3894510Speter if (samples == 0) { 390*7128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 391*7128Speter whoami , sampbytes / sizeof (unsigned UNIT)); 3924510Speter done(); 3934510Speter } 3944510Speter } 3954510Speter for (i = 0; i < nsamples; i++) { 3964510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 3974510Speter if (feof(pfile)) 3984510Speter break; 3994510Speter samples[i] += sample; 4004510Speter } 4014510Speter if (i != nsamples) { 4024510Speter fprintf(stderr, 403*7128Speter "%s: unexpected EOF after reading %d/%d samples\n", 404*7128Speter whoami , --i , nsamples ); 4054510Speter done(); 4064510Speter } 4074510Speter } 4084510Speter 4094510Speter /* 4104510Speter * Assign samples to the procedures to which they belong. 4114510Speter */ 4124510Speter asgnsamples() 4134510Speter { 4144510Speter register int j; 4154510Speter unsigned UNIT ccnt; 4164510Speter double time; 4174510Speter unsigned long pcl, pch; 4184510Speter register int i; 4194841Speter unsigned long overlap; 4204510Speter unsigned long svalue0, svalue1; 4214510Speter 4224510Speter /* read samples and assign to namelist symbols */ 4234510Speter scale = highpc - lowpc; 4244510Speter scale /= nsamples; 4254510Speter for (i=0; i < nsamples; i++) { 4264510Speter ccnt = samples[i]; 4274510Speter if (ccnt == 0) 4284510Speter continue; 4294510Speter pcl = lowpc + scale*i; 4304510Speter pch = lowpc + scale*(i+1); 4314510Speter time = ccnt; 4324510Speter # ifdef DEBUG 4334510Speter if ( debug & SAMPLEDEBUG ) { 4345072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4355072Smckusic pcl , pch , ccnt ); 4364510Speter } 4374510Speter # endif DEBUG 4384510Speter totime += time; 4394510Speter for (j=0; j<nname; j++) { 4404510Speter svalue0 = nl[j].value / sizeof(UNIT); 4414510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4424510Speter if (pch < svalue0) 4434510Speter break; 4444510Speter if (pcl >= svalue1) 4454510Speter continue; 4464510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4474510Speter if (overlap>0) { 4484510Speter # ifdef DEBUG 4494510Speter if ( debug & SAMPLEDEBUG ) { 4505072Smckusic printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" , 4515072Smckusic svalue0 , svalue1 , nl[j].name , 4525072Smckusic overlap*time/scale ); 4534510Speter } 4544510Speter # endif DEBUG 4554510Speter nl[j].time += overlap*time/scale; 4564510Speter } 4574510Speter } 4584510Speter } 4594510Speter # ifdef DEBUG 4604510Speter if ( debug & SAMPLEDEBUG ) { 4614510Speter printf( "[asgnsamples] totime %f\n" , totime ); 4624510Speter } 4634510Speter # endif DEBUG 4644510Speter if (totime==0.0) { 4654510Speter fprintf( stderr , "No time accumulated\n" ); 4664510Speter totime=1.0; 4674510Speter } 4684510Speter } 4694510Speter 4704510Speter 4714841Speter unsigned long 4724510Speter min(a, b) 4734841Speter unsigned long a,b; 4744510Speter { 4754510Speter if (a<b) 4764510Speter return(a); 4774510Speter return(b); 4784510Speter } 4794510Speter 4804841Speter unsigned long 4814510Speter max(a, b) 4824841Speter unsigned long a,b; 4834510Speter { 4844510Speter if (a>b) 4854510Speter return(a); 4864510Speter return(b); 4874510Speter } 4884510Speter 4894845Speter bool 4904845Speter funcsymbol( nlistp ) 4914845Speter struct nlist *nlistp; 4924845Speter { 4934845Speter extern char *strtab; /* string table from a.out */ 4944851Speter extern int aflag; /* if static functions aren't desired */ 4954845Speter char *name; 4964845Speter 4974845Speter /* 4984845Speter * must be a text symbol, 4994851Speter * and static text symbols don't qualify if aflag set. 5004845Speter */ 5014845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5024851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5034845Speter return FALSE; 5044845Speter } 5054845Speter /* 506*7128Speter * can't have any `funny' characters in name, 5074845Speter * where `funny' includes `.', .o file names 5084845Speter * and `$', pascal labels. 5094845Speter */ 5104845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5114845Speter if ( *name == '.' || *name == '$' ) { 5124845Speter return FALSE; 5134845Speter } 5144845Speter } 5154845Speter return TRUE; 5164845Speter } 5174845Speter 5184510Speter done() 5194510Speter { 5204510Speter 5214510Speter exit(0); 5224510Speter } 523