14510Speter #ifndef lint 2*7173Speter static char *sccsid = "@(#)gprof.c 1.12 (Berkeley) 06/14/82"; 34510Speter #endif lint 44510Speter 54563Speter #include "gprof.h" 64510Speter 77128Speter char *whoami = "gprof"; 87128Speter 9*7173Speter char *defaultes[] = { "mcount" , "__mcleanup" , 0 }; 10*7173Speter 114510Speter main(argc, argv) 12*7173Speter int argc; 13*7173Speter char **argv; 144510Speter { 15*7173Speter char **sp; 164510Speter 174510Speter --argc; 184510Speter argv++; 194510Speter debug = 0; 204510Speter while ( *argv != 0 && **argv == '-' ) { 214510Speter (*argv)++; 224866Smckusic switch ( **argv ) { 23*7173Speter case 'a': 24*7173Speter aflag = TRUE; 25*7173Speter break; 26*7173Speter case 'b': 27*7173Speter bflag = TRUE; 28*7173Speter break; 29*7173Speter case 'c': 30*7173Speter cflag = TRUE; 31*7173Speter break; 324866Smckusic case 'd': 33*7173Speter dflag = TRUE; 344510Speter (*argv)++; 354510Speter debug |= atoi( *argv ); 364510Speter debug |= ANYDEBUG; 374510Speter # ifdef DEBUG 384510Speter printf( "[main] debug = %d\n" , debug ); 394510Speter # endif DEBUG 404866Smckusic break; 41*7173Speter case 'e': 42*7173Speter eflag = TRUE; 43*7173Speter addelist( *++argv ); 444866Smckusic break; 45*7173Speter case 'f': 46*7173Speter fflag = TRUE; 47*7173Speter addflist( *++argv ); 484866Smckusic break; 494866Smckusic case 's': 50*7173Speter sflag = TRUE; 514866Smckusic break; 524866Smckusic case 'z': 53*7173Speter zflag = TRUE; 544866Smckusic break; 554510Speter } 564510Speter argv++; 574510Speter } 584510Speter if ( *argv != 0 ) { 594510Speter a_outname = *argv; 604510Speter argv++; 614510Speter } else { 624510Speter a_outname = A_OUTNAME; 634510Speter } 644510Speter if ( *argv != 0 ) { 654563Speter gmonname = *argv; 664510Speter argv++; 674510Speter } else { 684563Speter gmonname = GMONNAME; 694510Speter } 704510Speter /* 71*7173Speter * turn off default functions 72*7173Speter */ 73*7173Speter for ( sp = &defaultes[0] ; *sp ; sp++ ) { 74*7173Speter eflag = TRUE; 75*7173Speter addelist( *sp ); 76*7173Speter } 77*7173Speter /* 784510Speter * get information about a.out file. 794510Speter */ 804510Speter getnfile(); 814510Speter /* 824510Speter * get information about mon.out file(s). 834510Speter */ 844866Smckusic do { 854866Smckusic getpfile( gmonname ); 864866Smckusic if ( *argv != 0 ) { 874866Smckusic gmonname = *argv; 884866Smckusic } 897128Speter } while ( *argv++ != 0 ); 904510Speter /* 914866Smckusic * dump out a gmon.sum file if requested 924866Smckusic */ 937128Speter if ( sflag ) { 947128Speter dumpsum( GMONSUM ); 957128Speter } 964866Smckusic /* 974510Speter * assign samples to procedures 984510Speter */ 994510Speter asgnsamples(); 1004510Speter /* 1014510Speter * print the usual profile 1024510Speter */ 1034510Speter printprof(); 1044510Speter /* 1054510Speter * assemble and print the dynamic profile 1064510Speter */ 1074510Speter doarcs(); 1084510Speter done(); 1094510Speter } 1104510Speter 1117128Speter /* 1127128Speter * Set up string and symbol tables from a.out. 1137128Speter * and optionally the text space. 1147128Speter * On return symbol table is sorted by value. 1157128Speter */ 1164510Speter getnfile() 1174510Speter { 1184510Speter FILE *nfile; 1194510Speter 1204510Speter nfile = fopen( a_outname ,"r"); 1214510Speter if (nfile == NULL) { 1224510Speter perror( a_outname ); 1234510Speter done(); 1244510Speter } 1254510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1264510Speter if (N_BADMAG(xbuf)) { 1277128Speter fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 1284510Speter done(); 1294510Speter } 1304510Speter getstrtab(nfile); 1314510Speter getsymtab(nfile); 1324720Speter gettextspace( nfile ); 1334510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1344510Speter fclose(nfile); 1354510Speter # ifdef DEBUG 1364510Speter if ( debug & AOUTDEBUG ) { 1374510Speter register int j; 1384510Speter 1394510Speter for (j = 0; j < nname; j++){ 1404510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1414510Speter } 1424510Speter } 1434510Speter # endif DEBUG 1444510Speter } 1454510Speter 1464510Speter getstrtab(nfile) 1474510Speter FILE *nfile; 1484510Speter { 1494510Speter 1504510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1514510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1527128Speter fprintf(stderr, "%s: %s: no string table (old format?)\n" , 1537128Speter whoami , a_outname ); 1544510Speter done(); 1554510Speter } 1564510Speter strtab = (char *)calloc(ssiz, 1); 1574510Speter if (strtab == NULL) { 1587128Speter fprintf(stderr, "%s: %s: no room for %d bytes of string table", 1597128Speter whoami , a_outname , ssiz); 1604510Speter done(); 1614510Speter } 1624510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1637128Speter fprintf(stderr, "%s: %s: error reading string table\n", 1647128Speter whoami , a_outname ); 1654510Speter done(); 1664510Speter } 1674510Speter } 1684510Speter 1694510Speter /* 1704510Speter * Read in symbol table 1714510Speter */ 1724510Speter getsymtab(nfile) 1734510Speter FILE *nfile; 1744510Speter { 1754510Speter register long i; 1764510Speter int askfor; 1774510Speter struct nlist nbuf; 1784510Speter 1794510Speter /* pass1 - count symbols */ 1804510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1814510Speter nname = 0; 1824510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1834510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1844845Speter if ( ! funcsymbol( &nbuf ) ) { 1854510Speter continue; 1864510Speter } 1874510Speter nname++; 1884510Speter } 1894510Speter if (nname == 0) { 1907128Speter fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 1914510Speter done(); 1924510Speter } 1937128Speter askfor = nname + 1; 1944510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 1954510Speter if (nl == 0) { 1967128Speter fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 1977128Speter whoami, askfor * sizeof(nltype) ); 1984510Speter done(); 1994510Speter } 2004510Speter 2014510Speter /* pass2 - read symbols */ 2024510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2034510Speter npe = nl; 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 ) ) { 2084845Speter # ifdef DEBUG 2094845Speter if ( debug & AOUTDEBUG ) { 2104845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 2114845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 2124845Speter } 2134845Speter # endif DEBUG 2144510Speter continue; 2154510Speter } 2164510Speter npe->value = nbuf.n_value; 2174510Speter npe->name = strtab+nbuf.n_un.n_strx; 2184510Speter # ifdef DEBUG 2194510Speter if ( debug & AOUTDEBUG ) { 2204510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2214510Speter nname , npe -> name , npe -> value ); 2224510Speter } 2234510Speter # endif DEBUG 2244510Speter npe++; 2254510Speter nname++; 2264510Speter } 2274510Speter npe->value = -1; 2284510Speter npe++; 2294510Speter } 2304510Speter 2314510Speter /* 2324720Speter * read in the text space of an a.out file 2334720Speter */ 2344720Speter gettextspace( nfile ) 2354720Speter FILE *nfile; 2364720Speter { 2374720Speter unsigned char *malloc(); 2384720Speter 2394720Speter if ( cflag == 0 ) { 2404720Speter return; 2414720Speter } 2424720Speter textspace = malloc( xbuf.a_text ); 2434720Speter if ( textspace == 0 ) { 2447128Speter fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 2457128Speter whoami , xbuf.a_text ); 2467128Speter fprintf( stderr , "can't do -c\n" ); 2474720Speter return; 2484720Speter } 2494720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2504720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2517128Speter fprintf( stderr , "%s: couldn't read text space: " , whoami ); 2527128Speter fprintf( stderr , "can't do -c\n" ); 2534720Speter free( textspace ); 2544720Speter textspace = 0; 2554720Speter return; 2564720Speter } 2574720Speter } 2584720Speter /* 2594563Speter * information from a gmon.out file is in two parts: 2604510Speter * an array of sampling hits within pc ranges, 2614510Speter * and the arcs. 2624510Speter */ 2634510Speter getpfile(filename) 2644510Speter char *filename; 2654510Speter { 2664510Speter FILE *pfile; 2674510Speter FILE *openpfile(); 2684510Speter struct rawarc arc; 2694510Speter 2704510Speter pfile = openpfile(filename); 2714510Speter readsamples(pfile); 2724510Speter /* 2734510Speter * the rest of the file consists of 2744510Speter * a bunch of <from,self,count> tuples. 2754510Speter */ 2764510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2774510Speter # ifdef DEBUG 2784510Speter if ( debug & SAMPLEDEBUG ) { 2794752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2804510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2814510Speter } 2824510Speter # endif DEBUG 2834510Speter /* 2844510Speter * add this arc 2854510Speter */ 2864510Speter tally( &arc ); 2874510Speter } 2884510Speter fclose(pfile); 2894510Speter } 2904510Speter 2914841Speter FILE * 2924841Speter openpfile(filename) 2934510Speter char *filename; 2944510Speter { 2954866Smckusic struct hdr tmp; 2964510Speter FILE *pfile; 2974510Speter 2984510Speter if((pfile = fopen(filename, "r")) == NULL) { 2994510Speter perror(filename); 3004510Speter done(); 3014510Speter } 3024866Smckusic fread(&tmp, sizeof(struct hdr), 1, pfile); 3034866Smckusic if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc || 3044866Smckusic tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) { 3054866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 3064866Smckusic done(); 3074866Smckusic } 3084866Smckusic h = tmp; 3094752Speter s_lowpc = (unsigned long) h.lowpc; 3104752Speter s_highpc = (unsigned long) h.highpc; 3114510Speter lowpc = h.lowpc - (UNIT *)0; 3124510Speter highpc = h.highpc - (UNIT *)0; 3134510Speter sampbytes = h.ncnt - sizeof(struct hdr); 3144510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 3154510Speter return(pfile); 3164510Speter } 3174510Speter 3184510Speter tally( rawp ) 3194510Speter struct rawarc *rawp; 3204510Speter { 3214510Speter nltype *parentp; 3224510Speter nltype *childp; 3234510Speter 3244510Speter parentp = nllookup( rawp -> raw_frompc ); 3254510Speter childp = nllookup( rawp -> raw_selfpc ); 3264510Speter childp -> ncall += rawp -> raw_count; 3274510Speter # ifdef DEBUG 3284510Speter if ( debug & TALLYDEBUG ) { 3294510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3304510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3314510Speter } 3324510Speter # endif DEBUG 3334720Speter addarc( parentp , childp , rawp -> raw_count ); 3344510Speter } 3354510Speter 3364866Smckusic /* 3374866Smckusic * dump out the gmon.sum file 3384866Smckusic */ 3394866Smckusic dumpsum( sumfile ) 3404866Smckusic char *sumfile; 3414866Smckusic { 3424866Smckusic register nltype *nlp; 3434866Smckusic register arctype *arcp; 3444866Smckusic struct rawarc arc; 3454866Smckusic FILE *sfile; 3464866Smckusic 3474866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3484866Smckusic perror( sumfile ); 3494866Smckusic done(); 3504866Smckusic } 3514866Smckusic /* 3524866Smckusic * dump the header; use the last header read in 3534866Smckusic */ 3544866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 3554866Smckusic perror( sumfile ); 3564866Smckusic done(); 3574866Smckusic } 3584866Smckusic /* 3594866Smckusic * dump the samples 3604866Smckusic */ 3614866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 3624866Smckusic perror( sumfile ); 3634866Smckusic done(); 3644866Smckusic } 3654866Smckusic /* 3664866Smckusic * dump the normalized raw arc information 3674866Smckusic */ 3684866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 3694866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3704866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 3714866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 3724866Smckusic arc.raw_count = arcp -> arc_count; 3734866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3744866Smckusic perror( sumfile ); 3754866Smckusic done(); 3764866Smckusic } 3774866Smckusic # ifdef DEBUG 3784866Smckusic if ( debug & SAMPLEDEBUG ) { 3794866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 3804866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3814866Smckusic } 3824866Smckusic # endif DEBUG 3834866Smckusic } 3844866Smckusic } 3854866Smckusic fclose( sfile ); 3864866Smckusic } 3874866Smckusic 3884510Speter valcmp(p1, p2) 3894510Speter nltype *p1, *p2; 3904510Speter { 3914510Speter if ( p1 -> value < p2 -> value ) { 3924510Speter return LESSTHAN; 3934510Speter } 3944510Speter if ( p1 -> value > p2 -> value ) { 3954510Speter return GREATERTHAN; 3964510Speter } 3974510Speter return EQUALTO; 3984510Speter } 3994510Speter 4004510Speter readsamples(pfile) 4014510Speter FILE *pfile; 4024510Speter { 4034510Speter register i; 4044510Speter unsigned UNIT sample; 4054510Speter 4064510Speter if (samples == 0) { 4074510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 4084510Speter if (samples == 0) { 4097128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 4107128Speter whoami , sampbytes / sizeof (unsigned UNIT)); 4114510Speter done(); 4124510Speter } 4134510Speter } 4144510Speter for (i = 0; i < nsamples; i++) { 4154510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 4164510Speter if (feof(pfile)) 4174510Speter break; 4184510Speter samples[i] += sample; 4194510Speter } 4204510Speter if (i != nsamples) { 4214510Speter fprintf(stderr, 4227128Speter "%s: unexpected EOF after reading %d/%d samples\n", 4237128Speter whoami , --i , nsamples ); 4244510Speter done(); 4254510Speter } 4264510Speter } 4274510Speter 4284510Speter /* 4294510Speter * Assign samples to the procedures to which they belong. 4304510Speter */ 4314510Speter asgnsamples() 4324510Speter { 4334510Speter register int j; 4344510Speter unsigned UNIT ccnt; 4354510Speter double time; 4364510Speter unsigned long pcl, pch; 4374510Speter register int i; 4384841Speter unsigned long overlap; 4394510Speter unsigned long svalue0, svalue1; 4404510Speter 4414510Speter /* read samples and assign to namelist symbols */ 4424510Speter scale = highpc - lowpc; 4434510Speter scale /= nsamples; 4444510Speter for (i=0; i < nsamples; i++) { 4454510Speter ccnt = samples[i]; 4464510Speter if (ccnt == 0) 4474510Speter continue; 4484510Speter pcl = lowpc + scale*i; 4494510Speter pch = lowpc + scale*(i+1); 4504510Speter time = ccnt; 4514510Speter # ifdef DEBUG 4524510Speter if ( debug & SAMPLEDEBUG ) { 4535072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4545072Smckusic pcl , pch , ccnt ); 4554510Speter } 4564510Speter # endif DEBUG 4574510Speter totime += time; 4584510Speter for (j=0; j<nname; j++) { 4594510Speter svalue0 = nl[j].value / sizeof(UNIT); 4604510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4614510Speter if (pch < svalue0) 4624510Speter break; 4634510Speter if (pcl >= svalue1) 4644510Speter continue; 4654510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4664510Speter if (overlap>0) { 4674510Speter # ifdef DEBUG 4684510Speter if ( debug & SAMPLEDEBUG ) { 4695072Smckusic printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" , 4705072Smckusic svalue0 , svalue1 , nl[j].name , 4715072Smckusic overlap*time/scale ); 4724510Speter } 4734510Speter # endif DEBUG 4744510Speter nl[j].time += overlap*time/scale; 4754510Speter } 4764510Speter } 4774510Speter } 4784510Speter # ifdef DEBUG 4794510Speter if ( debug & SAMPLEDEBUG ) { 4804510Speter printf( "[asgnsamples] totime %f\n" , totime ); 4814510Speter } 4824510Speter # endif DEBUG 4834510Speter if (totime==0.0) { 4844510Speter fprintf( stderr , "No time accumulated\n" ); 4854510Speter totime=1.0; 4864510Speter } 4874510Speter } 4884510Speter 4894510Speter 4904841Speter unsigned long 4914510Speter min(a, b) 4924841Speter unsigned long a,b; 4934510Speter { 4944510Speter if (a<b) 4954510Speter return(a); 4964510Speter return(b); 4974510Speter } 4984510Speter 4994841Speter unsigned long 5004510Speter max(a, b) 5014841Speter unsigned long a,b; 5024510Speter { 5034510Speter if (a>b) 5044510Speter return(a); 5054510Speter return(b); 5064510Speter } 5074510Speter 5084845Speter bool 5094845Speter funcsymbol( nlistp ) 5104845Speter struct nlist *nlistp; 5114845Speter { 5124845Speter extern char *strtab; /* string table from a.out */ 5134851Speter extern int aflag; /* if static functions aren't desired */ 5144845Speter char *name; 5154845Speter 5164845Speter /* 5174845Speter * must be a text symbol, 5184851Speter * and static text symbols don't qualify if aflag set. 5194845Speter */ 5204845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5214851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5224845Speter return FALSE; 5234845Speter } 5244845Speter /* 5257128Speter * can't have any `funny' characters in name, 5264845Speter * where `funny' includes `.', .o file names 5274845Speter * and `$', pascal labels. 5284845Speter */ 5294845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5304845Speter if ( *name == '.' || *name == '$' ) { 5314845Speter return FALSE; 5324845Speter } 5334845Speter } 5344845Speter return TRUE; 5354845Speter } 5364845Speter 5374510Speter done() 5384510Speter { 5394510Speter 5404510Speter exit(0); 5414510Speter } 542