1*4510Speter #ifndef lint 2*4510Speter static char *sccsid = "@(#)gprof.c 1.1 (Berkeley) 10/15/81"; 3*4510Speter #endif lint 4*4510Speter 5*4510Speter #include "dprof.h" 6*4510Speter 7*4510Speter main(argc, argv) 8*4510Speter int argc; 9*4510Speter char **argv; 10*4510Speter { 11*4510Speter 12*4510Speter --argc; 13*4510Speter argv++; 14*4510Speter debug = 0; 15*4510Speter while ( *argv != 0 && **argv == '-' ) { 16*4510Speter (*argv)++; 17*4510Speter if ( **argv == 'd' ) { 18*4510Speter (*argv)++; 19*4510Speter debug |= atoi( *argv ); 20*4510Speter debug |= ANYDEBUG; 21*4510Speter # ifdef DEBUG 22*4510Speter printf( "[main] debug = %d\n" , debug ); 23*4510Speter # endif DEBUG 24*4510Speter } else if ( **argv == 'z' ) { 25*4510Speter zflg++; 26*4510Speter } 27*4510Speter argv++; 28*4510Speter } 29*4510Speter if ( *argv != 0 ) { 30*4510Speter a_outname = *argv; 31*4510Speter argv++; 32*4510Speter } else { 33*4510Speter a_outname = A_OUTNAME; 34*4510Speter } 35*4510Speter if ( *argv != 0 ) { 36*4510Speter dmonname = *argv; 37*4510Speter argv++; 38*4510Speter } else { 39*4510Speter dmonname = DMONNAME; 40*4510Speter } 41*4510Speter /* 42*4510Speter * get information about a.out file. 43*4510Speter */ 44*4510Speter getnfile(); 45*4510Speter /* 46*4510Speter * get information about mon.out file(s). 47*4510Speter */ 48*4510Speter getpfile( dmonname ); 49*4510Speter /* 50*4510Speter * assign samples to procedures 51*4510Speter */ 52*4510Speter asgnsamples(); 53*4510Speter /* 54*4510Speter * print the usual profile 55*4510Speter */ 56*4510Speter printprof(); 57*4510Speter /* 58*4510Speter * assemble and print the dynamic profile 59*4510Speter */ 60*4510Speter doarcs(); 61*4510Speter done(); 62*4510Speter } 63*4510Speter 64*4510Speter printprof() 65*4510Speter { 66*4510Speter register nltype *np; 67*4510Speter nltype **sortednlp; 68*4510Speter int index; 69*4510Speter 70*4510Speter actime = 0.0; 71*4510Speter putprofheader(); 72*4510Speter /* 73*4510Speter * Sort the symbol table in by time 74*4510Speter */ 75*4510Speter sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); 76*4510Speter if ( sortednlp == (nltype **) 0 ) { 77*4510Speter fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); 78*4510Speter } 79*4510Speter for ( index = 0 ; index < nname ; index += 1 ) { 80*4510Speter sortednlp[ index ] = &nl[ index ]; 81*4510Speter } 82*4510Speter qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); 83*4510Speter for ( index = 0 ; index < nname ; index += 1 ) { 84*4510Speter np = sortednlp[ index ]; 85*4510Speter putprofline( np , 1 ); 86*4510Speter } 87*4510Speter actime = 0.0; 88*4510Speter printf( "\ngranularity: each sample hit covers %.1f bytes" , scale ); 89*4510Speter printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ ); 90*4510Speter } 91*4510Speter 92*4510Speter putprofline( np , cumflag ) 93*4510Speter register nltype *np; 94*4510Speter int cumflag; 95*4510Speter { 96*4510Speter double time; 97*4510Speter long calls = np -> ncall + np -> selfcalls; 98*4510Speter 99*4510Speter if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) { 100*4510Speter return; 101*4510Speter } 102*4510Speter if ( cumflag ) { 103*4510Speter time = (np->time + np->childtime) / totime; 104*4510Speter actime += np->time; 105*4510Speter if ( np -> index != 0 ) { 106*4510Speter printf( "[%d]" , np -> index ); 107*4510Speter } 108*4510Speter printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ ); 109*4510Speter } else { 110*4510Speter printf( "\t%5.5s %7.7s" , "" , "" ); 111*4510Speter } 112*4510Speter printf( " %7.1f", np -> time / HZ ); 113*4510Speter if ( np -> childtime != 0.0 ) { 114*4510Speter printf( " %7.1f" , np -> childtime / HZ ); 115*4510Speter } else { 116*4510Speter printf( " %7.7s" , "" ); 117*4510Speter } 118*4510Speter if ( calls != 0 ) { 119*4510Speter printf( " %7d" , np -> ncall ); 120*4510Speter if ( np -> selfcalls != 0 ) { 121*4510Speter printf( "+%-7d " , np -> selfcalls ); 122*4510Speter } else { 123*4510Speter printf( " %7.7s " , "" ); 124*4510Speter } 125*4510Speter } else { 126*4510Speter printf( " %7.7s %7.7s " , "" , "" ); 127*4510Speter } 128*4510Speter if ( ! cumflag ) { 129*4510Speter printf( " " ); 130*4510Speter } 131*4510Speter printname( np ); 132*4510Speter printf( "\n" ); 133*4510Speter } 134*4510Speter 135*4510Speter /* 136*4510Speter * header for putprofline 137*4510Speter */ 138*4510Speter putprofheader() 139*4510Speter { 140*4510Speter 141*4510Speter printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" , 142*4510Speter "%time" , "cumsecs" , " self" , " child" , "ncall" , "" , "name" ); 143*4510Speter } 144*4510Speter 145*4510Speter /* 146*4510Speter * Set up string and symbol tables from a.out. 147*4510Speter * On return symbol table is sorted by value. 148*4510Speter */ 149*4510Speter getnfile() 150*4510Speter { 151*4510Speter FILE *nfile; 152*4510Speter 153*4510Speter nfile = fopen( a_outname ,"r"); 154*4510Speter if (nfile == NULL) { 155*4510Speter perror( a_outname ); 156*4510Speter done(); 157*4510Speter } 158*4510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 159*4510Speter if (N_BADMAG(xbuf)) { 160*4510Speter fprintf(stderr, "%s: bad format\n", a_outname ); 161*4510Speter done(); 162*4510Speter } 163*4510Speter getstrtab(nfile); 164*4510Speter getsymtab(nfile); 165*4510Speter qsort(nl, nname, sizeof(nltype), valcmp); 166*4510Speter fclose(nfile); 167*4510Speter # ifdef DEBUG 168*4510Speter if ( debug & AOUTDEBUG ) { 169*4510Speter register int j; 170*4510Speter 171*4510Speter for (j = 0; j < nname; j++){ 172*4510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 173*4510Speter } 174*4510Speter } 175*4510Speter # endif DEBUG 176*4510Speter } 177*4510Speter 178*4510Speter getstrtab(nfile) 179*4510Speter FILE *nfile; 180*4510Speter { 181*4510Speter 182*4510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 183*4510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 184*4510Speter fprintf(stderr, "%s: no string table (old format?)\n", a_outname ); 185*4510Speter done(); 186*4510Speter } 187*4510Speter strtab = (char *)calloc(ssiz, 1); 188*4510Speter if (strtab == NULL) { 189*4510Speter fprintf(stderr, "%s: no room for %d bytes of string table", 190*4510Speter a_outname , ssiz); 191*4510Speter done(); 192*4510Speter } 193*4510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 194*4510Speter fprintf(stderr, "%s: error reading string table\n", a_outname ); 195*4510Speter done(); 196*4510Speter } 197*4510Speter } 198*4510Speter 199*4510Speter /* 200*4510Speter * Read in symbol table 201*4510Speter */ 202*4510Speter getsymtab(nfile) 203*4510Speter FILE *nfile; 204*4510Speter { 205*4510Speter register long i; 206*4510Speter int askfor; 207*4510Speter struct nlist nbuf; 208*4510Speter 209*4510Speter /* pass1 - count symbols */ 210*4510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 211*4510Speter nname = 0; 212*4510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 213*4510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 214*4510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 215*4510Speter continue; 216*4510Speter } 217*4510Speter nname++; 218*4510Speter } 219*4510Speter if (nname == 0) { 220*4510Speter fprintf(stderr, "%s: no symbols\n", a_outname ); 221*4510Speter done(); 222*4510Speter } 223*4510Speter /* 224*4510Speter * ask also for CYCLEFRACTION extra namelist entries for 225*4510Speter * cycle entries. these hide out at the end of the namelist 226*4510Speter * and aren't accessed unless the whole namelist (nname+ncycles) 227*4510Speter * is sorted and searched. 228*4510Speter */ 229*4510Speter ncycles = nname * CYCLEFRACTION; 230*4510Speter askfor = nname + 1 + ncycles; 231*4510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 232*4510Speter if (nl == 0) { 233*4510Speter fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 234*4510Speter askfor * sizeof(nltype) ); 235*4510Speter done(); 236*4510Speter } 237*4510Speter 238*4510Speter /* pass2 - read symbols */ 239*4510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 240*4510Speter npe = nl; 241*4510Speter nname = 0; 242*4510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 243*4510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 244*4510Speter if ( nbuf.n_type != N_TEXT+N_EXT ) { 245*4510Speter continue; 246*4510Speter } 247*4510Speter npe->value = nbuf.n_value; 248*4510Speter npe->name = strtab+nbuf.n_un.n_strx; 249*4510Speter # ifdef DEBUG 250*4510Speter if ( debug & AOUTDEBUG ) { 251*4510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 252*4510Speter nname , npe -> name , npe -> value ); 253*4510Speter } 254*4510Speter # endif DEBUG 255*4510Speter npe++; 256*4510Speter nname++; 257*4510Speter } 258*4510Speter npe->value = -1; 259*4510Speter npe++; 260*4510Speter } 261*4510Speter 262*4510Speter /* 263*4510Speter * information from a dmon.out file is in two parts: 264*4510Speter * an array of sampling hits within pc ranges, 265*4510Speter * and the arcs. 266*4510Speter */ 267*4510Speter getpfile(filename) 268*4510Speter char *filename; 269*4510Speter { 270*4510Speter FILE *pfile; 271*4510Speter FILE *openpfile(); 272*4510Speter struct rawarc arc; 273*4510Speter 274*4510Speter pfile = openpfile(filename); 275*4510Speter readsamples(pfile); 276*4510Speter /* 277*4510Speter * the rest of the file consists of 278*4510Speter * a bunch of <from,self,count> tuples. 279*4510Speter */ 280*4510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 281*4510Speter # ifdef DEBUG 282*4510Speter if ( debug & SAMPLEDEBUG ) { 283*4510Speter printf( "[getpfile] frompc %d selfpc %d count %d\n" , 284*4510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 285*4510Speter } 286*4510Speter # endif DEBUG 287*4510Speter /* 288*4510Speter * add this arc 289*4510Speter */ 290*4510Speter tally( &arc ); 291*4510Speter } 292*4510Speter fclose(pfile); 293*4510Speter } 294*4510Speter 295*4510Speter FILE *openpfile(filename) 296*4510Speter char *filename; 297*4510Speter { 298*4510Speter FILE *pfile; 299*4510Speter 300*4510Speter if((pfile = fopen(filename, "r")) == NULL) { 301*4510Speter perror(filename); 302*4510Speter done(); 303*4510Speter } 304*4510Speter fread(&h, sizeof(struct hdr), 1, pfile); 305*4510Speter lowpc = h.lowpc - (UNIT *)0; 306*4510Speter highpc = h.highpc - (UNIT *)0; 307*4510Speter sampbytes = h.ncnt - sizeof(struct hdr); 308*4510Speter nsamples = sampbytes / sizeof (unsigned UNIT); 309*4510Speter return(pfile); 310*4510Speter } 311*4510Speter 312*4510Speter tally( rawp ) 313*4510Speter struct rawarc *rawp; 314*4510Speter { 315*4510Speter nltype *parentp; 316*4510Speter nltype *childp; 317*4510Speter arctype *arcp; 318*4510Speter arctype *malloc(); 319*4510Speter 320*4510Speter parentp = nllookup( rawp -> raw_frompc ); 321*4510Speter childp = nllookup( rawp -> raw_selfpc ); 322*4510Speter childp -> ncall += rawp -> raw_count; 323*4510Speter # ifdef DEBUG 324*4510Speter if ( debug & TALLYDEBUG ) { 325*4510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 326*4510Speter parentp -> name , childp -> name , rawp -> raw_count ); 327*4510Speter } 328*4510Speter # endif DEBUG 329*4510Speter arcp = arclookup( parentp , childp ); 330*4510Speter if ( arcp != 0 ) { 331*4510Speter /* 332*4510Speter * a hit: just increment the count. 333*4510Speter */ 334*4510Speter # ifdef DEBUG 335*4510Speter if ( debug & TALLYDEBUG ) { 336*4510Speter printf( "[tally] hit %d += %d\n" , 337*4510Speter arcp -> arc_count , rawp -> raw_count ); 338*4510Speter } 339*4510Speter # endif DEBUG 340*4510Speter arcp -> arc_count += rawp -> raw_count; 341*4510Speter return; 342*4510Speter } 343*4510Speter arcp = malloc( sizeof *arcp ); 344*4510Speter arcp -> arc_parentp = parentp; 345*4510Speter arcp -> arc_childp = childp; 346*4510Speter arcp -> arc_count = rawp -> raw_count; 347*4510Speter /* 348*4510Speter * prepend this child to the children of this parent 349*4510Speter */ 350*4510Speter arcp -> arc_childlist = parentp -> children; 351*4510Speter parentp -> children = arcp; 352*4510Speter /* 353*4510Speter * prepend this parent to the parents of this child 354*4510Speter */ 355*4510Speter arcp -> arc_parentlist = childp -> parents; 356*4510Speter childp -> parents = arcp; 357*4510Speter } 358*4510Speter 359*4510Speter valcmp(p1, p2) 360*4510Speter nltype *p1, *p2; 361*4510Speter { 362*4510Speter if ( p1 -> value < p2 -> value ) { 363*4510Speter return LESSTHAN; 364*4510Speter } 365*4510Speter if ( p1 -> value > p2 -> value ) { 366*4510Speter return GREATERTHAN; 367*4510Speter } 368*4510Speter return EQUALTO; 369*4510Speter } 370*4510Speter 371*4510Speter readsamples(pfile) 372*4510Speter FILE *pfile; 373*4510Speter { 374*4510Speter register i; 375*4510Speter unsigned UNIT sample; 376*4510Speter 377*4510Speter if (samples == 0) { 378*4510Speter samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT)); 379*4510Speter if (samples == 0) { 380*4510Speter fprintf( stderr , "prof: No room for %d sample pc's\n", 381*4510Speter sampbytes / sizeof (unsigned UNIT)); 382*4510Speter done(); 383*4510Speter } 384*4510Speter } 385*4510Speter for (i = 0; i < nsamples; i++) { 386*4510Speter fread(&sample, sizeof (unsigned UNIT), 1, pfile); 387*4510Speter if (feof(pfile)) 388*4510Speter break; 389*4510Speter samples[i] += sample; 390*4510Speter } 391*4510Speter if (i != nsamples) { 392*4510Speter fprintf(stderr, 393*4510Speter "prof: unexpected EOF after reading %d/%d samples\n", 394*4510Speter --i, nsamples); 395*4510Speter done(); 396*4510Speter } 397*4510Speter } 398*4510Speter 399*4510Speter /* 400*4510Speter * Assign samples to the procedures to which they belong. 401*4510Speter */ 402*4510Speter asgnsamples() 403*4510Speter { 404*4510Speter register int j; 405*4510Speter unsigned UNIT ccnt; 406*4510Speter double time; 407*4510Speter unsigned long pcl, pch; 408*4510Speter register int i; 409*4510Speter int overlap; 410*4510Speter unsigned long svalue0, svalue1; 411*4510Speter 412*4510Speter /* read samples and assign to namelist symbols */ 413*4510Speter scale = highpc - lowpc; 414*4510Speter scale /= nsamples; 415*4510Speter for (i=0; i < nsamples; i++) { 416*4510Speter ccnt = samples[i]; 417*4510Speter if (ccnt == 0) 418*4510Speter continue; 419*4510Speter pcl = lowpc + scale*i; 420*4510Speter pch = lowpc + scale*(i+1); 421*4510Speter time = ccnt; 422*4510Speter # ifdef DEBUG 423*4510Speter if ( debug & SAMPLEDEBUG ) { 424*4510Speter printf( "[asgnsamples] ccnt %d time %f totime %f\n" , 425*4510Speter ccnt , time , totime ); 426*4510Speter } 427*4510Speter # endif DEBUG 428*4510Speter totime += time; 429*4510Speter for (j=0; j<nname; j++) { 430*4510Speter svalue0 = nl[j].value / sizeof(UNIT); 431*4510Speter svalue1 = nl[j+1].value / sizeof(UNIT); 432*4510Speter if (pch < svalue0) 433*4510Speter break; 434*4510Speter if (pcl >= svalue1) 435*4510Speter continue; 436*4510Speter overlap=min(pch,svalue1) - max(pcl,svalue0); 437*4510Speter if (overlap>0) { 438*4510Speter # ifdef DEBUG 439*4510Speter if ( debug & SAMPLEDEBUG ) { 440*4510Speter printf( "[asgnsamples] %s gets %f ticks\n" , 441*4510Speter nl[j].name , overlap*time/scale ); 442*4510Speter } 443*4510Speter # endif DEBUG 444*4510Speter nl[j].time += overlap*time/scale; 445*4510Speter } 446*4510Speter } 447*4510Speter } 448*4510Speter # ifdef DEBUG 449*4510Speter if ( debug & SAMPLEDEBUG ) { 450*4510Speter printf( "[asgnsamples] totime %f\n" , totime ); 451*4510Speter } 452*4510Speter # endif DEBUG 453*4510Speter if (totime==0.0) { 454*4510Speter fprintf( stderr , "No time accumulated\n" ); 455*4510Speter totime=1.0; 456*4510Speter } 457*4510Speter } 458*4510Speter 459*4510Speter 460*4510Speter min(a, b) 461*4510Speter unsigned a,b; 462*4510Speter { 463*4510Speter if (a<b) 464*4510Speter return(a); 465*4510Speter return(b); 466*4510Speter } 467*4510Speter 468*4510Speter max(a, b) 469*4510Speter unsigned a,b; 470*4510Speter { 471*4510Speter if (a>b) 472*4510Speter return(a); 473*4510Speter return(b); 474*4510Speter } 475*4510Speter 476*4510Speter timecmp( npp1 , npp2 ) 477*4510Speter nltype **npp1, **npp2; 478*4510Speter { 479*4510Speter double d; 480*4510Speter 481*4510Speter d = (*npp2)->time - (*npp1)->time; 482*4510Speter if (d > 0.0) 483*4510Speter return(1); 484*4510Speter if (d < 0.0) 485*4510Speter return(-1); 486*4510Speter return(strcmp((*npp1)->name,(*npp2)->name)); 487*4510Speter } 488*4510Speter 489*4510Speter done() 490*4510Speter { 491*4510Speter 492*4510Speter exit(0); 493*4510Speter } 494