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