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