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