14510Speter #ifndef lint 2*4866Smckusic static char *sccsid = "@(#)gprof.c 1.9 (Berkeley) 11/11/81"; 34510Speter #endif lint 44510Speter 54563Speter #include "gprof.h" 64510Speter 74510Speter main(argc, argv) 84510Speter int argc; 94510Speter char **argv; 104510Speter { 114510Speter 124510Speter --argc; 134510Speter argv++; 144510Speter debug = 0; 154510Speter while ( *argv != 0 && **argv == '-' ) { 164510Speter (*argv)++; 17*4866Smckusic switch ( **argv ) { 18*4866Smckusic case 'd': 194510Speter (*argv)++; 204510Speter debug |= atoi( *argv ); 214510Speter debug |= ANYDEBUG; 224510Speter # ifdef DEBUG 234510Speter printf( "[main] debug = %d\n" , debug ); 244510Speter # endif DEBUG 25*4866Smckusic break; 26*4866Smckusic case 'a': 274845Speter aflag++; 28*4866Smckusic break; 29*4866Smckusic case 'b': 304853Speter bflag++; 31*4866Smckusic break; 32*4866Smckusic case 'c': 334845Speter cflag++; 34*4866Smckusic break; 35*4866Smckusic case 's': 36*4866Smckusic sflag++; 37*4866Smckusic break; 38*4866Smckusic case 'z': 394853Speter zflag++; 40*4866Smckusic break; 414510Speter } 424510Speter argv++; 434510Speter } 444510Speter if ( *argv != 0 ) { 454510Speter a_outname = *argv; 464510Speter argv++; 474510Speter } else { 484510Speter a_outname = A_OUTNAME; 494510Speter } 504510Speter if ( *argv != 0 ) { 514563Speter gmonname = *argv; 524510Speter argv++; 534510Speter } else { 544563Speter gmonname = GMONNAME; 554510Speter } 564510Speter /* 574510Speter * get information about a.out file. 584510Speter */ 594510Speter getnfile(); 604510Speter /* 614510Speter * get information about mon.out file(s). 624510Speter */ 63*4866Smckusic do { 64*4866Smckusic getpfile( gmonname ); 65*4866Smckusic if ( *argv != 0 ) { 66*4866Smckusic gmonname = *argv; 67*4866Smckusic } 68*4866Smckusic } while ( sflag && *argv++ != 0 ); 694510Speter /* 70*4866Smckusic * dump out a gmon.sum file if requested 71*4866Smckusic */ 72*4866Smckusic if ( sflag ) { 73*4866Smckusic dumpsum( GMONSUM ); 74*4866Smckusic } 75*4866Smckusic /* 764510Speter * assign samples to procedures 774510Speter */ 784510Speter asgnsamples(); 794510Speter /* 804510Speter * print the usual profile 814510Speter */ 824510Speter printprof(); 834510Speter /* 844510Speter * assemble and print the dynamic profile 854510Speter */ 864510Speter doarcs(); 874510Speter done(); 884510Speter } 894510Speter 904510Speter /* 914510Speter * Set up string and symbol tables from a.out. 924720Speter * and optionally the text space. 934510Speter * On return symbol table is sorted by value. 944510Speter */ 954510Speter getnfile() 964510Speter { 974510Speter FILE *nfile; 984510Speter 994510Speter nfile = fopen( a_outname ,"r"); 1004510Speter if (nfile == NULL) { 1014510Speter perror( a_outname ); 1024510Speter done(); 1034510Speter } 1044510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1054510Speter if (N_BADMAG(xbuf)) { 1064510Speter fprintf(stderr, "%s: bad format\n", a_outname ); 1074510Speter done(); 1084510Speter } 1094510Speter getstrtab(nfile); 1104510Speter getsymtab(nfile); 1114720Speter gettextspace( nfile ); 1124510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1134510Speter fclose(nfile); 1144510Speter # ifdef DEBUG 1154510Speter if ( debug & AOUTDEBUG ) { 1164510Speter register int j; 1174510Speter 1184510Speter for (j = 0; j < nname; j++){ 1194510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1204510Speter } 1214510Speter } 1224510Speter # endif DEBUG 1234510Speter } 1244510Speter 1254510Speter getstrtab(nfile) 1264510Speter FILE *nfile; 1274510Speter { 1284510Speter 1294510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1304510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1314510Speter fprintf(stderr, "%s: no string table (old format?)\n", a_outname ); 1324510Speter done(); 1334510Speter } 1344510Speter strtab = (char *)calloc(ssiz, 1); 1354510Speter if (strtab == NULL) { 1364510Speter fprintf(stderr, "%s: no room for %d bytes of string table", 1374510Speter a_outname , ssiz); 1384510Speter done(); 1394510Speter } 1404510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1414510Speter fprintf(stderr, "%s: error reading string table\n", a_outname ); 1424510Speter done(); 1434510Speter } 1444510Speter } 1454510Speter 1464510Speter /* 1474510Speter * Read in symbol table 1484510Speter */ 1494510Speter getsymtab(nfile) 1504510Speter FILE *nfile; 1514510Speter { 1524510Speter register long i; 1534510Speter int askfor; 1544510Speter struct nlist nbuf; 1554510Speter 1564510Speter /* pass1 - count symbols */ 1574510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1584510Speter nname = 0; 1594510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1604510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1614845Speter if ( ! funcsymbol( &nbuf ) ) { 1624510Speter continue; 1634510Speter } 1644510Speter nname++; 1654510Speter } 1664510Speter if (nname == 0) { 1674510Speter fprintf(stderr, "%s: no symbols\n", a_outname ); 1684510Speter done(); 1694510Speter } 1704510Speter /* 1714510Speter * ask also for CYCLEFRACTION extra namelist entries for 1724510Speter * cycle entries. these hide out at the end of the namelist 1734510Speter * and aren't accessed unless the whole namelist (nname+ncycles) 1744510Speter * is sorted and searched. 1754510Speter */ 1764510Speter ncycles = nname * CYCLEFRACTION; 1774510Speter askfor = nname + 1 + ncycles; 1784510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 1794510Speter if (nl == 0) { 1804510Speter fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 1814510Speter askfor * sizeof(nltype) ); 1824510Speter done(); 1834510Speter } 1844510Speter 1854510Speter /* pass2 - read symbols */ 1864510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1874510Speter npe = nl; 1884510Speter nname = 0; 1894510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1904510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1914845Speter if ( ! funcsymbol( &nbuf ) ) { 1924845Speter # ifdef DEBUG 1934845Speter if ( debug & AOUTDEBUG ) { 1944845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 1954845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 1964845Speter } 1974845Speter # endif DEBUG 1984510Speter continue; 1994510Speter } 2004510Speter npe->value = nbuf.n_value; 2014510Speter npe->name = strtab+nbuf.n_un.n_strx; 2024510Speter # ifdef DEBUG 2034510Speter if ( debug & AOUTDEBUG ) { 2044510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2054510Speter nname , npe -> name , npe -> value ); 2064510Speter } 2074510Speter # endif DEBUG 2084510Speter npe++; 2094510Speter nname++; 2104510Speter } 2114510Speter npe->value = -1; 2124510Speter npe++; 2134510Speter } 2144510Speter 2154510Speter /* 2164720Speter * read in the text space of an a.out file 2174720Speter */ 2184720Speter gettextspace( nfile ) 2194720Speter FILE *nfile; 2204720Speter { 2214720Speter unsigned char *malloc(); 2224720Speter 2234720Speter if ( cflag == 0 ) { 2244720Speter return; 2254720Speter } 2264720Speter textspace = malloc( xbuf.a_text ); 2274720Speter if ( textspace == 0 ) { 2284720Speter fprintf( stderr , "gprof: ran out room for %d bytes of text space: " ); 2294720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2304720Speter return; 2314720Speter } 2324720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2334720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2344720Speter fprintf( stderr , "couldn't read text space: " ); 2354720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2364720Speter free( textspace ); 2374720Speter textspace = 0; 2384720Speter return; 2394720Speter } 2404720Speter } 2414720Speter /* 2424563Speter * information from a gmon.out file is in two parts: 2434510Speter * an array of sampling hits within pc ranges, 2444510Speter * and the arcs. 2454510Speter */ 2464510Speter getpfile(filename) 2474510Speter char *filename; 2484510Speter { 2494510Speter FILE *pfile; 2504510Speter FILE *openpfile(); 2514510Speter struct rawarc arc; 2524510Speter 2534510Speter pfile = openpfile(filename); 2544510Speter readsamples(pfile); 2554510Speter /* 2564510Speter * the rest of the file consists of 2574510Speter * a bunch of <from,self,count> tuples. 2584510Speter */ 2594510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2604510Speter # ifdef DEBUG 2614510Speter if ( debug & SAMPLEDEBUG ) { 2624752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2634510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2644510Speter } 2654510Speter # endif DEBUG 2664510Speter /* 2674510Speter * add this arc 2684510Speter */ 2694510Speter tally( &arc ); 2704510Speter } 2714510Speter fclose(pfile); 2724510Speter } 2734510Speter 2744841Speter FILE * 2754841Speter openpfile(filename) 2764510Speter char *filename; 2774510Speter { 278*4866Smckusic struct hdr tmp; 2794510Speter FILE *pfile; 2804510Speter 2814510Speter if((pfile = fopen(filename, "r")) == NULL) { 2824510Speter perror(filename); 2834510Speter done(); 2844510Speter } 285*4866Smckusic fread(&tmp, sizeof(struct hdr), 1, pfile); 286*4866Smckusic if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc || 287*4866Smckusic tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) { 288*4866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 289*4866Smckusic done(); 290*4866Smckusic } 291*4866Smckusic h = tmp; 2924752Speter s_lowpc = (unsigned long) h.lowpc; 2934752Speter s_highpc = (unsigned long) h.highpc; 2944510Speter lowpc = h.lowpc - (UNIT *)0; 2954510Speter highpc = h.highpc - (UNIT *)0; 2964510Speter sampbytes = h.ncnt - sizeof(struct hdr); 2974510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 2984510Speter return(pfile); 2994510Speter } 3004510Speter 3014510Speter tally( rawp ) 3024510Speter struct rawarc *rawp; 3034510Speter { 3044510Speter nltype *parentp; 3054510Speter nltype *childp; 3064510Speter 3074510Speter parentp = nllookup( rawp -> raw_frompc ); 3084510Speter childp = nllookup( rawp -> raw_selfpc ); 3094510Speter childp -> ncall += rawp -> raw_count; 3104510Speter # ifdef DEBUG 3114510Speter if ( debug & TALLYDEBUG ) { 3124510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3134510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3144510Speter } 3154510Speter # endif DEBUG 3164720Speter addarc( parentp , childp , rawp -> raw_count ); 3174510Speter } 3184510Speter 319*4866Smckusic /* 320*4866Smckusic * dump out the gmon.sum file 321*4866Smckusic */ 322*4866Smckusic dumpsum( sumfile ) 323*4866Smckusic char *sumfile; 324*4866Smckusic { 325*4866Smckusic register nltype *nlp; 326*4866Smckusic register arctype *arcp; 327*4866Smckusic struct rawarc arc; 328*4866Smckusic FILE *sfile; 329*4866Smckusic 330*4866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 331*4866Smckusic perror( sumfile ); 332*4866Smckusic done(); 333*4866Smckusic } 334*4866Smckusic /* 335*4866Smckusic * dump the header; use the last header read in 336*4866Smckusic */ 337*4866Smckusic if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) { 338*4866Smckusic perror( sumfile ); 339*4866Smckusic done(); 340*4866Smckusic } 341*4866Smckusic /* 342*4866Smckusic * dump the samples 343*4866Smckusic */ 344*4866Smckusic if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) { 345*4866Smckusic perror( sumfile ); 346*4866Smckusic done(); 347*4866Smckusic } 348*4866Smckusic /* 349*4866Smckusic * dump the normalized raw arc information 350*4866Smckusic */ 351*4866Smckusic for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) { 352*4866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 353*4866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 354*4866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 355*4866Smckusic arc.raw_count = arcp -> arc_count; 356*4866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 357*4866Smckusic perror( sumfile ); 358*4866Smckusic done(); 359*4866Smckusic } 360*4866Smckusic # ifdef DEBUG 361*4866Smckusic if ( debug & SAMPLEDEBUG ) { 362*4866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 363*4866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 364*4866Smckusic } 365*4866Smckusic # endif DEBUG 366*4866Smckusic } 367*4866Smckusic } 368*4866Smckusic fclose( sfile ); 369*4866Smckusic } 370*4866Smckusic 3714510Speter valcmp(p1, p2) 3724510Speter nltype *p1, *p2; 3734510Speter { 3744510Speter if ( p1 -> value < p2 -> value ) { 3754510Speter return LESSTHAN; 3764510Speter } 3774510Speter if ( p1 -> value > p2 -> value ) { 3784510Speter return GREATERTHAN; 3794510Speter } 3804510Speter return EQUALTO; 3814510Speter } 3824510Speter 3834510Speter readsamples(pfile) 3844510Speter FILE *pfile; 3854510Speter { 3864510Speter register i; 3874510Speter unsigned UNIT sample; 3884510Speter 3894510Speter if (samples == 0) { 3904510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 3914510Speter if (samples == 0) { 3924510Speter fprintf( stderr , "prof: No room for %d sample pc's\n", 3934510Speter sampbytes / sizeof (unsigned UNIT)); 3944510Speter done(); 3954510Speter } 3964510Speter } 3974510Speter for (i = 0; i < nsamples; i++) { 3984510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 3994510Speter if (feof(pfile)) 4004510Speter break; 4014510Speter samples[i] += sample; 4024510Speter } 4034510Speter if (i != nsamples) { 4044510Speter fprintf(stderr, 4054510Speter "prof: unexpected EOF after reading %d/%d samples\n", 4064510Speter --i, nsamples); 4074510Speter done(); 4084510Speter } 4094510Speter } 4104510Speter 4114510Speter /* 4124510Speter * Assign samples to the procedures to which they belong. 4134510Speter */ 4144510Speter asgnsamples() 4154510Speter { 4164510Speter register int j; 4174510Speter unsigned UNIT ccnt; 4184510Speter double time; 4194510Speter unsigned long pcl, pch; 4204510Speter register int i; 4214841Speter unsigned long overlap; 4224510Speter unsigned long svalue0, svalue1; 4234510Speter 4244510Speter /* read samples and assign to namelist symbols */ 4254510Speter scale = highpc - lowpc; 4264510Speter scale /= nsamples; 4274510Speter for (i=0; i < nsamples; i++) { 4284510Speter ccnt = samples[i]; 4294510Speter if (ccnt == 0) 4304510Speter continue; 4314510Speter pcl = lowpc + scale*i; 4324510Speter pch = lowpc + scale*(i+1); 4334510Speter time = ccnt; 4344510Speter # ifdef DEBUG 4354510Speter if ( debug & SAMPLEDEBUG ) { 4364510Speter printf( "[asgnsamples] ccnt %d time %f totime %f\n" , 4374510Speter ccnt , time , totime ); 4384510Speter } 4394510Speter # endif DEBUG 4404510Speter totime += time; 4414510Speter for (j=0; j<nname; j++) { 4424510Speter svalue0 = nl[j].value / sizeof(UNIT); 4434510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4444510Speter if (pch < svalue0) 4454510Speter break; 4464510Speter if (pcl >= svalue1) 4474510Speter continue; 4484510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4494510Speter if (overlap>0) { 4504510Speter # ifdef DEBUG 4514510Speter if ( debug & SAMPLEDEBUG ) { 4524510Speter printf( "[asgnsamples] %s gets %f ticks\n" , 4534510Speter nl[j].name , overlap*time/scale ); 4544510Speter } 4554510Speter # endif DEBUG 4564510Speter nl[j].time += overlap*time/scale; 4574510Speter } 4584510Speter } 4594510Speter } 4604510Speter # ifdef DEBUG 4614510Speter if ( debug & SAMPLEDEBUG ) { 4624510Speter printf( "[asgnsamples] totime %f\n" , totime ); 4634510Speter } 4644510Speter # endif DEBUG 4654510Speter if (totime==0.0) { 4664510Speter fprintf( stderr , "No time accumulated\n" ); 4674510Speter totime=1.0; 4684510Speter } 4694510Speter } 4704510Speter 4714510Speter 4724841Speter unsigned long 4734510Speter min(a, b) 4744841Speter unsigned long a,b; 4754510Speter { 4764510Speter if (a<b) 4774510Speter return(a); 4784510Speter return(b); 4794510Speter } 4804510Speter 4814841Speter unsigned long 4824510Speter max(a, b) 4834841Speter unsigned long a,b; 4844510Speter { 4854510Speter if (a>b) 4864510Speter return(a); 4874510Speter return(b); 4884510Speter } 4894510Speter 4904845Speter bool 4914845Speter funcsymbol( nlistp ) 4924845Speter struct nlist *nlistp; 4934845Speter { 4944845Speter extern char *strtab; /* string table from a.out */ 4954851Speter extern int aflag; /* if static functions aren't desired */ 4964845Speter char *name; 4974845Speter 4984845Speter /* 4994845Speter * must be a text symbol, 5004851Speter * and static text symbols don't qualify if aflag set. 5014845Speter */ 5024845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 5034851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 5044845Speter return FALSE; 5054845Speter } 5064845Speter /* 5074845Speter * can't have any `funny characters in name, 5084845Speter * where `funny' includes `.', .o file names 5094845Speter * and `$', pascal labels. 5104845Speter */ 5114845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 5124845Speter if ( *name == '.' || *name == '$' ) { 5134845Speter return FALSE; 5144845Speter } 5154845Speter } 5164845Speter return TRUE; 5174845Speter } 5184845Speter 5194510Speter done() 5204510Speter { 5214510Speter 5224510Speter exit(0); 5234510Speter } 524