1: #ifndef lint
   2: static  char *sccsid = "@(#)prof.c	4.4 (Berkeley) 3/24/85";
   3: #endif
   4: /*
   5:  * prof
   6:  */
   7: #include <stdio.h>
   8: #include <sys/types.h>
   9: #include <sys/stat.h>
  10: #include <a.out.h>
  11: #include <sys/time.h>
  12: 
  13: typedef short UNIT;     /* unit of profiling */
  14: #define PCFUDGE     11
  15: #define A_OUTNAME   "a.out"
  16: #define MON_OUTNAME "mon.out"
  17: #define MON_SUMNAME "mon.sum"
  18: 
  19: /*
  20:  * The symbol table;
  21:  * for each external in the specified file we gather
  22:  * its address, the number of calls and compute its share of cpu time.
  23:  */
  24: struct nl {
  25:     char    *name;
  26:     unsigned value;
  27:     float   time;
  28:     long    ncall;
  29: } *nl;
  30: int nname;
  31: struct  nl *np;
  32: struct  nl *npe;
  33: 
  34: /*
  35:  * The header on the mon.out file.
  36:  * Mon.out consists of one of these headers, an array of ncount
  37:  * cnt structures (as below) and then an array of samples
  38:  * representing the discretized program counter values.
  39:  */
  40: struct hdr {
  41:     UNIT    *lowpc, *highpc;
  42:     int ncount;
  43: } h;
  44: 
  45: /*
  46:  * Each counter has an address and a number of calls.
  47:  */
  48: struct cnt {
  49:     unsigned cvalue;
  50:     long    cncall;
  51: } *cbuf;
  52: 
  53: /*
  54:  * Each discretized pc sample has
  55:  * a count of the number of samples in its range
  56:  */
  57: unsigned UNIT   *samples;
  58: 
  59: FILE    *pfile, *nfile;
  60: 
  61: unsigned lowpc, highpc;     /* range profiled */
  62: double  ransca, ranoff;     /* scaling for blowing up plots */
  63: unsigned sampbytes;     /* number of bytes of samples */
  64: int nsamples;       /* number of samples */
  65: double  totime;         /* total time for all routines */
  66: double  maxtime;        /* maximum time of any routine (for plot) */
  67: double  scale;          /* scale factor converting samples to pc
  68: 				   values: each sample covers scale bytes */
  69: char    *strtab;        /* string table in core */
  70: off_t   ssiz;           /* size of the string table */
  71: struct  exec xbuf;      /* exec header of a.out */
  72: 
  73: int aflg;
  74: int nflg;
  75: int vflg;
  76: int lflg;
  77: int zflg;
  78: int sflag;
  79: 
  80: char    *namfil;
  81: 
  82: int timcmp(), valcmp(), cntcmp();
  83: 
  84: main(argc, argv)
  85:     char **argv;
  86: {
  87:     int lowpct, highpct;
  88: 
  89:     /*
  90: 	 * Use highpct and lowpc as percentages, temporarily
  91: 	 * for graphing options involving blow-up
  92: 	 */
  93:     lowpct = -1;
  94:     highpct = -1;
  95:     argv++;
  96:     while ( *argv != 0 && **argv == '-' ) {
  97:         *argv += 1;
  98:         if (**argv == 'l')
  99:             lflg++;
 100:         else if (**argv == 'a')
 101:             aflg++;
 102:         else if (**argv == 'n')
 103:             nflg++;
 104:         else if (**argv == 'z')
 105:             zflg++;
 106:         else if (**argv == 'v')
 107:             vflg++;
 108:         else if ( **argv == 's' )
 109:             sflag++;
 110:         else if (**argv >= '0' && **argv <= '9') {
 111:             int i = atoi(*argv);
 112:             if (lowpct == -1)
 113:                 lowpct = i;
 114:             else
 115:                 highpct = i;
 116:         }
 117:         argv++;
 118:     }
 119:     if ( *argv != 0 ) {
 120:         namfil = *argv;
 121:         argv++;
 122:     } else {
 123:         namfil = A_OUTNAME;
 124:     }
 125:     if (lowpct >= 100)
 126:         lowpct = 0;
 127:     if (highpct <= lowpct || highpct > 100)
 128:         highpct = 100;
 129:     ransca = 100./(highpct-lowpct);
 130:     ranoff = 2040. + 40.8*lowpc*ransca;
 131:         /*
 132: 		 *	get information about a.out file.
 133: 		 */
 134:     getnfile();
 135:         /*
 136: 		 *	get information about mon.out file(s).
 137: 		 */
 138:     if ( *argv == 0 ) {
 139:         getpfile( MON_OUTNAME );
 140:     } else {
 141:         do {
 142:             getpfile( *argv );
 143:             argv++;
 144:         } while ( *argv != 0 );
 145:     }
 146:     asgnsamples();      /* assign samples to procedures */
 147: #ifdef plot
 148:     if (vflg)
 149:         plotprof(); /* a plotted or ... */
 150:     else
 151: #endif
 152:         printprof();    /* a printed profile */
 153:     if ( sflag != 0 ) {
 154:         putprof();
 155:     }
 156:     done();
 157: }
 158: 
 159: printprof()
 160: {
 161:     double time, actime, hz;
 162: 
 163:     actime = 0;
 164:     hz = hertz();
 165:     printf(" %%time  cumsecs  #call  ms/call  name\n");
 166:     if (!lflg)
 167:         qsort(nl, nname, sizeof(struct nl), timcmp);
 168:     for (np = nl; np<npe-1; np++) {
 169:         if (zflg == 0 && np->time == 0 && np->ncall == 0)
 170:             continue;
 171:         time = np->time/totime;
 172:         actime += np->time;
 173:         printf("%6.1f%9.2f", 100*time, actime/hz);
 174:         if (np->ncall != 0)
 175:             printf("%7ld %8.2f",
 176:                 np->ncall, (np->time*1000/hz)/np->ncall);
 177:         else
 178:             printf("%7.7s %8.8s", "", "");
 179:         printf("  %s\n", np->name);
 180:     }
 181: }
 182: 
 183: /*
 184:  * Set up string and symbol tables from a.out.
 185:  * On return symbol table is sorted by value.
 186:  */
 187: getnfile()
 188: {
 189: 
 190:     nfile = fopen(namfil,"r");
 191:     if (nfile == NULL) {
 192:         perror(namfil);
 193:         done();
 194:     }
 195:     fread(&xbuf, 1, sizeof(xbuf), nfile);
 196:     if (N_BADMAG(xbuf)) {
 197:         fprintf(stderr, "%s: bad format\n", namfil);
 198:         done();
 199:     }
 200:     getstrtab();
 201:     getsymtab();
 202:     qsort(nl, nname, sizeof(struct nl), valcmp);
 203: }
 204: 
 205: getstrtab()
 206: {
 207: 
 208:     fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0);
 209:     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
 210:         fprintf(stderr, "%s: no string table (old format?)\n", namfil);
 211:         done();
 212:     }
 213:     strtab = (char *)calloc(ssiz, 1);
 214:     if (strtab == NULL) {
 215:         fprintf(stderr, "%s: no room for %d bytes of string table",
 216:             namfil, ssiz);
 217:         done();
 218:     }
 219:     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
 220:         fprintf(stderr, "%s: error reading string table\n", namfil);
 221:         done();
 222:     }
 223: }
 224: 
 225: /*
 226:  * Read in symbol table
 227:  */
 228: getsymtab()
 229: {
 230:     register int i;
 231: 
 232:     /* pass1 - count symbols */
 233:     fseek(nfile, N_SYMOFF(xbuf), 0);
 234:     nname = 0;
 235:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
 236:         struct nlist nbuf;
 237:         fread(&nbuf, sizeof(nbuf), 1, nfile);
 238:         if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
 239:             continue;
 240:         if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
 241:             continue;
 242:         nname++;
 243:     }
 244:     if (nname == 0) {
 245:         fprintf(stderr, "%s: no symbols\n", namfil);
 246:         done();
 247:     }
 248:     nl = (struct nl *)calloc((nname+1), sizeof (struct nl));
 249:     if (nl == 0) {
 250:         fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
 251:             (nname+1) * sizeof (struct nlist));
 252:         done();
 253:     }
 254: 
 255:     /* pass2 - read symbols */
 256:     fseek(nfile, N_SYMOFF(xbuf), 0);
 257:     npe = nl;
 258:     nname = 0;
 259:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
 260:         struct nlist nbuf;
 261:         fread(&nbuf, sizeof(nbuf), 1, nfile);
 262:         if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
 263:             continue;
 264:         if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
 265:             continue;
 266:         npe->value = nbuf.n_value/sizeof(UNIT);
 267:         npe->name = strtab+nbuf.n_un.n_strx;
 268:         npe++;
 269:         nname++;
 270:     }
 271:     npe->value = -1;
 272:     npe++;
 273: }
 274: 
 275: /*
 276:  * information from a mon.out file is in two parts:
 277:  * the counters of how many times each procedure was called,
 278:  * if it was called at all;
 279:  * and an array of sampling hits within pc ranges.
 280:  * the counters must be dealt with on a file-by-file basis,
 281:  * since which procedures are represented may vary.
 282:  * the samples ranges are fixed, but must be summed across
 283:  * files, and then distributed among procedures, because
 284:  * of the wierd way the plotting is done.
 285:  */
 286: getpfile(filename)
 287:     char *filename;
 288: {
 289: 
 290:     openpfile(filename);
 291:     readcntrs();
 292:     asgncntrs();        /* assign counts to procedures */
 293:     readsamples();
 294:     closepfile();
 295: }
 296: 
 297: openpfile(filename)
 298:     char *filename;
 299: {
 300:     struct stat stb;
 301: 
 302:     if((pfile = fopen(filename, "r")) == NULL) {
 303:         perror(filename);
 304:         done();
 305:     }
 306:     fstat(fileno(pfile), &stb);
 307:     fread(&h, sizeof(struct hdr), 1, pfile);
 308:     lowpc = h.lowpc - (UNIT *)0;
 309:     highpc = h.highpc - (UNIT *)0;
 310:     sampbytes =
 311:         stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt);
 312:     nsamples = sampbytes / sizeof (unsigned UNIT);
 313: }
 314: 
 315: closepfile()
 316: {
 317: 
 318:     fclose(pfile);
 319:     free(cbuf);
 320: }
 321: 
 322: readcntrs()
 323: {
 324:     struct cnt *kp;
 325: 
 326:     cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt));
 327:     if (cbuf == 0) {
 328:         fprintf(stderr, "prof: No room for %d bytes of count buffer\n",
 329:             (h.ncount+1) * sizeof (struct cnt));
 330:         exit(1);
 331:     }
 332:     fread(cbuf, sizeof(struct cnt), h.ncount, pfile);
 333:     /* eliminate zero counters and scale counter pc values */
 334:     if (h.ncount) {
 335:         kp = &cbuf[h.ncount - 1];
 336:         for (;;) {
 337:             if (kp->cvalue==0) {
 338:                 h.ncount=kp-cbuf;
 339:                 ++kp;
 340:                 break;
 341:             }
 342:             if (kp == cbuf) {
 343:                 h.ncount = 0;
 344:                 break;
 345:             }
 346:             --kp;
 347:         }
 348:         for (; --kp>=cbuf; )
 349:             kp->cvalue /= sizeof(UNIT);
 350:     }
 351:     /* sort counters */
 352:     qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp);
 353: }
 354: 
 355: /*
 356:  * Assign counters to the procedures to which they belong
 357:  */
 358: asgncntrs()
 359: {
 360:     register int i;
 361:     struct cnt *kp;
 362: 
 363:     kp = &cbuf[h.ncount-1];
 364:     np = npe;
 365:     while (--np>=nl) {
 366:         if (kp<cbuf || np->value > kp->cvalue)
 367:             continue;
 368:             /* skip ``static'' functions */
 369:         while (kp >= cbuf && kp->cvalue > np->value + PCFUDGE)
 370:             --kp;
 371:         if (kp->cvalue >= np->value) {
 372:             np->ncall += kp->cncall;
 373:             --kp;
 374:         }
 375:     }
 376: }
 377: 
 378: readsamples()
 379: {
 380:     register i;
 381:     unsigned UNIT   sample;
 382:     int totalt;
 383: 
 384:     if (samples == 0) {
 385:         samples = (unsigned UNIT *)
 386:             calloc(sampbytes, sizeof (unsigned UNIT));
 387:         if (samples == 0) {
 388:             printf("prof: No room for %d sample pc's\n",
 389:                 sampbytes / sizeof (unsigned UNIT));
 390:             done();
 391:         }
 392:     }
 393:     for (i = 0; ; i++) {
 394:         fread(&sample, sizeof (unsigned UNIT), 1, pfile);
 395:         if (feof(pfile))
 396:             break;
 397:         samples[i] += sample;
 398:         totalt += sample;
 399:     }
 400:     if (i != nsamples) {
 401:         fprintf(stderr,
 402:             "prof: unexpected EOF after reading %d/%d samples\n",
 403:             --i, nsamples);
 404:         done();
 405:     }
 406: }
 407: 
 408: /*
 409:  * Assign samples to the procedures to which they belong.
 410:  */
 411: asgnsamples()
 412: {
 413:     register j;
 414:     unsigned UNIT   ccnt;
 415:     double time;
 416:     unsigned pcl, pch;
 417:     register int i;
 418:     int overlap;
 419: 
 420:     /* read samples and assign to namelist symbols */
 421:     scale = highpc - lowpc;
 422:     scale /= nsamples;
 423:     for (i=0; i < nsamples; i++) {
 424:         ccnt = samples[i];
 425:         if (ccnt == 0)
 426:             continue;
 427:         pcl = lowpc + scale*i;
 428:         pch = lowpc + scale*(i+1);
 429:         time = ccnt;
 430:         totime += time;
 431:         if(time > maxtime)
 432:             maxtime = time;
 433:         for (j=0; j<nname; j++) {
 434:             if (pch < nl[j].value)
 435:                 break;
 436:             if (pcl >= nl[j+1].value)
 437:                 continue;
 438:             overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value));
 439:             if (overlap>0)
 440:                 nl[j].time += overlap*time/scale;
 441:         }
 442:     }
 443:     if (totime==0.0) {
 444:         fprintf(stderr, "No time accumulated\n");
 445: /*
 446: 		done();
 447:  */
 448:         totime=1.0;
 449:     }
 450: }
 451: 
 452: /*
 453:  * dump what you have out to a mon.out style file.
 454:  */
 455: putprof()
 456: {
 457:     FILE *sfile;
 458:     struct nl *np;
 459:     struct cnt kp;
 460:     int i;
 461: 
 462:     sfile = fopen(MON_SUMNAME, "w");
 463:     if (sfile == NULL) {
 464:         perror(MON_SUMNAME);
 465:         done();
 466:     }
 467:     /*
 468: 	 * build a new header.
 469: 	 * h.lowpc and h.highpc are already fine.
 470: 	 * fix h.ncount to count non-zero calls,
 471: 	 * and the one zero call which marks the end.
 472: 	 */
 473:     h.ncount = 0;
 474:     for (np = nl; np < npe-1 ; np++)
 475:         if (np->ncall > 0)
 476:             h.ncount++;
 477:     h.ncount++;
 478:     fwrite(&h, sizeof (struct hdr), 1, sfile);
 479:     for (np = nl; np < npe-1; np++) {
 480:         if (np->ncall > 0) {
 481:             kp.cvalue = np->value * sizeof (unsigned UNIT);
 482:             kp.cncall = np->ncall;
 483:             fwrite(&kp, sizeof (struct cnt), 1, sfile);
 484:         }
 485:     }
 486:     kp.cvalue = 0;
 487:     kp.cncall = 0;
 488:     fwrite(&kp, sizeof (struct cnt), 1, sfile);
 489:     fwrite(samples, sizeof (unsigned UNIT), nsamples, sfile);
 490:     fclose(sfile);
 491: }
 492: 
 493: /*
 494:  *	discover the tick frequency of the machine
 495:  *	if something goes wrong, we return 1.
 496:  */
 497: hertz()
 498: {
 499:     struct itimerval tim;
 500: 
 501:     tim.it_interval.tv_sec = 0;
 502:     tim.it_interval.tv_usec = 1;
 503:     tim.it_value.tv_sec = 0;
 504:     tim.it_value.tv_usec = 0;
 505:     setitimer(ITIMER_REAL, &tim, 0);
 506:     setitimer(ITIMER_REAL, 0, &tim);
 507:     if (tim.it_interval.tv_usec < 1)
 508:         return (1);
 509:     return (1000000 / tim.it_interval.tv_usec);
 510: }
 511: 
 512: min(a, b)
 513: {
 514:     if (a<b)
 515:         return(a);
 516:     return(b);
 517: }
 518: 
 519: max(a, b)
 520: {
 521:     if (a>b)
 522:         return(a);
 523:     return(b);
 524: }
 525: 
 526: valcmp(p1, p2)
 527:     struct nl *p1, *p2;
 528: {
 529: 
 530:     return(p1->value - p2->value);
 531: }
 532: 
 533: timcmp(p1, p2)
 534:     struct nl *p1, *p2;
 535: {
 536:     float d;
 537: 
 538:     if (nflg && p2->ncall != p1->ncall)
 539:         return (p2->ncall - p1->ncall);
 540:     d = p2->time - p1->time;
 541:     if (d > 0.0)
 542:         return(1);
 543:     if (d < 0.0)
 544:         return(-1);
 545:     return(strcmp(p1->name,p2->name));
 546: }
 547: 
 548: cntcmp(p1, p2)
 549:     struct cnt *p1, *p2;
 550: {
 551: 
 552:     return(p1->cvalue - p2->cvalue);
 553: }
 554: 
 555: done()
 556: {
 557: 
 558: #ifdef plot
 559:     if(vflg) {
 560:         point(0, -2040);
 561:         closepl();
 562:     }
 563: #endif
 564:     exit(0);
 565: }
 566: 
 567: #ifdef plot
 568: plotprof()
 569: {
 570:     double time, lastx, lasty, lastsx;
 571:     register i;
 572: 
 573:     openpl();
 574:     erase();
 575:     space(-2048, -2048, 2048, 2048);
 576:     line(-2040, -2040, -2040, 2040);
 577:     line(0, 2040, 0, -2040);
 578:     for(i=0; i<11; i++)
 579:         line(-2040, 2040-i*408, 0, 2040-i*408);
 580:     lastx = 0.;
 581:     lasty = ranoff;
 582:     scale = (4080.*ransca)/(sampbytes/sizeof(UNIT));
 583:     lastsx = 0.0;
 584:     for(i = 0; i < nsamples; i++) {
 585:         unsigned UNIT ccnt;
 586:         double tx, ty;
 587:         ccnt = samples[i];
 588:         time = ccnt;
 589:         tx = lastsx;
 590:         ty = lasty;
 591:         lastsx -= 2000.*time/totime;
 592:         lasty -= scale;
 593:         if(lasty >= -2040. && ty <= 2040.) {
 594:             line((int)tx, (int)ty, (int)lastsx, (int)lasty);
 595:             if (ccnt!=0 || lastx!=0.0) {
 596:                 tx = lastx;
 597:                 lastx = -time*2000./maxtime;
 598:                 ty += scale/2;
 599:                 line(0, (int)ty, (int)tx, (int)ty);
 600:             }
 601:         }
 602:     }
 603:     scale = (4080.*ransca)/(highpc-lowpc);
 604:     lastx = 50.;
 605:     for(np = nl; np<npe;  np++) {
 606:         if(np->value < lowpc)
 607:             continue;
 608:         if(np->value >= highpc)
 609:             continue;
 610:         if(zflg == 0 && np->time == 0 && np->ncall == 0)
 611:             continue;
 612:         time = np->time/totime;
 613:         lasty = ranoff - (np->value - lowpc)*scale;
 614:         if(lasty >= -2040. && lasty <= 2040.) {
 615:             char bufl[BUFSIZ], *namp;
 616:             register j;
 617:             line(0, (int)lasty, 50, (int)lasty);
 618:             line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty);
 619:             move((int)(lastx+30), (int)(lasty+10));
 620:             sprintf(bufl, "%s", np->name + (np->name[0] == '_'));
 621:             label(bufl);
 622:         }
 623:         lastx += 500.;
 624:         if(lastx > 2000.)
 625:             lastx = 50.;
 626:     }
 627: }
 628: #endif

Defined functions

asgncntrs defined in line 358; used 1 times
asgnsamples defined in line 411; used 1 times
closepfile defined in line 315; used 1 times
cntcmp defined in line 548; used 2 times
done defined in line 555; used 12 times
getnfile defined in line 187; used 1 times
getpfile defined in line 286; used 2 times
getstrtab defined in line 205; used 1 times
getsymtab defined in line 228; used 1 times
hertz defined in line 497; used 1 times
main defined in line 84; never used
max defined in line 519; used 1 times
min defined in line 512; used 1 times
openpfile defined in line 297; used 1 times
plotprof defined in line 568; used 1 times
printprof defined in line 159; used 1 times
putprof defined in line 455; used 1 times
readcntrs defined in line 322; used 1 times
readsamples defined in line 378; used 1 times
timcmp defined in line 533; used 2 times
valcmp defined in line 526; used 2 times

Defined variables

aflg defined in line 73; used 3 times
cbuf defined in line 51; used 12 times
h defined in line 43; used 17 times
highpc defined in line 61; used 6 times
lflg defined in line 76; used 2 times
lowpc defined in line 61; used 10 times
maxtime defined in line 66; used 3 times
namfil defined in line 80; used 9 times
nflg defined in line 74; used 2 times
nl defined in line 29; used 15 times
nname defined in line 30; used 10 times
np defined in line 31; used 40 times
npe defined in line 32; used 11 times
nsamples defined in line 64; used 7 times
ranoff defined in line 62; used 3 times
ransca defined in line 62; used 4 times
sampbytes defined in line 63; used 5 times
samples defined in line 57; used 7 times
scale defined in line 67; used 10 times
sccsid defined in line 2; never used
sflag defined in line 78; used 2 times
strtab defined in line 69; used 4 times
totime defined in line 65; used 6 times
vflg defined in line 75; used 3 times
xbuf defined in line 71; used 9 times
zflg defined in line 77; used 3 times

Defined struct's

cnt defined in line 48; used 24 times
hdr defined in line 40; used 6 times
nl defined in line 24; used 18 times

Defined typedef's

UNIT defined in line 13; used 17 times

Defined macros

A_OUTNAME defined in line 15; used 1 times
MON_OUTNAME defined in line 16; used 1 times
MON_SUMNAME defined in line 17; used 2 times
PCFUDGE defined in line 14; used 1 times
Last modified: 1985-03-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2559
Valid CSS Valid XHTML 1.0 Strict