14510Speter #ifndef lint 2*10249Speter static char *sccsid = "@(#)gprof.c 1.19 (Berkeley) 01/11/83"; 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 /* 97*10249Speter * how long is a clock tick? 98*10249Speter */ 99*10249Speter hz = hertz(); 100*10249Speter /* 1014510Speter * get information about a.out file. 1024510Speter */ 1034510Speter getnfile(); 1044510Speter /* 1054510Speter * get information about mon.out file(s). 1064510Speter */ 1074866Smckusic do { 1084866Smckusic getpfile( gmonname ); 1094866Smckusic if ( *argv != 0 ) { 1104866Smckusic gmonname = *argv; 1114866Smckusic } 1127128Speter } while ( *argv++ != 0 ); 1134510Speter /* 1144866Smckusic * dump out a gmon.sum file if requested 1154866Smckusic */ 1167128Speter if ( sflag ) { 1177128Speter dumpsum( GMONSUM ); 1187128Speter } 1194866Smckusic /* 1204510Speter * assign samples to procedures 1214510Speter */ 1224510Speter asgnsamples(); 1234510Speter /* 1244510Speter * print the usual profile 1254510Speter */ 1264510Speter printprof(); 1274510Speter /* 1284510Speter * assemble and print the dynamic profile 1294510Speter */ 1304510Speter doarcs(); 1314510Speter done(); 1324510Speter } 1334510Speter 1347128Speter /* 1357128Speter * Set up string and symbol tables from a.out. 1367128Speter * and optionally the text space. 1377128Speter * On return symbol table is sorted by value. 1387128Speter */ 1394510Speter getnfile() 1404510Speter { 1414510Speter FILE *nfile; 1424510Speter 1434510Speter nfile = fopen( a_outname ,"r"); 1444510Speter if (nfile == NULL) { 1454510Speter perror( a_outname ); 1464510Speter done(); 1474510Speter } 1484510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1494510Speter if (N_BADMAG(xbuf)) { 1507128Speter fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 1514510Speter done(); 1524510Speter } 1534510Speter getstrtab(nfile); 1544510Speter getsymtab(nfile); 1554720Speter gettextspace( nfile ); 1564510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1574510Speter fclose(nfile); 1584510Speter # ifdef DEBUG 1594510Speter if ( debug & AOUTDEBUG ) { 1604510Speter register int j; 1614510Speter 1624510Speter for (j = 0; j < nname; j++){ 1634510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1644510Speter } 1654510Speter } 1664510Speter # endif DEBUG 1674510Speter } 1684510Speter 1694510Speter getstrtab(nfile) 1704510Speter FILE *nfile; 1714510Speter { 1724510Speter 1734510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1744510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1757128Speter fprintf(stderr, "%s: %s: no string table (old format?)\n" , 1767128Speter whoami , a_outname ); 1774510Speter done(); 1784510Speter } 1794510Speter strtab = (char *)calloc(ssiz, 1); 1804510Speter if (strtab == NULL) { 1817128Speter fprintf(stderr, "%s: %s: no room for %d bytes of string table", 1827128Speter whoami , a_outname , ssiz); 1834510Speter done(); 1844510Speter } 1854510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1867128Speter fprintf(stderr, "%s: %s: error reading string table\n", 1877128Speter whoami , a_outname ); 1884510Speter done(); 1894510Speter } 1904510Speter } 1914510Speter 1924510Speter /* 1934510Speter * Read in symbol table 1944510Speter */ 1954510Speter getsymtab(nfile) 1964510Speter FILE *nfile; 1974510Speter { 1984510Speter register long i; 1994510Speter int askfor; 2004510Speter struct nlist nbuf; 2014510Speter 2024510Speter /* pass1 - count symbols */ 2034510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2044510Speter nname = 0; 2054510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2064510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2074845Speter if ( ! funcsymbol( &nbuf ) ) { 2084510Speter continue; 2094510Speter } 2104510Speter nname++; 2114510Speter } 2124510Speter if (nname == 0) { 2137128Speter fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 2144510Speter done(); 2154510Speter } 2167128Speter askfor = nname + 1; 2174510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 2184510Speter if (nl == 0) { 2197128Speter fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 2207128Speter whoami, askfor * sizeof(nltype) ); 2214510Speter done(); 2224510Speter } 2234510Speter 2244510Speter /* pass2 - read symbols */ 2254510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2264510Speter npe = nl; 2274510Speter nname = 0; 2284510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2294510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2304845Speter if ( ! funcsymbol( &nbuf ) ) { 2314845Speter # ifdef DEBUG 2324845Speter if ( debug & AOUTDEBUG ) { 2334845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 2344845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 2354845Speter } 2364845Speter # endif DEBUG 2374510Speter continue; 2384510Speter } 2394510Speter npe->value = nbuf.n_value; 2404510Speter npe->name = strtab+nbuf.n_un.n_strx; 2414510Speter # ifdef DEBUG 2424510Speter if ( debug & AOUTDEBUG ) { 2434510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2444510Speter nname , npe -> name , npe -> value ); 2454510Speter } 2464510Speter # endif DEBUG 2474510Speter npe++; 2484510Speter nname++; 2494510Speter } 2504510Speter npe->value = -1; 2514510Speter npe++; 2524510Speter } 2534510Speter 2544510Speter /* 2554720Speter * read in the text space of an a.out file 2564720Speter */ 2574720Speter gettextspace( nfile ) 2584720Speter FILE *nfile; 2594720Speter { 2604720Speter unsigned char *malloc(); 2614720Speter 2624720Speter if ( cflag == 0 ) { 2634720Speter return; 2644720Speter } 2654720Speter textspace = malloc( xbuf.a_text ); 2664720Speter if ( textspace == 0 ) { 2677128Speter fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 2687128Speter whoami , xbuf.a_text ); 2697128Speter fprintf( stderr , "can't do -c\n" ); 2704720Speter return; 2714720Speter } 2724720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2734720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2747128Speter fprintf( stderr , "%s: couldn't read text space: " , whoami ); 2757128Speter fprintf( stderr , "can't do -c\n" ); 2764720Speter free( textspace ); 2774720Speter textspace = 0; 2784720Speter return; 2794720Speter } 2804720Speter } 2814720Speter /* 2824563Speter * information from a gmon.out file is in two parts: 2834510Speter * an array of sampling hits within pc ranges, 2844510Speter * and the arcs. 2854510Speter */ 2864510Speter getpfile(filename) 2874510Speter char *filename; 2884510Speter { 2894510Speter FILE *pfile; 2904510Speter FILE *openpfile(); 2914510Speter struct rawarc arc; 2924510Speter 2934510Speter pfile = openpfile(filename); 2944510Speter readsamples(pfile); 2954510Speter /* 2964510Speter * the rest of the file consists of 2974510Speter * a bunch of <from,self,count> tuples. 2984510Speter */ 2994510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 3004510Speter # ifdef DEBUG 3014510Speter if ( debug & SAMPLEDEBUG ) { 3024752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 3034510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3044510Speter } 3054510Speter # endif DEBUG 3064510Speter /* 3074510Speter * add this arc 3084510Speter */ 3094510Speter tally( &arc ); 3104510Speter } 3114510Speter fclose(pfile); 3124510Speter } 3134510Speter 3144841Speter FILE * 3154841Speter openpfile(filename) 3164510Speter char *filename; 3174510Speter { 3184866Smckusic struct hdr tmp; 3194510Speter FILE *pfile; 3204510Speter 3214510Speter if((pfile = fopen(filename, "r")) == NULL) { 3224510Speter perror(filename); 3234510Speter done(); 3244510Speter } 3254866Smckusic fread(&tmp, sizeof(struct hdr), 1, pfile); 3264866Smckusic if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc || 3274866Smckusic tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) { 3284866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 3294866Smckusic done(); 3304866Smckusic } 3314866Smckusic h = tmp; 3324752Speter s_lowpc = (unsigned long) h.lowpc; 3334752Speter s_highpc = (unsigned long) h.highpc; 3347227Smckusick lowpc = (unsigned long)h.lowpc / sizeof(UNIT); 3357227Smckusick highpc = (unsigned long)h.highpc / sizeof(UNIT); 3364510Speter sampbytes = h.ncnt - sizeof(struct hdr); 3374510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 3387226Speter # ifdef DEBUG 3397226Speter if ( debug & SAMPLEDEBUG ) { 3407226Speter printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n", 3417226Speter h.lowpc , h.highpc , h.ncnt ); 3427226Speter printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 3437226Speter s_lowpc , s_highpc ); 3447226Speter printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 3457226Speter lowpc , highpc ); 3467226Speter printf( "[openpfile] sampbytes %d nsamples %d\n" , 3477226Speter sampbytes , nsamples ); 3487226Speter } 3497226Speter # endif DEBUG 3504510Speter return(pfile); 3514510Speter } 3524510Speter 3534510Speter tally( rawp ) 3544510Speter struct rawarc *rawp; 3554510Speter { 3564510Speter nltype *parentp; 3574510Speter nltype *childp; 3584510Speter 3594510Speter parentp = nllookup( rawp -> raw_frompc ); 3604510Speter childp = nllookup( rawp -> raw_selfpc ); 3614510Speter childp -> ncall += rawp -> raw_count; 3624510Speter # ifdef DEBUG 3634510Speter if ( debug & TALLYDEBUG ) { 3644510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3654510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3664510Speter } 3674510Speter # endif DEBUG 3684720Speter addarc( parentp , childp , rawp -> raw_count ); 3694510Speter } 3704510Speter 3714866Smckusic /* 3724866Smckusic * dump out the gmon.sum file 3734866Smckusic */ 3744866Smckusic dumpsum( sumfile ) 3754866Smckusic char *sumfile; 3764866Smckusic { 3774866Smckusic register nltype *nlp; 3784866Smckusic register arctype *arcp; 3794866Smckusic struct rawarc arc; 3804866Smckusic FILE *sfile; 3814866Smckusic 3824866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3834866Smckusic perror( sumfile ); 3844866Smckusic done(); 3854866Smckusic } 3864866Smckusic /* 3874866Smckusic * dump the header; use the last header read in 3884866Smckusic */ 3894866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 3904866Smckusic perror( sumfile ); 3914866Smckusic done(); 3924866Smckusic } 3934866Smckusic /* 3944866Smckusic * dump the samples 3954866Smckusic */ 3964866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 3974866Smckusic perror( sumfile ); 3984866Smckusic done(); 3994866Smckusic } 4004866Smckusic /* 4014866Smckusic * dump the normalized raw arc information 4024866Smckusic */ 4034866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 4044866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 4054866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 4064866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 4074866Smckusic arc.raw_count = arcp -> arc_count; 4084866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 4094866Smckusic perror( sumfile ); 4104866Smckusic done(); 4114866Smckusic } 4124866Smckusic # ifdef DEBUG 4134866Smckusic if ( debug & SAMPLEDEBUG ) { 4144866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 4154866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4164866Smckusic } 4174866Smckusic # endif DEBUG 4184866Smckusic } 4194866Smckusic } 4204866Smckusic fclose( sfile ); 4214866Smckusic } 4224866Smckusic 4234510Speter valcmp(p1, p2) 4244510Speter nltype *p1, *p2; 4254510Speter { 4264510Speter if ( p1 -> value < p2 -> value ) { 4274510Speter return LESSTHAN; 4284510Speter } 4294510Speter if ( p1 -> value > p2 -> value ) { 4304510Speter return GREATERTHAN; 4314510Speter } 4324510Speter return EQUALTO; 4334510Speter } 4344510Speter 4354510Speter readsamples(pfile) 4364510Speter FILE *pfile; 4374510Speter { 4384510Speter register i; 4394510Speter unsigned UNIT sample; 4404510Speter 4414510Speter if (samples == 0) { 4424510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 4434510Speter if (samples == 0) { 4447128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 4457128Speter whoami , sampbytes / sizeof (unsigned UNIT)); 4464510Speter done(); 4474510Speter } 4484510Speter } 4494510Speter for (i = 0; i < nsamples; i++) { 4504510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 4514510Speter if (feof(pfile)) 4524510Speter break; 4534510Speter samples[i] += sample; 4544510Speter } 4554510Speter if (i != nsamples) { 4564510Speter fprintf(stderr, 4577128Speter "%s: unexpected EOF after reading %d/%d samples\n", 4587128Speter whoami , --i , nsamples ); 4594510Speter done(); 4604510Speter } 4614510Speter } 4624510Speter 4634510Speter /* 4644510Speter * Assign samples to the procedures to which they belong. 4654510Speter */ 4664510Speter asgnsamples() 4674510Speter { 4684510Speter register int j; 4694510Speter unsigned UNIT ccnt; 4704510Speter double time; 4714510Speter unsigned long pcl, pch; 4724510Speter register int i; 4734841Speter unsigned long overlap; 4744510Speter unsigned long svalue0, svalue1; 4754510Speter 4764510Speter /* read samples and assign to namelist symbols */ 4774510Speter scale = highpc - lowpc; 4784510Speter scale /= nsamples; 4797257Smckusick for (i = 0, j = 1; i < nsamples; i++) { 4804510Speter ccnt = samples[i]; 4814510Speter if (ccnt == 0) 4824510Speter continue; 4834510Speter pcl = lowpc + scale*i; 4844510Speter pch = lowpc + scale*(i+1); 4854510Speter time = ccnt; 4864510Speter # ifdef DEBUG 4874510Speter if ( debug & SAMPLEDEBUG ) { 4885072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4895072Smckusic pcl , pch , ccnt ); 4904510Speter } 4914510Speter # endif DEBUG 4924510Speter totime += time; 4937252Smckusick for (j = j - 1; j < nname; j++) { 4944510Speter svalue0 = nl[j].value / sizeof(UNIT); 4954510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4964510Speter if (pch < svalue0) 4974510Speter break; 4984510Speter if (pcl >= svalue1) 4994510Speter continue; 5004510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 5014510Speter if (overlap>0) { 5024510Speter # ifdef DEBUG 5034510Speter if ( debug & SAMPLEDEBUG ) { 5045072Smckusic printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" , 5055072Smckusic svalue0 , svalue1 , nl[j].name , 5065072Smckusic overlap*time/scale ); 5074510Speter } 5084510Speter # endif DEBUG 5094510Speter nl[j].time += overlap*time/scale; 5104510Speter } 5114510Speter } 5124510Speter } 5134510Speter # ifdef DEBUG 5144510Speter if ( debug & SAMPLEDEBUG ) { 5154510Speter printf( "[asgnsamples] totime %f\n" , totime ); 5164510Speter } 5174510Speter # endif DEBUG 5184510Speter } 5194510Speter 5204510Speter 5214841Speter unsigned long 5224510Speter min(a, b) 5234841Speter unsigned long a,b; 5244510Speter { 5254510Speter if (a<b) 5264510Speter return(a); 5274510Speter return(b); 5284510Speter } 5294510Speter 5304841Speter unsigned long 5314510Speter max(a, b) 5324841Speter unsigned long a,b; 5334510Speter { 5344510Speter if (a>b) 5354510Speter return(a); 5364510Speter return(b); 5374510Speter } 5384510Speter 5394845Speter bool 5404845Speter funcsymbol( nlistp ) 5414845Speter struct nlist *nlistp; 5424845Speter { 5434845Speter extern char *strtab; /* string table from a.out */ 5444851Speter extern int aflag; /* if static functions aren't desired */ 5454845Speter char *name; 5464845Speter 5474845Speter /* 5484845Speter * must be a text symbol, 5494851Speter * and static text symbols don't qualify if aflag set. 5504845Speter */ 5514845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5524851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5534845Speter return FALSE; 5544845Speter } 5554845Speter /* 5567128Speter * can't have any `funny' characters in name, 5574845Speter * where `funny' includes `.', .o file names 5584845Speter * and `$', pascal labels. 5594845Speter */ 5604845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5614845Speter if ( *name == '.' || *name == '$' ) { 5624845Speter return FALSE; 5634845Speter } 5644845Speter } 5654845Speter return TRUE; 5664845Speter } 5674845Speter 5684510Speter done() 5694510Speter { 5704510Speter 5714510Speter exit(0); 5724510Speter } 573