14510Speter #ifndef lint 2*7257Smckusick static char *sccsid = "@(#)gprof.c 1.18 (Berkeley) 06/21/82"; 34510Speter #endif lint 44510Speter 54563Speter #include "gprof.h" 64510Speter 77128Speter char *whoami = "gprof"; 87128Speter 97223Speter /* 107223Speter * things which get -E excluded by default. 117223Speter */ 127223Speter char *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; 137173Speter 144510Speter main(argc, argv) 157173Speter int argc; 167173Speter char **argv; 174510Speter { 187173Speter char **sp; 194510Speter 204510Speter --argc; 214510Speter argv++; 224510Speter debug = 0; 234510Speter while ( *argv != 0 && **argv == '-' ) { 244510Speter (*argv)++; 254866Smckusic switch ( **argv ) { 267173Speter case 'a': 277173Speter aflag = TRUE; 287173Speter break; 297173Speter case 'b': 307173Speter bflag = TRUE; 317173Speter break; 327173Speter case 'c': 337173Speter cflag = TRUE; 347173Speter break; 354866Smckusic case 'd': 367173Speter dflag = TRUE; 374510Speter (*argv)++; 384510Speter debug |= atoi( *argv ); 394510Speter debug |= ANYDEBUG; 404510Speter # ifdef DEBUG 414510Speter printf( "[main] debug = %d\n" , debug ); 424510Speter # endif DEBUG 434866Smckusic break; 447223Speter case 'E': 457223Speter ++argv; 467223Speter addlist( Elist , *argv ); 477223Speter Eflag = TRUE; 487223Speter addlist( elist , *argv ); 497223Speter eflag = TRUE; 507223Speter break; 517173Speter case 'e': 527223Speter addlist( elist , *++argv ); 537173Speter eflag = TRUE; 544866Smckusic break; 557223Speter case 'F': 567223Speter ++argv; 577223Speter addlist( Flist , *argv ); 587223Speter Fflag = TRUE; 597223Speter addlist( flist , *argv ); 607223Speter fflag = TRUE; 617223Speter break; 627173Speter case 'f': 637223Speter addlist( flist , *++argv ); 647173Speter fflag = TRUE; 654866Smckusic break; 664866Smckusic case 's': 677173Speter sflag = TRUE; 684866Smckusic break; 694866Smckusic case 'z': 707173Speter zflag = TRUE; 714866Smckusic break; 724510Speter } 734510Speter argv++; 744510Speter } 754510Speter if ( *argv != 0 ) { 764510Speter a_outname = *argv; 774510Speter argv++; 784510Speter } else { 794510Speter a_outname = A_OUTNAME; 804510Speter } 814510Speter if ( *argv != 0 ) { 824563Speter gmonname = *argv; 834510Speter argv++; 844510Speter } else { 854563Speter gmonname = GMONNAME; 864510Speter } 874510Speter /* 887173Speter * turn off default functions 897173Speter */ 907223Speter for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 917223Speter Eflag = TRUE; 927223Speter addlist( Elist , *sp ); 937173Speter eflag = TRUE; 947223Speter addlist( elist , *sp ); 957173Speter } 967173Speter /* 974510Speter * get information about a.out file. 984510Speter */ 994510Speter getnfile(); 1004510Speter /* 1014510Speter * get information about mon.out file(s). 1024510Speter */ 1034866Smckusic do { 1044866Smckusic getpfile( gmonname ); 1054866Smckusic if ( *argv != 0 ) { 1064866Smckusic gmonname = *argv; 1074866Smckusic } 1087128Speter } while ( *argv++ != 0 ); 1094510Speter /* 1104866Smckusic * dump out a gmon.sum file if requested 1114866Smckusic */ 1127128Speter if ( sflag ) { 1137128Speter dumpsum( GMONSUM ); 1147128Speter } 1154866Smckusic /* 1164510Speter * assign samples to procedures 1174510Speter */ 1184510Speter asgnsamples(); 1194510Speter /* 1204510Speter * print the usual profile 1214510Speter */ 1224510Speter printprof(); 1234510Speter /* 1244510Speter * assemble and print the dynamic profile 1254510Speter */ 1264510Speter doarcs(); 1274510Speter done(); 1284510Speter } 1294510Speter 1307128Speter /* 1317128Speter * Set up string and symbol tables from a.out. 1327128Speter * and optionally the text space. 1337128Speter * On return symbol table is sorted by value. 1347128Speter */ 1354510Speter getnfile() 1364510Speter { 1374510Speter FILE *nfile; 1384510Speter 1394510Speter nfile = fopen( a_outname ,"r"); 1404510Speter if (nfile == NULL) { 1414510Speter perror( a_outname ); 1424510Speter done(); 1434510Speter } 1444510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1454510Speter if (N_BADMAG(xbuf)) { 1467128Speter fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 1474510Speter done(); 1484510Speter } 1494510Speter getstrtab(nfile); 1504510Speter getsymtab(nfile); 1514720Speter gettextspace( nfile ); 1524510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1534510Speter fclose(nfile); 1544510Speter # ifdef DEBUG 1554510Speter if ( debug & AOUTDEBUG ) { 1564510Speter register int j; 1574510Speter 1584510Speter for (j = 0; j < nname; j++){ 1594510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1604510Speter } 1614510Speter } 1624510Speter # endif DEBUG 1634510Speter } 1644510Speter 1654510Speter getstrtab(nfile) 1664510Speter FILE *nfile; 1674510Speter { 1684510Speter 1694510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1704510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1717128Speter fprintf(stderr, "%s: %s: no string table (old format?)\n" , 1727128Speter whoami , a_outname ); 1734510Speter done(); 1744510Speter } 1754510Speter strtab = (char *)calloc(ssiz, 1); 1764510Speter if (strtab == NULL) { 1777128Speter fprintf(stderr, "%s: %s: no room for %d bytes of string table", 1787128Speter whoami , a_outname , ssiz); 1794510Speter done(); 1804510Speter } 1814510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1827128Speter fprintf(stderr, "%s: %s: error reading string table\n", 1837128Speter whoami , a_outname ); 1844510Speter done(); 1854510Speter } 1864510Speter } 1874510Speter 1884510Speter /* 1894510Speter * Read in symbol table 1904510Speter */ 1914510Speter getsymtab(nfile) 1924510Speter FILE *nfile; 1934510Speter { 1944510Speter register long i; 1954510Speter int askfor; 1964510Speter struct nlist nbuf; 1974510Speter 1984510Speter /* pass1 - count symbols */ 1994510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2004510Speter nname = 0; 2014510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2024510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2034845Speter if ( ! funcsymbol( &nbuf ) ) { 2044510Speter continue; 2054510Speter } 2064510Speter nname++; 2074510Speter } 2084510Speter if (nname == 0) { 2097128Speter fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 2104510Speter done(); 2114510Speter } 2127128Speter askfor = nname + 1; 2134510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 2144510Speter if (nl == 0) { 2157128Speter fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 2167128Speter whoami, askfor * sizeof(nltype) ); 2174510Speter done(); 2184510Speter } 2194510Speter 2204510Speter /* pass2 - read symbols */ 2214510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2224510Speter npe = nl; 2234510Speter nname = 0; 2244510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2254510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2264845Speter if ( ! funcsymbol( &nbuf ) ) { 2274845Speter # ifdef DEBUG 2284845Speter if ( debug & AOUTDEBUG ) { 2294845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 2304845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 2314845Speter } 2324845Speter # endif DEBUG 2334510Speter continue; 2344510Speter } 2354510Speter npe->value = nbuf.n_value; 2364510Speter npe->name = strtab+nbuf.n_un.n_strx; 2374510Speter # ifdef DEBUG 2384510Speter if ( debug & AOUTDEBUG ) { 2394510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2404510Speter nname , npe -> name , npe -> value ); 2414510Speter } 2424510Speter # endif DEBUG 2434510Speter npe++; 2444510Speter nname++; 2454510Speter } 2464510Speter npe->value = -1; 2474510Speter npe++; 2484510Speter } 2494510Speter 2504510Speter /* 2514720Speter * read in the text space of an a.out file 2524720Speter */ 2534720Speter gettextspace( nfile ) 2544720Speter FILE *nfile; 2554720Speter { 2564720Speter unsigned char *malloc(); 2574720Speter 2584720Speter if ( cflag == 0 ) { 2594720Speter return; 2604720Speter } 2614720Speter textspace = malloc( xbuf.a_text ); 2624720Speter if ( textspace == 0 ) { 2637128Speter fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 2647128Speter whoami , xbuf.a_text ); 2657128Speter fprintf( stderr , "can't do -c\n" ); 2664720Speter return; 2674720Speter } 2684720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2694720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2707128Speter fprintf( stderr , "%s: couldn't read text space: " , whoami ); 2717128Speter fprintf( stderr , "can't do -c\n" ); 2724720Speter free( textspace ); 2734720Speter textspace = 0; 2744720Speter return; 2754720Speter } 2764720Speter } 2774720Speter /* 2784563Speter * information from a gmon.out file is in two parts: 2794510Speter * an array of sampling hits within pc ranges, 2804510Speter * and the arcs. 2814510Speter */ 2824510Speter getpfile(filename) 2834510Speter char *filename; 2844510Speter { 2854510Speter FILE *pfile; 2864510Speter FILE *openpfile(); 2874510Speter struct rawarc arc; 2884510Speter 2894510Speter pfile = openpfile(filename); 2904510Speter readsamples(pfile); 2914510Speter /* 2924510Speter * the rest of the file consists of 2934510Speter * a bunch of <from,self,count> tuples. 2944510Speter */ 2954510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2964510Speter # ifdef DEBUG 2974510Speter if ( debug & SAMPLEDEBUG ) { 2984752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2994510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3004510Speter } 3014510Speter # endif DEBUG 3024510Speter /* 3034510Speter * add this arc 3044510Speter */ 3054510Speter tally( &arc ); 3064510Speter } 3074510Speter fclose(pfile); 3084510Speter } 3094510Speter 3104841Speter FILE * 3114841Speter openpfile(filename) 3124510Speter char *filename; 3134510Speter { 3144866Smckusic struct hdr tmp; 3154510Speter FILE *pfile; 3164510Speter 3174510Speter if((pfile = fopen(filename, "r")) == NULL) { 3184510Speter perror(filename); 3194510Speter done(); 3204510Speter } 3214866Smckusic fread(&tmp, sizeof(struct hdr), 1, pfile); 3224866Smckusic if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc || 3234866Smckusic tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) { 3244866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 3254866Smckusic done(); 3264866Smckusic } 3274866Smckusic h = tmp; 3284752Speter s_lowpc = (unsigned long) h.lowpc; 3294752Speter s_highpc = (unsigned long) h.highpc; 3307227Smckusick lowpc = (unsigned long)h.lowpc / sizeof(UNIT); 3317227Smckusick highpc = (unsigned long)h.highpc / sizeof(UNIT); 3324510Speter sampbytes = h.ncnt - sizeof(struct hdr); 3334510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 3347226Speter # ifdef DEBUG 3357226Speter if ( debug & SAMPLEDEBUG ) { 3367226Speter printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n", 3377226Speter h.lowpc , h.highpc , h.ncnt ); 3387226Speter printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 3397226Speter s_lowpc , s_highpc ); 3407226Speter printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 3417226Speter lowpc , highpc ); 3427226Speter printf( "[openpfile] sampbytes %d nsamples %d\n" , 3437226Speter sampbytes , nsamples ); 3447226Speter } 3457226Speter # endif DEBUG 3464510Speter return(pfile); 3474510Speter } 3484510Speter 3494510Speter tally( rawp ) 3504510Speter struct rawarc *rawp; 3514510Speter { 3524510Speter nltype *parentp; 3534510Speter nltype *childp; 3544510Speter 3554510Speter parentp = nllookup( rawp -> raw_frompc ); 3564510Speter childp = nllookup( rawp -> raw_selfpc ); 3574510Speter childp -> ncall += rawp -> raw_count; 3584510Speter # ifdef DEBUG 3594510Speter if ( debug & TALLYDEBUG ) { 3604510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3614510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3624510Speter } 3634510Speter # endif DEBUG 3644720Speter addarc( parentp , childp , rawp -> raw_count ); 3654510Speter } 3664510Speter 3674866Smckusic /* 3684866Smckusic * dump out the gmon.sum file 3694866Smckusic */ 3704866Smckusic dumpsum( sumfile ) 3714866Smckusic char *sumfile; 3724866Smckusic { 3734866Smckusic register nltype *nlp; 3744866Smckusic register arctype *arcp; 3754866Smckusic struct rawarc arc; 3764866Smckusic FILE *sfile; 3774866Smckusic 3784866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3794866Smckusic perror( sumfile ); 3804866Smckusic done(); 3814866Smckusic } 3824866Smckusic /* 3834866Smckusic * dump the header; use the last header read in 3844866Smckusic */ 3854866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 3864866Smckusic perror( sumfile ); 3874866Smckusic done(); 3884866Smckusic } 3894866Smckusic /* 3904866Smckusic * dump the samples 3914866Smckusic */ 3924866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 3934866Smckusic perror( sumfile ); 3944866Smckusic done(); 3954866Smckusic } 3964866Smckusic /* 3974866Smckusic * dump the normalized raw arc information 3984866Smckusic */ 3994866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 4004866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 4014866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 4024866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 4034866Smckusic arc.raw_count = arcp -> arc_count; 4044866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 4054866Smckusic perror( sumfile ); 4064866Smckusic done(); 4074866Smckusic } 4084866Smckusic # ifdef DEBUG 4094866Smckusic if ( debug & SAMPLEDEBUG ) { 4104866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 4114866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4124866Smckusic } 4134866Smckusic # endif DEBUG 4144866Smckusic } 4154866Smckusic } 4164866Smckusic fclose( sfile ); 4174866Smckusic } 4184866Smckusic 4194510Speter valcmp(p1, p2) 4204510Speter nltype *p1, *p2; 4214510Speter { 4224510Speter if ( p1 -> value < p2 -> value ) { 4234510Speter return LESSTHAN; 4244510Speter } 4254510Speter if ( p1 -> value > p2 -> value ) { 4264510Speter return GREATERTHAN; 4274510Speter } 4284510Speter return EQUALTO; 4294510Speter } 4304510Speter 4314510Speter readsamples(pfile) 4324510Speter FILE *pfile; 4334510Speter { 4344510Speter register i; 4354510Speter unsigned UNIT sample; 4364510Speter 4374510Speter if (samples == 0) { 4384510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 4394510Speter if (samples == 0) { 4407128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 4417128Speter whoami , sampbytes / sizeof (unsigned UNIT)); 4424510Speter done(); 4434510Speter } 4444510Speter } 4454510Speter for (i = 0; i < nsamples; i++) { 4464510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 4474510Speter if (feof(pfile)) 4484510Speter break; 4494510Speter samples[i] += sample; 4504510Speter } 4514510Speter if (i != nsamples) { 4524510Speter fprintf(stderr, 4537128Speter "%s: unexpected EOF after reading %d/%d samples\n", 4547128Speter whoami , --i , nsamples ); 4554510Speter done(); 4564510Speter } 4574510Speter } 4584510Speter 4594510Speter /* 4604510Speter * Assign samples to the procedures to which they belong. 4614510Speter */ 4624510Speter asgnsamples() 4634510Speter { 4644510Speter register int j; 4654510Speter unsigned UNIT ccnt; 4664510Speter double time; 4674510Speter unsigned long pcl, pch; 4684510Speter register int i; 4694841Speter unsigned long overlap; 4704510Speter unsigned long svalue0, svalue1; 4714510Speter 4724510Speter /* read samples and assign to namelist symbols */ 4734510Speter scale = highpc - lowpc; 4744510Speter scale /= nsamples; 475*7257Smckusick for (i = 0, j = 1; i < nsamples; i++) { 4764510Speter ccnt = samples[i]; 4774510Speter if (ccnt == 0) 4784510Speter continue; 4794510Speter pcl = lowpc + scale*i; 4804510Speter pch = lowpc + scale*(i+1); 4814510Speter time = ccnt; 4824510Speter # ifdef DEBUG 4834510Speter if ( debug & SAMPLEDEBUG ) { 4845072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4855072Smckusic pcl , pch , ccnt ); 4864510Speter } 4874510Speter # endif DEBUG 4884510Speter totime += time; 4897252Smckusick for (j = j - 1; j < nname; j++) { 4904510Speter svalue0 = nl[j].value / sizeof(UNIT); 4914510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4924510Speter if (pch < svalue0) 4934510Speter break; 4944510Speter if (pcl >= svalue1) 4954510Speter continue; 4964510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4974510Speter if (overlap>0) { 4984510Speter # ifdef DEBUG 4994510Speter if ( debug & SAMPLEDEBUG ) { 5005072Smckusic printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" , 5015072Smckusic svalue0 , svalue1 , nl[j].name , 5025072Smckusic overlap*time/scale ); 5034510Speter } 5044510Speter # endif DEBUG 5054510Speter nl[j].time += overlap*time/scale; 5064510Speter } 5074510Speter } 5084510Speter } 5094510Speter # ifdef DEBUG 5104510Speter if ( debug & SAMPLEDEBUG ) { 5114510Speter printf( "[asgnsamples] totime %f\n" , totime ); 5124510Speter } 5134510Speter # endif DEBUG 5144510Speter } 5154510Speter 5164510Speter 5174841Speter unsigned long 5184510Speter min(a, b) 5194841Speter unsigned long a,b; 5204510Speter { 5214510Speter if (a<b) 5224510Speter return(a); 5234510Speter return(b); 5244510Speter } 5254510Speter 5264841Speter unsigned long 5274510Speter max(a, b) 5284841Speter unsigned long a,b; 5294510Speter { 5304510Speter if (a>b) 5314510Speter return(a); 5324510Speter return(b); 5334510Speter } 5344510Speter 5354845Speter bool 5364845Speter funcsymbol( nlistp ) 5374845Speter struct nlist *nlistp; 5384845Speter { 5394845Speter extern char *strtab; /* string table from a.out */ 5404851Speter extern int aflag; /* if static functions aren't desired */ 5414845Speter char *name; 5424845Speter 5434845Speter /* 5444845Speter * must be a text symbol, 5454851Speter * and static text symbols don't qualify if aflag set. 5464845Speter */ 5474845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5484851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5494845Speter return FALSE; 5504845Speter } 5514845Speter /* 5527128Speter * can't have any `funny' characters in name, 5534845Speter * where `funny' includes `.', .o file names 5544845Speter * and `$', pascal labels. 5554845Speter */ 5564845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5574845Speter if ( *name == '.' || *name == '$' ) { 5584845Speter return FALSE; 5594845Speter } 5604845Speter } 5614845Speter return TRUE; 5624845Speter } 5634845Speter 5644510Speter done() 5654510Speter { 5664510Speter 5674510Speter exit(0); 5684510Speter } 569