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