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

Defined functions

asgncntrs defined in line 362; used 1 times
asgnsamples defined in line 413; used 1 times
closepfile defined in line 319; used 1 times
cntcmp defined in line 554; used 2 times
done defined in line 561; used 12 times
getnfile defined in line 192; used 1 times
getpfile defined in line 290; used 2 times
getstrtab defined in line 210; used 1 times
getsymtab defined in line 233; used 1 times
hertz defined in line 499; used 1 times
main defined in line 89; never used
max defined in line 519; used 1 times
min defined in line 512; used 1 times
openpfile defined in line 301; used 1 times
plotprof defined in line 574; used 1 times
printprof defined in line 164; used 1 times
putprof defined in line 457; used 1 times
readcntrs defined in line 326; used 1 times
readsamples defined in line 383; 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 78; used 3 times
cbuf defined in line 56; used 12 times
h defined in line 48; used 17 times
highpc defined in line 66; used 6 times
lflg defined in line 81; used 2 times
lowpc defined in line 66; used 10 times
maxtime defined in line 71; used 3 times
namfil defined in line 85; used 9 times
nflg defined in line 79; used 2 times
nl defined in line 34; used 15 times
nname defined in line 35; used 8 times
np defined in line 36; used 40 times
npe defined in line 37; used 11 times
nsamples defined in line 69; used 10 times
ranoff defined in line 67; used 3 times
ransca defined in line 67; used 4 times
sampbytes defined in line 68; used 2 times
samples defined in line 62; used 7 times
scale defined in line 72; used 10 times
sccsid defined in line 2; never used
sflag defined in line 83; used 2 times
ssiz defined in line 75; used 8 times
strtab defined in line 74; used 4 times
totime defined in line 70; used 6 times
vflg defined in line 80; used 3 times
xbuf defined in line 76; used 7 times
zflg defined in line 82; used 3 times

Defined struct's

cnt defined in line 53; used 24 times
hdr defined in line 45; used 6 times
nl defined in line 29; used 18 times

Defined typedef's

UNIT defined in line 13; used 15 times

Defined macros

A_OUTNAME defined in line 20; used 1 times
MON_OUTNAME defined in line 21; used 1 times
MON_SUMNAME defined in line 22; used 2 times
PCFUDGE defined in line 17; used 1 times
Last modified: 1997-02-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5737
Valid CSS Valid XHTML 1.0 Strict