|
|
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: #include <pagsiz.h> ! 9: ! 10: typedef short UNIT; /* unit of profiling */ ! 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 (vflag) ! 145: plotprof(); /* a plotted or ... */ ! 146: else ! 147: #else ! 148: printprof(); /* a printed profile */ ! 149: #endif ! 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 amoung procedures, because ! 280: * of the wierd way the plotting is done. ! 281: */ ! 282: getpfile( filename ) ! 283: char *filename; ! 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); ! 307: nsamples = sampbytes / sizeof (unsigned UNIT); ! 308: } ! 309: ! 310: closepfile() ! 311: { ! 312: ! 313: fclose( pfile ); ! 314: free( cbuf ); ! 315: } ! 316: ! 317: /* ! 318: * read in procedure call counters ! 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: while (kp >= cbuf && kp->cvalue - np->value > 11) ! 367: --kp; ! 368: if (kp->cvalue >= np->value) { ! 369: np->ncall += kp->cncall; ! 370: --kp; ! 371: } ! 372: } ! 373: } ! 374: ! 375: /* ! 376: * read pc samples ! 377: */ ! 378: readsamples() ! 379: { ! 380: register i; ! 381: unsigned UNIT sample; ! 382: ! 383: if ( samples == 0 ) { ! 384: samples = (unsigned UNIT *) ! 385: calloc( sampbytes , sizeof (unsigned UNIT) ); ! 386: if ( samples == 0 ) { ! 387: printf( "prof: No room for %d sample pc's\n" , ! 388: sampbytes / sizeof (unsigned UNIT) ); ! 389: done(); ! 390: } ! 391: } ! 392: for ( i = 0 ; ; i++ ) { ! 393: fread( &sample , sizeof (unsigned UNIT) , 1 , pfile ); ! 394: if ( feof( pfile ) ) { ! 395: break; ! 396: } ! 397: samples[ i ] += sample; ! 398: } ! 399: if ( i != nsamples ) { ! 400: fprintf( stderr , ! 401: "prof: unexpected EOF after reading %d/%d samples\n" , ! 402: --i , nsamples ); ! 403: done(); ! 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: } ! 476: } ! 477: h.ncount++; ! 478: fwrite( &h , sizeof (struct hdr) , 1 , sfile ); ! 479: /* ! 480: * write out the counters ! 481: */ ! 482: for ( np = nl ; np < npe - 1 ; np++ ) { ! 483: if ( np -> ncall > 0 ) { ! 484: kp.cvalue = np -> value * sizeof (unsigned UNIT); ! 485: kp.cncall = np -> ncall; ! 486: fwrite( &kp , sizeof (struct cnt) , 1 , sfile ); ! 487: } ! 488: } ! 489: kp.cvalue = 0; ! 490: kp.cncall = 0; ! 491: fwrite( &kp , sizeof (struct cnt) , 1 , sfile ); ! 492: /* ! 493: * write out the samples ! 494: */ ! 495: fwrite( samples , sizeof (unsigned UNIT) , nsamples , sfile ); ! 496: fclose( sfile ); ! 497: } ! 498: ! 499: min(a, b) ! 500: { ! 501: if (a<b) ! 502: return(a); ! 503: return(b); ! 504: } ! 505: ! 506: max(a, b) ! 507: { ! 508: if (a>b) ! 509: return(a); ! 510: return(b); ! 511: } ! 512: ! 513: valcmp(p1, p2) ! 514: struct nl *p1, *p2; ! 515: { ! 516: ! 517: return(p1->value - p2->value); ! 518: } ! 519: ! 520: timcmp(p1, p2) ! 521: struct nl *p1, *p2; ! 522: { ! 523: float d; ! 524: ! 525: if (nflg && p2->ncall != p1->ncall) ! 526: return (p2->ncall - p1->ncall); ! 527: d = p2->time - p1->time; ! 528: if (d > 0.0) ! 529: return(1); ! 530: if (d < 0.0) ! 531: return(-1); ! 532: return(strcmp(p1->name,p2->name)); ! 533: } ! 534: ! 535: cntcmp(p1, p2) ! 536: struct cnt *p1, *p2; ! 537: { ! 538: ! 539: return(p1->cvalue - p2->cvalue); ! 540: } ! 541: ! 542: done() ! 543: { ! 544: ! 545: #ifdef plot ! 546: if(vflg) { ! 547: point(0, -2040); ! 548: closepl(); ! 549: } ! 550: #endif ! 551: exit(0); ! 552: } ! 553: ! 554: #ifdef plot ! 555: plotprof() ! 556: { ! 557: double time, lastx, lasty, lastsx; ! 558: register i; ! 559: ! 560: openpl(); ! 561: erase(); ! 562: space(-2048, -2048, 2048, 2048); ! 563: line(-2040, -2040, -2040, 2040); ! 564: line(0, 2040, 0, -2040); ! 565: for(i=0; i<11; i++) ! 566: line(-2040, 2040-i*408, 0, 2040-i*408); ! 567: lastx = 0.; ! 568: lasty = ranoff; ! 569: scale = (4080.*ransca)/(sampbytes/sizeof(UNIT)); ! 570: lastsx = 0.0; ! 571: for(i = 0 ; i < nsamples ; i++ ) { ! 572: unsigned UNIT ccnt; ! 573: double tx, ty; ! 574: ccnt = samples[i]; ! 575: time = ccnt; ! 576: tx = lastsx; ! 577: ty = lasty; ! 578: lastsx =- 2000.*time/totime; ! 579: lasty =- scale; ! 580: if(lasty >= -2040. && ty <= 2040.) { ! 581: line((int)tx, (int)ty, (int)lastsx, (int)lasty); ! 582: if (ccnt!=0 || lastx!=0.0) { ! 583: tx = lastx; ! 584: lastx = -time*2000./maxtime; ! 585: ty =+ scale/2; ! 586: line(0, (int)ty, (int)tx, (int)ty); ! 587: } ! 588: } ! 589: } ! 590: scale = (4080.*ransca)/(highpc-lowpc); ! 591: lastx = 50.; ! 592: for(np = nl; np<npe; np++) { ! 593: if(np->value < lowpc) ! 594: continue; ! 595: if(np->value >= highpc) ! 596: continue; ! 597: time = np->time/totime; ! 598: lasty = ranoff - (np->value - lowpc)*scale; ! 599: if(lasty >= -2040. && lasty <= 2040.) { ! 600: char bufl[BUFSIZ], *namp; ! 601: register j; ! 602: line(0, (int)lasty, 50, (int)lasty); ! 603: line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty); ! 604: point((int)(lastx+30), (int)(lasty+10)); ! 605: sprintf(bufl, "%s\n", np->name + np->name[0] == '_'); ! 606: label(bufl); ! 607: } ! 608: lastx =+ 500.; ! 609: if(lastx > 2000.) ! 610: lastx = 50.; ! 611: } ! 612: } ! 613: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.