14510Speter #ifndef lint 2*4720Speter static char *sccsid = "@(#)gprof.c 1.3 (Berkeley) 11/02/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++; 26*4720Speter } else if ( **argv == 'c' ) { 27*4720Speter 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 printprof() 674510Speter { 684510Speter register nltype *np; 694510Speter nltype **sortednlp; 704510Speter int index; 714510Speter 724510Speter actime = 0.0; 734510Speter putprofheader(); 744510Speter /* 754510Speter * Sort the symbol table in by time 764510Speter */ 774510Speter sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); 784510Speter if ( sortednlp == (nltype **) 0 ) { 794510Speter fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); 804510Speter } 814510Speter for ( index = 0 ; index < nname ; index += 1 ) { 824510Speter sortednlp[ index ] = &nl[ index ]; 834510Speter } 844510Speter qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); 854510Speter for ( index = 0 ; index < nname ; index += 1 ) { 864510Speter np = sortednlp[ index ]; 874510Speter putprofline( np , 1 ); 884510Speter } 894510Speter actime = 0.0; 904510Speter printf( "\ngranularity: each sample hit covers %.1f bytes" , scale ); 914510Speter printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ ); 924510Speter } 934510Speter 944510Speter putprofline( np , cumflag ) 954510Speter register nltype *np; 964510Speter int cumflag; 974510Speter { 984510Speter double time; 994510Speter long calls = np -> ncall + np -> selfcalls; 1004510Speter 1014510Speter if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) { 1024510Speter return; 1034510Speter } 1044510Speter if ( cumflag ) { 1054510Speter time = (np->time + np->childtime) / totime; 1064510Speter actime += np->time; 1074510Speter if ( np -> index != 0 ) { 1084510Speter printf( "[%d]" , np -> index ); 1094510Speter } 1104510Speter printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ ); 1114510Speter } else { 1124510Speter printf( "\t%5.5s %7.7s" , "" , "" ); 1134510Speter } 1144510Speter printf( " %7.1f", np -> time / HZ ); 1154510Speter if ( np -> childtime != 0.0 ) { 1164510Speter printf( " %7.1f" , np -> childtime / HZ ); 1174510Speter } else { 1184510Speter printf( " %7.7s" , "" ); 1194510Speter } 1204510Speter if ( calls != 0 ) { 1214510Speter printf( " %7d" , np -> ncall ); 1224510Speter if ( np -> selfcalls != 0 ) { 1234510Speter printf( "+%-7d " , np -> selfcalls ); 1244510Speter } else { 1254510Speter printf( " %7.7s " , "" ); 1264510Speter } 1274510Speter } else { 1284510Speter printf( " %7.7s %7.7s " , "" , "" ); 1294510Speter } 1304510Speter if ( ! cumflag ) { 1314510Speter printf( " " ); 1324510Speter } 1334510Speter printname( np ); 1344510Speter printf( "\n" ); 1354510Speter } 1364510Speter 1374510Speter /* 1384510Speter * header for putprofline 1394510Speter */ 1404510Speter putprofheader() 1414510Speter { 1424510Speter 1434510Speter printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" , 1444510Speter "%time" , "cumsecs" , " self" , " child" , "ncall" , "" , "name" ); 1454510Speter } 1464510Speter 1474510Speter /* 1484510Speter * Set up string and symbol tables from a.out. 149*4720Speter * and optionally the text space. 1504510Speter * On return symbol table is sorted by value. 1514510Speter */ 1524510Speter getnfile() 1534510Speter { 1544510Speter FILE *nfile; 1554510Speter 1564510Speter nfile = fopen( a_outname ,"r"); 1574510Speter if (nfile == NULL) { 1584510Speter perror( a_outname ); 1594510Speter done(); 1604510Speter } 1614510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1624510Speter if (N_BADMAG(xbuf)) { 1634510Speter fprintf(stderr, "%s: bad format\n", a_outname ); 1644510Speter done(); 1654510Speter } 1664510Speter getstrtab(nfile); 1674510Speter getsymtab(nfile); 168*4720Speter gettextspace( nfile ); 1694510Speter qsort(nl, nname, sizeof(nltype), valcmp); 1704510Speter fclose(nfile); 1714510Speter # ifdef DEBUG 1724510Speter if ( debug & AOUTDEBUG ) { 1734510Speter register int j; 1744510Speter 1754510Speter for (j = 0; j < nname; j++){ 1764510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 1774510Speter } 1784510Speter } 1794510Speter # endif DEBUG 1804510Speter } 1814510Speter 1824510Speter getstrtab(nfile) 1834510Speter FILE *nfile; 1844510Speter { 1854510Speter 1864510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 1874510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 1884510Speter fprintf(stderr, "%s: no string table (old format?)\n", a_outname ); 1894510Speter done(); 1904510Speter } 1914510Speter strtab = (char *)calloc(ssiz, 1); 1924510Speter if (strtab == NULL) { 1934510Speter fprintf(stderr, "%s: no room for %d bytes of string table", 1944510Speter a_outname , ssiz); 1954510Speter done(); 1964510Speter } 1974510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 1984510Speter fprintf(stderr, "%s: error reading string table\n", a_outname ); 1994510Speter done(); 2004510Speter } 2014510Speter } 2024510Speter 2034510Speter /* 2044510Speter * Read in symbol table 2054510Speter */ 2064510Speter getsymtab(nfile) 2074510Speter FILE *nfile; 2084510Speter { 2094510Speter register long i; 2104510Speter int askfor; 2114510Speter struct nlist nbuf; 2124510Speter 2134510Speter /* pass1 - count symbols */ 2144510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2154510Speter nname = 0; 2164510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2174510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2184510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 2194510Speter continue; 2204510Speter } 2214510Speter nname++; 2224510Speter } 2234510Speter if (nname == 0) { 2244510Speter fprintf(stderr, "%s: no symbols\n", a_outname ); 2254510Speter done(); 2264510Speter } 2274510Speter /* 2284510Speter * ask also for CYCLEFRACTION extra namelist entries for 2294510Speter * cycle entries. these hide out at the end of the namelist 2304510Speter * and aren't accessed unless the whole namelist (nname+ncycles) 2314510Speter * is sorted and searched. 2324510Speter */ 2334510Speter ncycles = nname * CYCLEFRACTION; 2344510Speter askfor = nname + 1 + ncycles; 2354510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 2364510Speter if (nl == 0) { 2374510Speter fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 2384510Speter askfor * sizeof(nltype) ); 2394510Speter done(); 2404510Speter } 2414510Speter 2424510Speter /* pass2 - read symbols */ 2434510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2444510Speter npe = nl; 2454510Speter nname = 0; 2464510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2474510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2484510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 2494510Speter continue; 2504510Speter } 2514510Speter npe->value = nbuf.n_value; 2524510Speter npe->name = strtab+nbuf.n_un.n_strx; 2534510Speter # ifdef DEBUG 2544510Speter if ( debug & AOUTDEBUG ) { 2554510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2564510Speter nname , npe -> name , npe -> value ); 2574510Speter } 2584510Speter # endif DEBUG 2594510Speter npe++; 2604510Speter nname++; 2614510Speter } 2624510Speter npe->value = -1; 2634510Speter npe++; 2644510Speter } 2654510Speter 2664510Speter /* 267*4720Speter * read in the text space of an a.out file 268*4720Speter */ 269*4720Speter gettextspace( nfile ) 270*4720Speter FILE *nfile; 271*4720Speter { 272*4720Speter unsigned char *malloc(); 273*4720Speter 274*4720Speter if ( cflag == 0 ) { 275*4720Speter return; 276*4720Speter } 277*4720Speter textspace = malloc( xbuf.a_text ); 278*4720Speter if ( textspace == 0 ) { 279*4720Speter fprintf( stderr , "gprof: ran out room for %d bytes of text space: " ); 280*4720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 281*4720Speter return; 282*4720Speter } 283*4720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 284*4720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 285*4720Speter fprintf( stderr , "couldn't read text space: " ); 286*4720Speter fprintf( stderr , "can't do -c\n" , xbuf.a_text ); 287*4720Speter free( textspace ); 288*4720Speter textspace = 0; 289*4720Speter return; 290*4720Speter } 291*4720Speter } 292*4720Speter /* 2934563Speter * information from a gmon.out file is in two parts: 2944510Speter * an array of sampling hits within pc ranges, 2954510Speter * and the arcs. 2964510Speter */ 2974510Speter getpfile(filename) 2984510Speter char *filename; 2994510Speter { 3004510Speter FILE *pfile; 3014510Speter FILE *openpfile(); 3024510Speter struct rawarc arc; 3034510Speter 3044510Speter pfile = openpfile(filename); 3054510Speter readsamples(pfile); 3064510Speter /* 3074510Speter * the rest of the file consists of 3084510Speter * a bunch of <from,self,count> tuples. 3094510Speter */ 3104510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 3114510Speter # ifdef DEBUG 3124510Speter if ( debug & SAMPLEDEBUG ) { 3134510Speter printf( "[getpfile] frompc %d selfpc %d count %d\n" , 3144510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3154510Speter } 3164510Speter # endif DEBUG 3174510Speter /* 3184510Speter * add this arc 3194510Speter */ 3204510Speter tally( &arc ); 3214510Speter } 3224510Speter fclose(pfile); 3234510Speter } 3244510Speter 3254510Speter FILE *openpfile(filename) 3264510Speter char *filename; 3274510Speter { 3284510Speter FILE *pfile; 3294510Speter 3304510Speter if((pfile = fopen(filename, "r")) == NULL) { 3314510Speter perror(filename); 3324510Speter done(); 3334510Speter } 3344510Speter fread(&h, sizeof(struct hdr), 1, pfile); 3354510Speter lowpc = h.lowpc - (UNIT *)0; 3364510Speter highpc = h.highpc - (UNIT *)0; 3374510Speter sampbytes = h.ncnt - sizeof(struct hdr); 3384510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 3394510Speter return(pfile); 3404510Speter } 3414510Speter 3424510Speter tally( rawp ) 3434510Speter struct rawarc *rawp; 3444510Speter { 3454510Speter nltype *parentp; 3464510Speter nltype *childp; 3474510Speter 3484510Speter parentp = nllookup( rawp -> raw_frompc ); 3494510Speter childp = nllookup( rawp -> raw_selfpc ); 3504510Speter childp -> ncall += rawp -> raw_count; 3514510Speter # ifdef DEBUG 3524510Speter if ( debug & TALLYDEBUG ) { 3534510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 3544510Speter parentp -> name , childp -> name , rawp -> raw_count ); 3554510Speter } 3564510Speter # endif DEBUG 357*4720Speter addarc( parentp , childp , rawp -> raw_count ); 3584510Speter } 3594510Speter 3604510Speter valcmp(p1, p2) 3614510Speter nltype *p1, *p2; 3624510Speter { 3634510Speter if ( p1 -> value < p2 -> value ) { 3644510Speter return LESSTHAN; 3654510Speter } 3664510Speter if ( p1 -> value > p2 -> value ) { 3674510Speter return GREATERTHAN; 3684510Speter } 3694510Speter return EQUALTO; 3704510Speter } 3714510Speter 3724510Speter readsamples(pfile) 3734510Speter FILE *pfile; 3744510Speter { 3754510Speter register i; 3764510Speter unsigned UNIT sample; 3774510Speter 3784510Speter if (samples == 0) { 3794510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 3804510Speter if (samples == 0) { 3814510Speter fprintf( stderr , "prof: No room for %d sample pc's\n", 3824510Speter sampbytes / sizeof (unsigned UNIT)); 3834510Speter done(); 3844510Speter } 3854510Speter } 3864510Speter for (i = 0; i < nsamples; i++) { 3874510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 3884510Speter if (feof(pfile)) 3894510Speter break; 3904510Speter samples[i] += sample; 3914510Speter } 3924510Speter if (i != nsamples) { 3934510Speter fprintf(stderr, 3944510Speter "prof: unexpected EOF after reading %d/%d samples\n", 3954510Speter --i, nsamples); 3964510Speter done(); 3974510Speter } 3984510Speter } 3994510Speter 4004510Speter /* 4014510Speter * Assign samples to the procedures to which they belong. 4024510Speter */ 4034510Speter asgnsamples() 4044510Speter { 4054510Speter register int j; 4064510Speter unsigned UNIT ccnt; 4074510Speter double time; 4084510Speter unsigned long pcl, pch; 4094510Speter register int i; 4104510Speter int overlap; 4114510Speter unsigned long svalue0, svalue1; 4124510Speter 4134510Speter /* read samples and assign to namelist symbols */ 4144510Speter scale = highpc - lowpc; 4154510Speter scale /= nsamples; 4164510Speter for (i=0; i < nsamples; i++) { 4174510Speter ccnt = samples[i]; 4184510Speter if (ccnt == 0) 4194510Speter continue; 4204510Speter pcl = lowpc + scale*i; 4214510Speter pch = lowpc + scale*(i+1); 4224510Speter time = ccnt; 4234510Speter # ifdef DEBUG 4244510Speter if ( debug & SAMPLEDEBUG ) { 4254510Speter printf( "[asgnsamples] ccnt %d time %f totime %f\n" , 4264510Speter ccnt , time , totime ); 4274510Speter } 4284510Speter # endif DEBUG 4294510Speter totime += time; 4304510Speter for (j=0; j<nname; j++) { 4314510Speter svalue0 = nl[j].value / sizeof(UNIT); 4324510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 4334510Speter if (pch < svalue0) 4344510Speter break; 4354510Speter if (pcl >= svalue1) 4364510Speter continue; 4374510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 4384510Speter if (overlap>0) { 4394510Speter # ifdef DEBUG 4404510Speter if ( debug & SAMPLEDEBUG ) { 4414510Speter printf( "[asgnsamples] %s gets %f ticks\n" , 4424510Speter nl[j].name , overlap*time/scale ); 4434510Speter } 4444510Speter # endif DEBUG 4454510Speter nl[j].time += overlap*time/scale; 4464510Speter } 4474510Speter } 4484510Speter } 4494510Speter # ifdef DEBUG 4504510Speter if ( debug & SAMPLEDEBUG ) { 4514510Speter printf( "[asgnsamples] totime %f\n" , totime ); 4524510Speter } 4534510Speter # endif DEBUG 4544510Speter if (totime==0.0) { 4554510Speter fprintf( stderr , "No time accumulated\n" ); 4564510Speter totime=1.0; 4574510Speter } 4584510Speter } 4594510Speter 4604510Speter 4614510Speter min(a, b) 4624510Speter unsigned a,b; 4634510Speter { 4644510Speter if (a<b) 4654510Speter return(a); 4664510Speter return(b); 4674510Speter } 4684510Speter 4694510Speter max(a, b) 4704510Speter unsigned a,b; 4714510Speter { 4724510Speter if (a>b) 4734510Speter return(a); 4744510Speter return(b); 4754510Speter } 4764510Speter 4774510Speter timecmp( npp1 , npp2 ) 4784510Speter nltype **npp1, **npp2; 4794510Speter { 4804510Speter double d; 4814510Speter 4824510Speter d = (*npp2)->time - (*npp1)->time; 4834510Speter if (d > 0.0) 4844510Speter return(1); 4854510Speter if (d < 0.0) 4864510Speter return(-1); 4874510Speter return(strcmp((*npp1)->name,(*npp2)->name)); 4884510Speter } 4894510Speter 4904510Speter done() 4914510Speter { 4924510Speter 4934510Speter exit(0); 4944510Speter } 495