14510Speter #ifndef lint 2*4851Speter static char *sccsid = "@(#)gprof.c 1.7 (Berkeley) 11/10/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 244845Speter } else if ( **argv == 'a' ) { 254845Speter aflag++; 264845Speter } else if ( **argv == 'c' ) { 274845Speter cflag++; 284510Speter } else if ( **argv == 'z' ) { 294510Speter zflg++; 304510Speter } 314510Speter argv++; 324510Speter } 334510Speter if ( *argv != 0 ) { 344510Speter a_outname = *argv; 354510Speter argv++; 364510Speter } else { 374510Speter a_outname = A_OUTNAME; 384510Speter } 394510Speter if ( *argv != 0 ) { 404563Speter gmonname = *argv; 414510Speter argv++; 424510Speter } else { 434563Speter gmonname = GMONNAME; 444510Speter } 454510Speter /* 464510Speter * get information about a.out file. 474510Speter */ 484510Speter getnfile(); 494510Speter /* 504510Speter * get information about mon.out file(s). 514510Speter */ 524563Speter getpfile( gmonname ); 534510Speter /* 544510Speter * assign samples to procedures 554510Speter */ 564510Speter asgnsamples(); 574510Speter /* 584510Speter * print the usual profile 594510Speter */ 604510Speter printprof(); 614510Speter /* 624510Speter * assemble and print the dynamic profile 634510Speter */ 644510Speter doarcs(); 654510Speter done(); 664510Speter } 674510Speter 684510Speter /* 694510Speter * Set up string and symbol tables from a.out. 704720Speter * and optionally the text space. 714510Speter * On return symbol table is sorted by value. 724510Speter */ 734510Speter getnfile() 744510Speter { 754510Speter FILE *nfile; 764510Speter 774510Speter nfile = fopen( a_outname ,"r"); 784510Speter if (nfile == NULL) { 794510Speter perror( a_outname ); 804510Speter done(); 814510Speter } 824510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 834510Speter if (N_BADMAG(xbuf)) { 844510Speter fprintf(stderr, "%s: bad format\n", a_outname ); 854510Speter done(); 864510Speter } 874510Speter getstrtab(nfile); 884510Speter getsymtab(nfile); 894720Speter gettextspace( nfile ); 904510Speter qsort(nl, nname, sizeof(nltype), valcmp); 914510Speter fclose(nfile); 924510Speter # ifdef DEBUG 934510Speter if ( debug & AOUTDEBUG ) { 944510Speter register int j; 954510Speter 964510Speter for (j = 0; j < nname; j++){ 974510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 984510Speter } 994510Speter } 1004510Speter # endif DEBUG 1014510Speter } 1024510Speter 1034510Speter getstrtab(nfile) 1044510Speter FILE *nfile; 1054510Speter { 1064510Speter 1074510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1084510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1094510Speter fprintf(stderr, "%s: no string table (old format?)\n", a_outname ); 1104510Speter done(); 1114510Speter } 1124510Speter strtab = (char *)calloc(ssiz, 1); 1134510Speter if (strtab == NULL) { 1144510Speter fprintf(stderr, "%s: no room for %d bytes of string table", 1154510Speter a_outname , ssiz); 1164510Speter done(); 1174510Speter } 1184510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1194510Speter fprintf(stderr, "%s: error reading string table\n", a_outname ); 1204510Speter done(); 1214510Speter } 1224510Speter } 1234510Speter 1244510Speter /* 1254510Speter * Read in symbol table 1264510Speter */ 1274510Speter getsymtab(nfile) 1284510Speter FILE *nfile; 1294510Speter { 1304510Speter register long i; 1314510Speter int askfor; 1324510Speter struct nlist nbuf; 1334510Speter 1344510Speter /* pass1 - count symbols */ 1354510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1364510Speter nname = 0; 1374510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1384510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1394845Speter if ( ! funcsymbol( &nbuf ) ) { 1404510Speter continue; 1414510Speter } 1424510Speter nname++; 1434510Speter } 1444510Speter if (nname == 0) { 1454510Speter fprintf(stderr, "%s: no symbols\n", a_outname ); 1464510Speter done(); 1474510Speter } 1484510Speter /* 1494510Speter * ask also for CYCLEFRACTION extra namelist entries for 1504510Speter * cycle entries. these hide out at the end of the namelist 1514510Speter * and aren't accessed unless the whole namelist (nname+ncycles) 1524510Speter * is sorted and searched. 1534510Speter */ 1544510Speter ncycles = nname * CYCLEFRACTION; 1554510Speter askfor = nname + 1 + ncycles; 1564510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 1574510Speter if (nl == 0) { 1584510Speter fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 1594510Speter askfor * sizeof(nltype) ); 1604510Speter done(); 1614510Speter } 1624510Speter 1634510Speter /* pass2 - read symbols */ 1644510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 1654510Speter npe = nl; 1664510Speter nname = 0; 1674510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 1684510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 1694845Speter if ( ! funcsymbol( &nbuf ) ) { 1704845Speter # ifdef DEBUG 1714845Speter if ( debug & AOUTDEBUG ) { 1724845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 1734845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 1744845Speter } 1754845Speter # endif DEBUG 1764510Speter continue; 1774510Speter } 1784510Speter npe->value = nbuf.n_value; 1794510Speter npe->name = strtab+nbuf.n_un.n_strx; 1804510Speter # ifdef DEBUG 1814510Speter if ( debug & AOUTDEBUG ) { 1824510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 1834510Speter nname , npe -> name , npe -> value ); 1844510Speter } 1854510Speter # endif DEBUG 1864510Speter npe++; 1874510Speter nname++; 1884510Speter } 1894510Speter npe->value = -1; 1904510Speter npe++; 1914510Speter } 1924510Speter 1934510Speter /* 1944720Speter * read in the text space of an a.out file 1954720Speter */ 1964720Speter gettextspace( nfile ) 1974720Speter FILE *nfile; 1984720Speter { 1994720Speter unsigned char *malloc(); 2004720Speter 2014720Speter if ( cflag == 0 ) { 2024720Speter return; 2034720Speter } 2044720Speter textspace = malloc( xbuf.a_text ); 2054720Speter if ( textspace == 0 ) { 2064720Speter fprintf( stderr , "gprof: ran out room for %d bytes of text space: " ); 2074720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2084720Speter return; 2094720Speter } 2104720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 2114720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 2124720Speter fprintf( stderr , "couldn't read text space: " ); 2134720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 2144720Speter free( textspace ); 2154720Speter textspace = 0; 2164720Speter return; 2174720Speter } 2184720Speter } 2194720Speter /* 2204563Speter * information from a gmon.out file is in two parts: 2214510Speter * an array of sampling hits within pc ranges, 2224510Speter * and the arcs. 2234510Speter */ 2244510Speter getpfile(filename) 2254510Speter char *filename; 2264510Speter { 2274510Speter FILE *pfile; 2284510Speter FILE *openpfile(); 2294510Speter struct rawarc arc; 2304510Speter 2314510Speter pfile = openpfile(filename); 2324510Speter readsamples(pfile); 2334510Speter /* 2344510Speter * the rest of the file consists of 2354510Speter * a bunch of <from,self,count> tuples. 2364510Speter */ 2374510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2384510Speter # ifdef DEBUG 2394510Speter if ( debug & SAMPLEDEBUG ) { 2404752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2414510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2424510Speter } 2434510Speter # endif DEBUG 2444510Speter /* 2454510Speter * add this arc 2464510Speter */ 2474510Speter tally( &arc ); 2484510Speter } 2494510Speter fclose(pfile); 2504510Speter } 2514510Speter 2524841Speter FILE * 2534841Speter openpfile(filename) 2544510Speter char *filename; 2554510Speter { 2564510Speter FILE *pfile; 2574510Speter 2584510Speter if((pfile = fopen(filename, "r")) == NULL) { 2594510Speter perror(filename); 2604510Speter done(); 2614510Speter } 2624510Speter fread(&h, sizeof(struct hdr), 1, pfile); 2634752Speter s_lowpc = (unsigned long) h.lowpc; 2644752Speter s_highpc = (unsigned long) h.highpc; 2654510Speter lowpc = h.lowpc - (UNIT *)0; 2664510Speter highpc = h.highpc - (UNIT *)0; 2674510Speter sampbytes = h.ncnt - sizeof(struct hdr); 2684510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 2694510Speter return(pfile); 2704510Speter } 2714510Speter 2724510Speter tally( rawp ) 2734510Speter struct rawarc *rawp; 2744510Speter { 2754510Speter nltype *parentp; 2764510Speter nltype *childp; 2774510Speter 2784510Speter parentp = nllookup( rawp -> raw_frompc ); 2794510Speter childp = nllookup( rawp -> raw_selfpc ); 2804510Speter childp -> ncall += rawp -> raw_count; 2814510Speter # ifdef DEBUG 2824510Speter if ( debug & TALLYDEBUG ) { 2834510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 2844510Speter parentp -> name , childp -> name , rawp -> raw_count ); 2854510Speter } 2864510Speter # endif DEBUG 2874720Speter addarc( parentp , childp , rawp -> raw_count ); 2884510Speter } 2894510Speter 2904510Speter valcmp(p1, p2) 2914510Speter nltype *p1, *p2; 2924510Speter { 2934510Speter if ( p1 -> value < p2 -> value ) { 2944510Speter return LESSTHAN; 2954510Speter } 2964510Speter if ( p1 -> value > p2 -> value ) { 2974510Speter return GREATERTHAN; 2984510Speter } 2994510Speter return EQUALTO; 3004510Speter } 3014510Speter 3024510Speter readsamples(pfile) 3034510Speter FILE *pfile; 3044510Speter { 3054510Speter register i; 3064510Speter unsigned UNIT sample; 3074510Speter 3084510Speter if (samples == 0) { 3094510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 3104510Speter if (samples == 0) { 3114510Speter fprintf( stderr , "prof: No room for %d sample pc's\n", 3124510Speter sampbytes / sizeof (unsigned UNIT)); 3134510Speter done(); 3144510Speter } 3154510Speter } 3164510Speter for (i = 0; i < nsamples; i++) { 3174510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 3184510Speter if (feof(pfile)) 3194510Speter break; 3204510Speter samples[i] += sample; 3214510Speter } 3224510Speter if (i != nsamples) { 3234510Speter fprintf(stderr, 3244510Speter "prof: unexpected EOF after reading %d/%d samples\n", 3254510Speter --i, nsamples); 3264510Speter done(); 3274510Speter } 3284510Speter } 3294510Speter 3304510Speter /* 3314510Speter * Assign samples to the procedures to which they belong. 3324510Speter */ 3334510Speter asgnsamples() 3344510Speter { 3354510Speter register int j; 3364510Speter unsigned UNIT ccnt; 3374510Speter double time; 3384510Speter unsigned long pcl, pch; 3394510Speter register int i; 3404841Speter unsigned long overlap; 3414510Speter unsigned long svalue0, svalue1; 3424510Speter 3434510Speter /* read samples and assign to namelist symbols */ 3444510Speter scale = highpc - lowpc; 3454510Speter scale /= nsamples; 3464510Speter for (i=0; i < nsamples; i++) { 3474510Speter ccnt = samples[i]; 3484510Speter if (ccnt == 0) 3494510Speter continue; 3504510Speter pcl = lowpc + scale*i; 3514510Speter pch = lowpc + scale*(i+1); 3524510Speter time = ccnt; 3534510Speter # ifdef DEBUG 3544510Speter if ( debug & SAMPLEDEBUG ) { 3554510Speter printf( "[asgnsamples] ccnt %d time %f totime %f\n" , 3564510Speter ccnt , time , totime ); 3574510Speter } 3584510Speter # endif DEBUG 3594510Speter totime += time; 3604510Speter for (j=0; j<nname; j++) { 3614510Speter svalue0 = nl[j].value / sizeof(UNIT); 3624510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 3634510Speter if (pch < svalue0) 3644510Speter break; 3654510Speter if (pcl >= svalue1) 3664510Speter continue; 3674510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 3684510Speter if (overlap>0) { 3694510Speter # ifdef DEBUG 3704510Speter if ( debug & SAMPLEDEBUG ) { 3714510Speter printf( "[asgnsamples] %s gets %f ticks\n" , 3724510Speter nl[j].name , overlap*time/scale ); 3734510Speter } 3744510Speter # endif DEBUG 3754510Speter nl[j].time += overlap*time/scale; 3764510Speter } 3774510Speter } 3784510Speter } 3794510Speter # ifdef DEBUG 3804510Speter if ( debug & SAMPLEDEBUG ) { 3814510Speter printf( "[asgnsamples] totime %f\n" , totime ); 3824510Speter } 3834510Speter # endif DEBUG 3844510Speter if (totime==0.0) { 3854510Speter fprintf( stderr , "No time accumulated\n" ); 3864510Speter totime=1.0; 3874510Speter } 3884510Speter } 3894510Speter 3904510Speter 3914841Speter unsigned long 3924510Speter min(a, b) 3934841Speter unsigned long a,b; 3944510Speter { 3954510Speter if (a<b) 3964510Speter return(a); 3974510Speter return(b); 3984510Speter } 3994510Speter 4004841Speter unsigned long 4014510Speter max(a, b) 4024841Speter unsigned long a,b; 4034510Speter { 4044510Speter if (a>b) 4054510Speter return(a); 4064510Speter return(b); 4074510Speter } 4084510Speter 4094845Speter bool 4104845Speter funcsymbol( nlistp ) 4114845Speter struct nlist *nlistp; 4124845Speter { 4134845Speter extern char *strtab; /* string table from a.out */ 414*4851Speter extern int aflag; /* if static functions aren't desired */ 4154845Speter char *name; 4164845Speter 4174845Speter /* 4184845Speter * must be a text symbol, 419*4851Speter * and static text symbols don't qualify if aflag set. 4204845Speter */ 4214845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 422*4851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 4234845Speter return FALSE; 4244845Speter } 4254845Speter /* 4264845Speter * can't have any `funny characters in name, 4274845Speter * where `funny' includes `.', .o file names 4284845Speter * and `$', pascal labels. 4294845Speter */ 4304845Speter for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) { 4314845Speter if ( *name == '.' || *name == '$' ) { 4324845Speter return FALSE; 4334845Speter } 4344845Speter } 4354845Speter return TRUE; 4364845Speter } 4374845Speter 4384510Speter done() 4394510Speter { 4404510Speter 4414510Speter exit(0); 4424510Speter } 443