14510Speter #ifndef lint 2*4841Speter static char *sccsid = "@(#)gprof.c 1.5 (Berkeley) 11/09/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)++; 174510Speter if ( **argv == 'd' ) { 184510Speter (*argv)++; 194510Speter debug |= atoi( *argv ); 204510Speter debug |= ANYDEBUG; 214510Speter # ifdef DEBUG 224510Speter printf( "[main] debug = %d\n" , debug ); 234510Speter # endif DEBUG 244510Speter } else if ( **argv == 'z' ) { 254510Speter zflg++; 264720Speter } else if ( **argv == 'c' ) { 274720Speter cflag++; 284510Speter } 294510Speter argv++; 304510Speter } 314510Speter if ( *argv != 0 ) { 324510Speter a_outname = *argv; 334510Speter argv++; 344510Speter } else { 354510Speter a_outname = A_OUTNAME; 364510Speter } 374510Speter if ( *argv != 0 ) { 384563Speter gmonname = *argv; 394510Speter argv++; 404510Speter } else { 414563Speter gmonname = GMONNAME; 424510Speter } 434510Speter /* 444510Speter * get information about a.out file. 454510Speter */ 464510Speter getnfile(); 474510Speter /* 484510Speter * get information about mon.out file(s). 494510Speter */ 504563Speter getpfile( gmonname ); 514510Speter /* 524510Speter * assign samples to procedures 534510Speter */ 544510Speter asgnsamples(); 554510Speter /* 564510Speter * print the usual profile 574510Speter */ 584510Speter printprof(); 594510Speter /* 604510Speter * assemble and print the dynamic profile 614510Speter */ 624510Speter doarcs(); 634510Speter done(); 644510Speter } 654510Speter 664510Speter /* 674510Speter * Set up string and symbol tables from a.out. 684720Speter * and optionally the text space. 694510Speter * On return symbol table is sorted by value. 704510Speter */ 714510Speter getnfile() 724510Speter { 734510Speter FILE *nfile; 744510Speter 754510Speter nfile = fopen( a_outname ,"r"); 764510Speter if (nfile == NULL) { 774510Speter perror( a_outname ); 784510Speter done(); 794510Speter } 804510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 814510Speter if (N_BADMAG(xbuf)) { 824510Speter fprintf(stderr, "%s: bad format\n", a_outname ); 834510Speter done(); 844510Speter } 854510Speter getstrtab(nfile); 864510Speter getsymtab(nfile); 874720Speter gettextspace( nfile ); 884510Speter qsort(nl, nname, sizeof(nltype), valcmp); 894510Speter fclose(nfile); 904510Speter # ifdef DEBUG 914510Speter if ( debug & AOUTDEBUG ) { 924510Speter register int j; 934510Speter 944510Speter for (j = 0; j < nname; j++){ 954510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 964510Speter } 974510Speter } 984510Speter # endif DEBUG 994510Speter } 1004510Speter 1014510Speter getstrtab(nfile) 1024510Speter FILE *nfile; 1034510Speter { 1044510Speter 1054510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1064510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1074510Speter fprintf(stderr, "%s: no string table (old format?)\n", a_outname ); 1084510Speter done(); 1094510Speter } 1104510Speter strtab = (char *)calloc(ssiz, 1); 1114510Speter if (strtab == NULL) { 1124510Speter fprintf(stderr, "%s: no room for %d bytes of string table", 1134510Speter a_outname , ssiz); 1144510Speter done(); 1154510Speter } 1164510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1174510Speter fprintf(stderr, "%s: error reading string table\n", a_outname ); 1184510Speter done(); 1194510Speter } 1204510Speter } 1214510Speter 1224510Speter /* 1234510Speter * Read in symbol table 1244510Speter */ 1254510Speter getsymtab(nfile) 1264510Speter FILE *nfile; 1274510Speter { 1284510Speter register long i; 1294510Speter int askfor; 1304510Speter struct nlist nbuf; 1314510Speter 1324510Speter /* pass1 - count symbols */ 1334510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1344510Speter nname = 0; 1354510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1364510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1374510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 1384510Speter continue; 1394510Speter } 1404510Speter nname++; 1414510Speter } 1424510Speter if (nname == 0) { 1434510Speter fprintf(stderr, "%s: no symbols\n", a_outname ); 1444510Speter done(); 1454510Speter } 1464510Speter /* 1474510Speter * ask also for CYCLEFRACTION extra namelist entries for 1484510Speter * cycle entries. these hide out at the end of the namelist 1494510Speter * and aren't accessed unless the whole namelist (nname+ncycles) 1504510Speter * is sorted and searched. 1514510Speter */ 1524510Speter ncycles = nname * CYCLEFRACTION; 1534510Speter askfor = nname + 1 + ncycles; 1544510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 1554510Speter if (nl == 0) { 1564510Speter fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 1574510Speter askfor * sizeof(nltype) ); 1584510Speter done(); 1594510Speter } 1604510Speter 1614510Speter /* pass2 - read symbols */ 1624510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1634510Speter npe = nl; 1644510Speter nname = 0; 1654510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1664510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1674510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 1684510Speter continue; 1694510Speter } 1704510Speter npe->value = nbuf.n_value; 1714510Speter npe->name = strtab+nbuf.n_un.n_strx; 1724510Speter # ifdef DEBUG 1734510Speter if ( debug & AOUTDEBUG ) { 1744510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 1754510Speter nname , npe -> name , npe -> value ); 1764510Speter } 1774510Speter # endif DEBUG 1784510Speter npe++; 1794510Speter nname++; 1804510Speter } 1814510Speter npe->value = -1; 1824510Speter npe++; 1834510Speter } 1844510Speter 1854510Speter /* 1864720Speter * read in the text space of an a.out file 1874720Speter */ 1884720Speter gettextspace( nfile ) 1894720Speter FILE *nfile; 1904720Speter { 1914720Speter unsigned char *malloc(); 1924720Speter 1934720Speter if ( cflag == 0 ) { 1944720Speter return; 1954720Speter } 1964720Speter textspace = malloc( xbuf.a_text ); 1974720Speter if ( textspace == 0 ) { 1984720Speter fprintf( stderr , "gprof: ran out room for %d bytes of text space: " ); 1994720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2004720Speter return; 2014720Speter } 2024720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2034720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2044720Speter fprintf( stderr , "couldn't read text space: " ); 2054720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2064720Speter free( textspace ); 2074720Speter textspace = 0; 2084720Speter return; 2094720Speter } 2104720Speter } 2114720Speter /* 2124563Speter * information from a gmon.out file is in two parts: 2134510Speter * an array of sampling hits within pc ranges, 2144510Speter * and the arcs. 2154510Speter */ 2164510Speter getpfile(filename) 2174510Speter char *filename; 2184510Speter { 2194510Speter FILE *pfile; 2204510Speter FILE *openpfile(); 2214510Speter struct rawarc arc; 2224510Speter 2234510Speter pfile = openpfile(filename); 2244510Speter readsamples(pfile); 2254510Speter /* 2264510Speter * the rest of the file consists of 2274510Speter * a bunch of <from,self,count> tuples. 2284510Speter */ 2294510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2304510Speter # ifdef DEBUG 2314510Speter if ( debug & SAMPLEDEBUG ) { 2324752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2334510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2344510Speter } 2354510Speter # endif DEBUG 2364510Speter /* 2374510Speter * add this arc 2384510Speter */ 2394510Speter tally( &arc ); 2404510Speter } 2414510Speter fclose(pfile); 2424510Speter } 2434510Speter 244*4841Speter FILE * 245*4841Speter openpfile(filename) 2464510Speter char *filename; 2474510Speter { 2484510Speter FILE *pfile; 2494510Speter 2504510Speter if((pfile = fopen(filename, "r")) == NULL) { 2514510Speter perror(filename); 2524510Speter done(); 2534510Speter } 2544510Speter fread(&h, sizeof(struct hdr), 1, pfile); 2554752Speter s_lowpc = (unsigned long) h.lowpc; 2564752Speter s_highpc = (unsigned long) h.highpc; 2574510Speter lowpc = h.lowpc - (UNIT *)0; 2584510Speter highpc = h.highpc - (UNIT *)0; 2594510Speter sampbytes = h.ncnt - sizeof(struct hdr); 2604510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 2614510Speter return(pfile); 2624510Speter } 2634510Speter 2644510Speter tally( rawp ) 2654510Speter struct rawarc *rawp; 2664510Speter { 2674510Speter nltype *parentp; 2684510Speter nltype *childp; 2694510Speter 2704510Speter parentp = nllookup( rawp -> raw_frompc ); 2714510Speter childp = nllookup( rawp -> raw_selfpc ); 2724510Speter childp -> ncall += rawp -> raw_count; 2734510Speter # ifdef DEBUG 2744510Speter if ( debug & TALLYDEBUG ) { 2754510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 2764510Speter parentp -> name , childp -> name , rawp -> raw_count ); 2774510Speter } 2784510Speter # endif DEBUG 2794720Speter addarc( parentp , childp , rawp -> raw_count ); 2804510Speter } 2814510Speter 2824510Speter valcmp(p1, p2) 2834510Speter nltype *p1, *p2; 2844510Speter { 2854510Speter if ( p1 -> value < p2 -> value ) { 2864510Speter return LESSTHAN; 2874510Speter } 2884510Speter if ( p1 -> value > p2 -> value ) { 2894510Speter return GREATERTHAN; 2904510Speter } 2914510Speter return EQUALTO; 2924510Speter } 2934510Speter 2944510Speter readsamples(pfile) 2954510Speter FILE *pfile; 2964510Speter { 2974510Speter register i; 2984510Speter unsigned UNIT sample; 2994510Speter 3004510Speter if (samples == 0) { 3014510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 3024510Speter if (samples == 0) { 3034510Speter fprintf( stderr , "prof: No room for %d sample pc's\n", 3044510Speter sampbytes / sizeof (unsigned UNIT)); 3054510Speter done(); 3064510Speter } 3074510Speter } 3084510Speter for (i = 0; i < nsamples; i++) { 3094510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 3104510Speter if (feof(pfile)) 3114510Speter break; 3124510Speter samples[i] += sample; 3134510Speter } 3144510Speter if (i != nsamples) { 3154510Speter fprintf(stderr, 3164510Speter "prof: unexpected EOF after reading %d/%d samples\n", 3174510Speter --i, nsamples); 3184510Speter done(); 3194510Speter } 3204510Speter } 3214510Speter 3224510Speter /* 3234510Speter * Assign samples to the procedures to which they belong. 3244510Speter */ 3254510Speter asgnsamples() 3264510Speter { 3274510Speter register int j; 3284510Speter unsigned UNIT ccnt; 3294510Speter double time; 3304510Speter unsigned long pcl, pch; 3314510Speter register int i; 332*4841Speter unsigned long overlap; 3334510Speter unsigned long svalue0, svalue1; 3344510Speter 3354510Speter /* read samples and assign to namelist symbols */ 3364510Speter scale = highpc - lowpc; 3374510Speter scale /= nsamples; 3384510Speter for (i=0; i < nsamples; i++) { 3394510Speter ccnt = samples[i]; 3404510Speter if (ccnt == 0) 3414510Speter continue; 3424510Speter pcl = lowpc + scale*i; 3434510Speter pch = lowpc + scale*(i+1); 3444510Speter time = ccnt; 3454510Speter # ifdef DEBUG 3464510Speter if ( debug & SAMPLEDEBUG ) { 3474510Speter printf( "[asgnsamples] ccnt %d time %f totime %f\n" , 3484510Speter ccnt , time , totime ); 3494510Speter } 3504510Speter # endif DEBUG 3514510Speter totime += time; 3524510Speter for (j=0; j<nname; j++) { 3534510Speter svalue0 = nl[j].value / sizeof(UNIT); 3544510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 3554510Speter if (pch < svalue0) 3564510Speter break; 3574510Speter if (pcl >= svalue1) 3584510Speter continue; 3594510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 3604510Speter if (overlap>0) { 3614510Speter # ifdef DEBUG 3624510Speter if ( debug & SAMPLEDEBUG ) { 3634510Speter printf( "[asgnsamples] %s gets %f ticks\n" , 3644510Speter nl[j].name , overlap*time/scale ); 3654510Speter } 3664510Speter # endif DEBUG 3674510Speter nl[j].time += overlap*time/scale; 3684510Speter } 3694510Speter } 3704510Speter } 3714510Speter # ifdef DEBUG 3724510Speter if ( debug & SAMPLEDEBUG ) { 3734510Speter printf( "[asgnsamples] totime %f\n" , totime ); 3744510Speter } 3754510Speter # endif DEBUG 3764510Speter if (totime==0.0) { 3774510Speter fprintf( stderr , "No time accumulated\n" ); 3784510Speter totime=1.0; 3794510Speter } 3804510Speter } 3814510Speter 3824510Speter 383*4841Speter unsigned long 3844510Speter min(a, b) 385*4841Speter unsigned long a,b; 3864510Speter { 3874510Speter if (a<b) 3884510Speter return(a); 3894510Speter return(b); 3904510Speter } 3914510Speter 392*4841Speter unsigned long 3934510Speter max(a, b) 394*4841Speter unsigned long a,b; 3954510Speter { 3964510Speter if (a>b) 3974510Speter return(a); 3984510Speter return(b); 3994510Speter } 4004510Speter 4014510Speter done() 4024510Speter { 4034510Speter 4044510Speter exit(0); 4054510Speter } 406