|
|
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: * `UNIT *' in the file is a bad mistake; see openpfile below. ! 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*lowpct*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, nlen; ! 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; ! 265: npe->name = strtab+nbuf.n_un.n_strx; ! 266: nlen=strlen(npe->name); ! 267: if(nlen<2 || npe->name[nlen-2]!='.' || npe->name[nlen-1]!='o'){ ! 268: npe++; ! 269: nname++; ! 270: } ! 271: } ! 272: npe->value = -1; ! 273: npe++; ! 274: } ! 275: ! 276: /* ! 277: * information from a mon.out file is in two parts: ! 278: * the counters of how many times each procedure was called, ! 279: * if it was called at all; ! 280: * and an array of sampling hits within pc ranges. ! 281: * the counters must be dealt with on a file-by-file basis, ! 282: * since which procedures are represented may vary. ! 283: * the samples ranges are fixed, but must be summed across ! 284: * files, and then distributed among procedures, because ! 285: * of the wierd way the plotting is done. ! 286: */ ! 287: getpfile(filename) ! 288: char *filename; ! 289: { ! 290: ! 291: openpfile(filename); ! 292: readcntrs(); ! 293: asgncntrs(); /* assign counts to procedures */ ! 294: readsamples(); ! 295: closepfile(); ! 296: } ! 297: ! 298: /* ! 299: * beware the scaling below, to calculate highpc and lowpc. ! 300: * it attempts to turn the pointers into something real. ! 301: * the sign bit gets botched and unbotched again. ! 302: * in truth, UNIT * should be some well-defined integer offset instead. ! 303: */ ! 304: openpfile(filename) ! 305: char *filename; ! 306: { ! 307: struct stat stb; ! 308: ! 309: if((pfile = fopen(filename, "r")) == NULL) { ! 310: perror(filename); ! 311: done(); ! 312: } ! 313: fstat(fileno(pfile), &stb); ! 314: fread(&h, sizeof(struct hdr), 1, pfile); ! 315: lowpc = (h.lowpc - (UNIT *)0) * sizeof(UNIT); ! 316: highpc = (h.highpc - (UNIT *)0) * sizeof(UNIT); ! 317: nsamples = (stb.st_size-sizeof(struct hdr)-h.ncount*sizeof(struct cnt)) ! 318: /sizeof(unsigned UNIT); ! 319: } ! 320: ! 321: closepfile() ! 322: { ! 323: ! 324: fclose(pfile); ! 325: free(cbuf); ! 326: } ! 327: ! 328: readcntrs() ! 329: { ! 330: struct cnt *kp; ! 331: ! 332: cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt)); ! 333: if (cbuf == 0) { ! 334: fprintf(stderr, "prof: No room for %d bytes of count buffer\n", ! 335: (h.ncount+1) * sizeof (struct cnt)); ! 336: exit(1); ! 337: } ! 338: fread(cbuf, sizeof(struct cnt), h.ncount, pfile); ! 339: /* eliminate zero counters */ ! 340: if (h.ncount) { ! 341: kp = &cbuf[h.ncount - 1]; ! 342: while (kp->cvalue == 0 && kp > cbuf) ! 343: kp--; ! 344: h.ncount = kp-cbuf+1; ! 345: } ! 346: /* sort counters */ ! 347: qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp); ! 348: } ! 349: ! 350: /* ! 351: * Assign counters to the procedures to which they belong ! 352: */ ! 353: asgncntrs() ! 354: { ! 355: register int i; ! 356: register struct cnt *kp; ! 357: ! 358: kp = &cbuf[h.ncount-1]; ! 359: np = npe; ! 360: while (--np>=nl) { ! 361: if (kp<cbuf || np->value > kp->cvalue) ! 362: continue; ! 363: /* skip nameless functions */ ! 364: if (kp->cvalue >= np->value) { ! 365: do { ! 366: --kp; ! 367: } while (kp >= cbuf && kp->cvalue >= np->value); ! 368: np->ncall += (kp+1)->cncall; ! 369: } ! 370: } ! 371: } ! 372: ! 373: readsamples() ! 374: { ! 375: register i; ! 376: unsigned UNIT sample; ! 377: int totalt; ! 378: ! 379: if (samples == 0) { ! 380: samples = (unsigned UNIT *) ! 381: calloc(nsamples, sizeof (unsigned UNIT)); ! 382: if (samples == 0) { ! 383: printf("prof: No room for %d sample pc's\n", nsamples); ! 384: done(); ! 385: } ! 386: } ! 387: for (i = 0; ; i++) { ! 388: fread(&sample, sizeof (unsigned UNIT), 1, pfile); ! 389: if (feof(pfile)) ! 390: break; ! 391: samples[i] += sample; ! 392: totalt += sample; ! 393: } ! 394: if (i != nsamples) { ! 395: fprintf(stderr, ! 396: "prof: unexpected EOF after reading %d/%d samples\n", ! 397: --i, nsamples); ! 398: done(); ! 399: } ! 400: } ! 401: ! 402: /* ! 403: * Assign samples to the procedures to which they belong. ! 404: */ ! 405: asgnsamples() ! 406: { ! 407: register j; ! 408: unsigned UNIT ccnt; ! 409: double time; ! 410: unsigned pcl, pch; ! 411: register int i; ! 412: int overlap; ! 413: ! 414: /* read samples and assign to namelist symbols */ ! 415: scale = highpc - lowpc; ! 416: scale /= nsamples; ! 417: for (i=0; i < nsamples; i++) { ! 418: ccnt = samples[i]; ! 419: if (ccnt == 0) ! 420: continue; ! 421: pcl = lowpc + scale*i; ! 422: pch = lowpc + scale*(i+1); ! 423: time = ccnt; ! 424: totime += time; ! 425: if(time > maxtime) ! 426: maxtime = time; ! 427: for (j=0; j<nname; j++) { ! 428: if (pch < nl[j].value) ! 429: break; ! 430: if (pcl >= nl[j+1].value) ! 431: continue; ! 432: overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value)); ! 433: if (overlap>0) ! 434: nl[j].time += overlap*time/scale; ! 435: } ! 436: } ! 437: if (totime==0.0) { ! 438: fprintf(stderr, "No time accumulated\n"); ! 439: /* ! 440: done(); ! 441: */ ! 442: totime=1.0; ! 443: } ! 444: } ! 445: ! 446: /* ! 447: * dump what you have out to a mon.out style file. ! 448: */ ! 449: putprof() ! 450: { ! 451: FILE *sfile; ! 452: struct nl *np; ! 453: struct cnt kp; ! 454: int i; ! 455: ! 456: sfile = fopen(MON_SUMNAME, "w"); ! 457: if (sfile == NULL) { ! 458: perror(MON_SUMNAME); ! 459: done(); ! 460: } ! 461: /* ! 462: * build a new header. ! 463: * h.lowpc and h.highpc are already fine. ! 464: * fix h.ncount to count non-zero calls, ! 465: * and the one zero call which marks the end. ! 466: */ ! 467: h.ncount = 0; ! 468: for (np = nl; np < npe-1 ; np++) ! 469: if (np->ncall > 0) ! 470: h.ncount++; ! 471: h.ncount++; ! 472: fwrite(&h, sizeof (struct hdr), 1, sfile); ! 473: for (np = nl; np < npe-1; np++) { ! 474: if (np->ncall > 0) { ! 475: kp.cvalue = np->value; ! 476: kp.cncall = np->ncall; ! 477: fwrite(&kp, sizeof (struct cnt), 1, sfile); ! 478: } ! 479: } ! 480: kp.cvalue = 0; ! 481: kp.cncall = 0; ! 482: fwrite(&kp, sizeof (struct cnt), 1, sfile); ! 483: fwrite(samples, sizeof (unsigned UNIT), nsamples, sfile); ! 484: fclose(sfile); ! 485: } ! 486: ! 487: min(a, b) ! 488: { ! 489: if (a<b) ! 490: return(a); ! 491: return(b); ! 492: } ! 493: ! 494: max(a, b) ! 495: { ! 496: if (a>b) ! 497: return(a); ! 498: return(b); ! 499: } ! 500: ! 501: valcmp(p1, p2) ! 502: struct nl *p1, *p2; ! 503: { ! 504: ! 505: return(p1->value - p2->value); ! 506: } ! 507: ! 508: timcmp(p1, p2) ! 509: struct nl *p1, *p2; ! 510: { ! 511: float d; ! 512: ! 513: if (nflg && p2->ncall != p1->ncall) ! 514: return (p2->ncall - p1->ncall); ! 515: d = p2->time - p1->time; ! 516: if (d > 0.0) ! 517: return(1); ! 518: if (d < 0.0) ! 519: return(-1); ! 520: return(strcmp(p1->name,p2->name)); ! 521: } ! 522: ! 523: cntcmp(p1, p2) ! 524: struct cnt *p1, *p2; ! 525: { ! 526: ! 527: return(p1->cvalue - p2->cvalue); ! 528: } ! 529: ! 530: done() ! 531: { ! 532: ! 533: #ifdef plot ! 534: if(vflg) { ! 535: point(0, -2040); ! 536: closepl(); ! 537: } ! 538: #endif ! 539: exit(0); ! 540: } ! 541: ! 542: #ifdef plot ! 543: plotprof() ! 544: { ! 545: double time, lastx, lasty, lastsx; ! 546: register i; ! 547: ! 548: openpl(); ! 549: erase(); ! 550: range(-2048, -2048, 2048, 2048); ! 551: line(-2040, -2040, -2040, 2040); ! 552: line(0, 2040, 0, -2040); ! 553: for(i=0; i<11; i++) ! 554: line(-2040, 2040-i*408, 0, 2040-i*408); ! 555: lastx = 0.; ! 556: lasty = ranoff; ! 557: scale = (4080.*ransca)/nsamples; ! 558: lastsx = 0.0; ! 559: for(i = 0; i < nsamples; i++) { ! 560: unsigned UNIT ccnt; ! 561: double tx, ty; ! 562: ccnt = samples[i]; ! 563: time = ccnt; ! 564: tx = lastsx; ! 565: ty = lasty; ! 566: lastsx -= 2000.*time/totime; ! 567: lasty -= scale; ! 568: if(lasty >= -2040. && ty <= 2040.) { ! 569: line((int)tx, (int)ty, (int)lastsx, (int)lasty); ! 570: if (ccnt!=0 || lastx!=0.0) { ! 571: tx = lastx; ! 572: lastx = -time*2000./maxtime; ! 573: ty += scale/2; ! 574: line(0, (int)ty, (int)tx, (int)ty); ! 575: } ! 576: } ! 577: } ! 578: scale = (4080.*ransca)/(highpc-lowpc); ! 579: lastx = 50.; ! 580: for(np = nl; np<npe; np++) { ! 581: if(np->value < lowpc) ! 582: continue; ! 583: if(np->value >= highpc) ! 584: continue; ! 585: time = np->time/totime; ! 586: lasty = ranoff - (np->value - lowpc)*scale; ! 587: if(lasty >= -2040. && lasty <= 2040.) { ! 588: char bufl[BUFSIZ], *namp; ! 589: register j; ! 590: line(0, (int)lasty, 50, (int)lasty); ! 591: line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty); ! 592: move((int)(lastx+30), (int)(lasty+10)); ! 593: sprintf(bufl, "%s", np->name + (np->name[0] == '_')); ! 594: text(bufl); ! 595: } ! 596: lastx += 500.; ! 597: if(lastx > 2500.) ! 598: lastx = 50.; ! 599: } ! 600: } ! 601: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.