14510Speter #ifndef lint 2*7223Speter static char *sccsid = "@(#)gprof.c 1.13 (Berkeley) 06/18/82"; 34510Speter #endif lint 44510Speter 54563Speter #include "gprof.h" 64510Speter 77128Speter char *whoami = "gprof"; 87128Speter 9*7223Speter /* 10*7223Speter * things which get -E excluded by default. 11*7223Speter */ 12*7223Speter 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; 44*7223Speter case 'E': 45*7223Speter ++argv; 46*7223Speter addlist( Elist , *argv ); 47*7223Speter Eflag = TRUE; 48*7223Speter addlist( elist , *argv ); 49*7223Speter eflag = TRUE; 50*7223Speter break; 517173Speter case 'e': 52*7223Speter addlist( elist , *++argv ); 537173Speter eflag = TRUE; 544866Smckusic break; 55*7223Speter case 'F': 56*7223Speter ++argv; 57*7223Speter addlist( Flist , *argv ); 58*7223Speter Fflag = TRUE; 59*7223Speter addlist( flist , *argv ); 60*7223Speter fflag = TRUE; 61*7223Speter break; 627173Speter case 'f': 63*7223Speter 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 */ 90*7223Speter for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 91*7223Speter Eflag = TRUE; 92*7223Speter addlist( Elist , *sp ); 937173Speter eflag = TRUE; 94*7223Speter 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; 3304510Speter lowpc = h.lowpc - (UNIT *)0; 3314510Speter highpc = h.highpc - (UNIT *)0; 3324510Speter sampbytes = h.ncnt - sizeof(struct hdr); 3334510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 3344510Speter return(pfile); 3354510Speter } 3364510Speter 3374510Speter tally( rawp ) 3384510Speter struct rawarc *rawp; 3394510Speter { 3404510Speter nltype *parentp; 3414510Speter nltype *childp; 3424510Speter 3434510Speter parentp = nllookup( rawp -> raw_frompc ); 3444510Speter childp = nllookup( rawp -> raw_selfpc ); 3454510Speter childp -> ncall += rawp -> raw_count; 3464510Speter # ifdef DEBUG 3474510Speter if ( debug & TALLYDEBUG ) { 3484510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3494510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3504510Speter } 3514510Speter # endif DEBUG 3524720Speter addarc( parentp , childp , rawp -> raw_count ); 3534510Speter } 3544510Speter 3554866Smckusic /* 3564866Smckusic * dump out the gmon.sum file 3574866Smckusic */ 3584866Smckusic dumpsum( sumfile ) 3594866Smckusic char *sumfile; 3604866Smckusic { 3614866Smckusic register nltype *nlp; 3624866Smckusic register arctype *arcp; 3634866Smckusic struct rawarc arc; 3644866Smckusic FILE *sfile; 3654866Smckusic 3664866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3674866Smckusic perror( sumfile ); 3684866Smckusic done(); 3694866Smckusic } 3704866Smckusic /* 3714866Smckusic * dump the header; use the last header read in 3724866Smckusic */ 3734866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 3744866Smckusic perror( sumfile ); 3754866Smckusic done(); 3764866Smckusic } 3774866Smckusic /* 3784866Smckusic * dump the samples 3794866Smckusic */ 3804866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 3814866Smckusic perror( sumfile ); 3824866Smckusic done(); 3834866Smckusic } 3844866Smckusic /* 3854866Smckusic * dump the normalized raw arc information 3864866Smckusic */ 3874866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 3884866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3894866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 3904866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 3914866Smckusic arc.raw_count = arcp -> arc_count; 3924866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3934866Smckusic perror( sumfile ); 3944866Smckusic done(); 3954866Smckusic } 3964866Smckusic # ifdef DEBUG 3974866Smckusic if ( debug & SAMPLEDEBUG ) { 3984866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 3994866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4004866Smckusic } 4014866Smckusic # endif DEBUG 4024866Smckusic } 4034866Smckusic } 4044866Smckusic fclose( sfile ); 4054866Smckusic } 4064866Smckusic 4074510Speter valcmp(p1, p2) 4084510Speter nltype *p1, *p2; 4094510Speter { 4104510Speter if ( p1 -> value < p2 -> value ) { 4114510Speter return LESSTHAN; 4124510Speter } 4134510Speter if ( p1 -> value > p2 -> value ) { 4144510Speter return GREATERTHAN; 4154510Speter } 4164510Speter return EQUALTO; 4174510Speter } 4184510Speter 4194510Speter readsamples(pfile) 4204510Speter FILE *pfile; 4214510Speter { 4224510Speter register i; 4234510Speter unsigned UNIT sample; 4244510Speter 4254510Speter if (samples == 0) { 4264510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 4274510Speter if (samples == 0) { 4287128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 4297128Speter whoami , sampbytes / sizeof (unsigned UNIT)); 4304510Speter done(); 4314510Speter } 4324510Speter } 4334510Speter for (i = 0; i < nsamples; i++) { 4344510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 4354510Speter if (feof(pfile)) 4364510Speter break; 4374510Speter samples[i] += sample; 4384510Speter } 4394510Speter if (i != nsamples) { 4404510Speter fprintf(stderr, 4417128Speter "%s: unexpected EOF after reading %d/%d samples\n", 4427128Speter whoami , --i , nsamples ); 4434510Speter done(); 4444510Speter } 4454510Speter } 4464510Speter 4474510Speter /* 4484510Speter * Assign samples to the procedures to which they belong. 4494510Speter */ 4504510Speter asgnsamples() 4514510Speter { 4524510Speter register int j; 4534510Speter unsigned UNIT ccnt; 4544510Speter double time; 4554510Speter unsigned long pcl, pch; 4564510Speter register int i; 4574841Speter unsigned long overlap; 4584510Speter unsigned long svalue0, svalue1; 4594510Speter 4604510Speter /* read samples and assign to namelist symbols */ 4614510Speter scale = highpc - lowpc; 4624510Speter scale /= nsamples; 4634510Speter for (i=0; i < nsamples; i++) { 4644510Speter ccnt = samples[i]; 4654510Speter if (ccnt == 0) 4664510Speter continue; 4674510Speter pcl = lowpc + scale*i; 4684510Speter pch = lowpc + scale*(i+1); 4694510Speter time = ccnt; 4704510Speter # ifdef DEBUG 4714510Speter if ( debug & SAMPLEDEBUG ) { 4725072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4735072Smckusic pcl , pch , ccnt ); 4744510Speter } 4754510Speter # endif DEBUG 4764510Speter totime += time; 4774510Speter for (j=0; j<nname; j++) { 4784510Speter svalue0 = nl[j].value / sizeof(UNIT); 4794510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4804510Speter if (pch < svalue0) 4814510Speter break; 4824510Speter if (pcl >= svalue1) 4834510Speter continue; 4844510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4854510Speter if (overlap>0) { 4864510Speter # ifdef DEBUG 4874510Speter if ( debug & SAMPLEDEBUG ) { 4885072Smckusic printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" , 4895072Smckusic svalue0 , svalue1 , nl[j].name , 4905072Smckusic overlap*time/scale ); 4914510Speter } 4924510Speter # endif DEBUG 4934510Speter nl[j].time += overlap*time/scale; 4944510Speter } 4954510Speter } 4964510Speter } 4974510Speter # ifdef DEBUG 4984510Speter if ( debug & SAMPLEDEBUG ) { 4994510Speter printf( "[asgnsamples] totime %f\n" , totime ); 5004510Speter } 5014510Speter # endif DEBUG 5024510Speter if (totime==0.0) { 5034510Speter fprintf( stderr , "No time accumulated\n" ); 5044510Speter totime=1.0; 5054510Speter } 5064510Speter } 5074510Speter 5084510Speter 5094841Speter unsigned long 5104510Speter min(a, b) 5114841Speter unsigned long a,b; 5124510Speter { 5134510Speter if (a<b) 5144510Speter return(a); 5154510Speter return(b); 5164510Speter } 5174510Speter 5184841Speter unsigned long 5194510Speter max(a, b) 5204841Speter unsigned long a,b; 5214510Speter { 5224510Speter if (a>b) 5234510Speter return(a); 5244510Speter return(b); 5254510Speter } 5264510Speter 5274845Speter bool 5284845Speter funcsymbol( nlistp ) 5294845Speter struct nlist *nlistp; 5304845Speter { 5314845Speter extern char *strtab; /* string table from a.out */ 5324851Speter extern int aflag; /* if static functions aren't desired */ 5334845Speter char *name; 5344845Speter 5354845Speter /* 5364845Speter * must be a text symbol, 5374851Speter * and static text symbols don't qualify if aflag set. 5384845Speter */ 5394845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5404851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5414845Speter return FALSE; 5424845Speter } 5434845Speter /* 5447128Speter * can't have any `funny' characters in name, 5454845Speter * where `funny' includes `.', .o file names 5464845Speter * and `$', pascal labels. 5474845Speter */ 5484845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5494845Speter if ( *name == '.' || *name == '$' ) { 5504845Speter return FALSE; 5514845Speter } 5524845Speter } 5534845Speter return TRUE; 5544845Speter } 5554845Speter 5564510Speter done() 5574510Speter { 5584510Speter 5594510Speter exit(0); 5604510Speter } 561