Annotation of src/usr.bin/gprof/gprof.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: gprof.c,v 1.8 1995/04/19 07:15:59 cgd Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1983, 1993
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by the University of
! 18: * California, Berkeley and its contributors.
! 19: * 4. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: */
! 35:
! 36: #ifndef lint
! 37: static char copyright[] =
! 38: "@(#) Copyright (c) 1983, 1993\n\
! 39: The Regents of the University of California. All rights reserved.\n";
! 40: #endif /* not lint */
! 41:
! 42: #ifndef lint
! 43: #if 0
! 44: static char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93";
! 45: #else
! 46: static char rcsid[] = "$NetBSD: gprof.c,v 1.8 1995/04/19 07:15:59 cgd Exp $";
! 47: #endif
! 48: #endif /* not lint */
! 49:
! 50: #include "gprof.h"
! 51:
! 52: char *whoami = "gprof";
! 53:
! 54: /*
! 55: * things which get -E excluded by default.
! 56: */
! 57: char *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
! 58:
! 59: static struct gmonhdr gmonhdr;
! 60:
! 61: main(argc, argv)
! 62: int argc;
! 63: char **argv;
! 64: {
! 65: char **sp;
! 66: nltype **timesortnlp;
! 67:
! 68: --argc;
! 69: argv++;
! 70: debug = 0;
! 71: bflag = TRUE;
! 72: while ( *argv != 0 && **argv == '-' ) {
! 73: (*argv)++;
! 74: switch ( **argv ) {
! 75: case 'a':
! 76: aflag = TRUE;
! 77: break;
! 78: case 'b':
! 79: bflag = FALSE;
! 80: break;
! 81: case 'C':
! 82: Cflag = TRUE;
! 83: cyclethreshold = atoi( *++argv );
! 84: break;
! 85: case 'c':
! 86: #if defined(vax) || defined(tahoe) || defined(sparc)
! 87: cflag = TRUE;
! 88: #else
! 89: fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n");
! 90: exit(1);
! 91: #endif
! 92: break;
! 93: case 'd':
! 94: dflag = TRUE;
! 95: setlinebuf(stdout);
! 96: debug |= atoi( *++argv );
! 97: debug |= ANYDEBUG;
! 98: # ifdef DEBUG
! 99: printf("[main] debug = %d\n", debug);
! 100: # else not DEBUG
! 101: printf("%s: -d ignored\n", whoami);
! 102: # endif DEBUG
! 103: break;
! 104: case 'E':
! 105: ++argv;
! 106: addlist( Elist , *argv );
! 107: Eflag = TRUE;
! 108: addlist( elist , *argv );
! 109: eflag = TRUE;
! 110: break;
! 111: case 'e':
! 112: addlist( elist , *++argv );
! 113: eflag = TRUE;
! 114: break;
! 115: case 'F':
! 116: ++argv;
! 117: addlist( Flist , *argv );
! 118: Fflag = TRUE;
! 119: addlist( flist , *argv );
! 120: fflag = TRUE;
! 121: break;
! 122: case 'f':
! 123: addlist( flist , *++argv );
! 124: fflag = TRUE;
! 125: break;
! 126: case 'k':
! 127: addlist( kfromlist , *++argv );
! 128: addlist( ktolist , *++argv );
! 129: kflag = TRUE;
! 130: break;
! 131: case 's':
! 132: sflag = TRUE;
! 133: break;
! 134: case 'z':
! 135: zflag = TRUE;
! 136: break;
! 137: }
! 138: argv++;
! 139: }
! 140: if ( *argv != 0 ) {
! 141: a_outname = *argv;
! 142: argv++;
! 143: } else {
! 144: a_outname = A_OUTNAME;
! 145: }
! 146: if ( *argv != 0 ) {
! 147: gmonname = *argv;
! 148: argv++;
! 149: } else {
! 150: gmonname = GMONNAME;
! 151: }
! 152: /*
! 153: * turn off default functions
! 154: */
! 155: for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
! 156: Eflag = TRUE;
! 157: addlist( Elist , *sp );
! 158: eflag = TRUE;
! 159: addlist( elist , *sp );
! 160: }
! 161: /*
! 162: * get information about a.out file.
! 163: */
! 164: getnfile();
! 165: /*
! 166: * get information about mon.out file(s).
! 167: */
! 168: do {
! 169: getpfile( gmonname );
! 170: if ( *argv != 0 ) {
! 171: gmonname = *argv;
! 172: }
! 173: } while ( *argv++ != 0 );
! 174: /*
! 175: * how many ticks per second?
! 176: * if we can't tell, report time in ticks.
! 177: */
! 178: if (hz == 0) {
! 179: hz = 1;
! 180: fprintf(stderr, "time is in ticks, not seconds\n");
! 181: }
! 182: /*
! 183: * dump out a gmon.sum file if requested
! 184: */
! 185: if ( sflag ) {
! 186: dumpsum( GMONSUM );
! 187: }
! 188: /*
! 189: * assign samples to procedures
! 190: */
! 191: asgnsamples();
! 192: /*
! 193: * assemble the dynamic profile
! 194: */
! 195: timesortnlp = doarcs();
! 196: /*
! 197: * print the dynamic profile
! 198: */
! 199: printgprof( timesortnlp );
! 200: /*
! 201: * print the flat profile
! 202: */
! 203: printprof();
! 204: /*
! 205: * print the index
! 206: */
! 207: printindex();
! 208: done();
! 209: }
! 210:
! 211: /*
! 212: * Set up string and symbol tables from a.out.
! 213: * and optionally the text space.
! 214: * On return symbol table is sorted by value.
! 215: */
! 216: getnfile()
! 217: {
! 218: FILE *nfile;
! 219: int valcmp();
! 220:
! 221: nfile = fopen( a_outname ,"r");
! 222: if (nfile == NULL) {
! 223: perror( a_outname );
! 224: done();
! 225: }
! 226: fread(&xbuf, 1, sizeof(xbuf), nfile);
! 227: if (N_BADMAG(xbuf)) {
! 228: fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
! 229: done();
! 230: }
! 231: getstrtab(nfile);
! 232: getsymtab(nfile);
! 233: gettextspace( nfile );
! 234: qsort(nl, nname, sizeof(nltype), valcmp);
! 235: fclose(nfile);
! 236: # ifdef DEBUG
! 237: if ( debug & AOUTDEBUG ) {
! 238: register int j;
! 239:
! 240: for (j = 0; j < nname; j++){
! 241: printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
! 242: }
! 243: }
! 244: # endif DEBUG
! 245: }
! 246:
! 247: getstrtab(nfile)
! 248: FILE *nfile;
! 249: {
! 250:
! 251: fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
! 252: if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
! 253: fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
! 254: whoami , a_outname );
! 255: done();
! 256: }
! 257: strtab = calloc(ssiz, 1);
! 258: if (strtab == NULL) {
! 259: fprintf(stderr, "%s: %s: no room for %d bytes of string table\n",
! 260: whoami , a_outname , ssiz);
! 261: done();
! 262: }
! 263: if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
! 264: fprintf(stderr, "%s: %s: error reading string table\n",
! 265: whoami , a_outname );
! 266: done();
! 267: }
! 268: }
! 269:
! 270: /*
! 271: * Read in symbol table
! 272: */
! 273: getsymtab(nfile)
! 274: FILE *nfile;
! 275: {
! 276: register long i;
! 277: int askfor;
! 278: struct nlist nbuf;
! 279:
! 280: /* pass1 - count symbols */
! 281: fseek(nfile, (long)N_SYMOFF(xbuf), 0);
! 282: nname = 0;
! 283: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
! 284: fread(&nbuf, sizeof(nbuf), 1, nfile);
! 285: if ( ! funcsymbol( &nbuf ) ) {
! 286: continue;
! 287: }
! 288: nname++;
! 289: }
! 290: if (nname == 0) {
! 291: fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
! 292: done();
! 293: }
! 294: askfor = nname + 1;
! 295: nl = (nltype *) calloc( askfor , sizeof(nltype) );
! 296: if (nl == 0) {
! 297: fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
! 298: whoami, askfor * sizeof(nltype) );
! 299: done();
! 300: }
! 301:
! 302: /* pass2 - read symbols */
! 303: fseek(nfile, (long)N_SYMOFF(xbuf), 0);
! 304: npe = nl;
! 305: nname = 0;
! 306: for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
! 307: fread(&nbuf, sizeof(nbuf), 1, nfile);
! 308: if ( ! funcsymbol( &nbuf ) ) {
! 309: # ifdef DEBUG
! 310: if ( debug & AOUTDEBUG ) {
! 311: printf( "[getsymtab] rejecting: 0x%x %s\n" ,
! 312: nbuf.n_type , strtab + nbuf.n_un.n_strx );
! 313: }
! 314: # endif DEBUG
! 315: continue;
! 316: }
! 317: npe->value = nbuf.n_value;
! 318: npe->name = strtab+nbuf.n_un.n_strx;
! 319: # ifdef DEBUG
! 320: if ( debug & AOUTDEBUG ) {
! 321: printf( "[getsymtab] %d %s 0x%08x\n" ,
! 322: nname , npe -> name , npe -> value );
! 323: }
! 324: # endif DEBUG
! 325: npe++;
! 326: nname++;
! 327: }
! 328: npe->value = -1;
! 329: }
! 330:
! 331: /*
! 332: * read in the text space of an a.out file
! 333: */
! 334: gettextspace( nfile )
! 335: FILE *nfile;
! 336: {
! 337:
! 338: if ( cflag == 0 ) {
! 339: return;
! 340: }
! 341: textspace = (u_char *) malloc( xbuf.a_text );
! 342: if ( textspace == 0 ) {
! 343: fprintf( stderr , "%s: ran out room for %d bytes of text space: " ,
! 344: whoami , xbuf.a_text );
! 345: fprintf( stderr , "can't do -c\n" );
! 346: return;
! 347: }
! 348: (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
! 349: if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
! 350: fprintf( stderr , "%s: couldn't read text space: " , whoami );
! 351: fprintf( stderr , "can't do -c\n" );
! 352: free( textspace );
! 353: textspace = 0;
! 354: return;
! 355: }
! 356: }
! 357: /*
! 358: * information from a gmon.out file is in two parts:
! 359: * an array of sampling hits within pc ranges,
! 360: * and the arcs.
! 361: */
! 362: getpfile(filename)
! 363: char *filename;
! 364: {
! 365: FILE *pfile;
! 366: FILE *openpfile();
! 367: struct rawarc arc;
! 368:
! 369: pfile = openpfile(filename);
! 370: readsamples(pfile);
! 371: /*
! 372: * the rest of the file consists of
! 373: * a bunch of <from,self,count> tuples.
! 374: */
! 375: while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
! 376: # ifdef DEBUG
! 377: if ( debug & SAMPLEDEBUG ) {
! 378: printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
! 379: arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
! 380: }
! 381: # endif DEBUG
! 382: /*
! 383: * add this arc
! 384: */
! 385: tally( &arc );
! 386: }
! 387: fclose(pfile);
! 388: }
! 389:
! 390: FILE *
! 391: openpfile(filename)
! 392: char *filename;
! 393: {
! 394: struct gmonhdr tmp;
! 395: FILE *pfile;
! 396: int size;
! 397: int rate;
! 398:
! 399: if((pfile = fopen(filename, "r")) == NULL) {
! 400: perror(filename);
! 401: done();
! 402: }
! 403: fread(&tmp, sizeof(struct gmonhdr), 1, pfile);
! 404: if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc ||
! 405: tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) {
! 406: fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
! 407: done();
! 408: }
! 409: gmonhdr = tmp;
! 410: if ( gmonhdr.version == GMONVERSION ) {
! 411: rate = gmonhdr.profrate;
! 412: size = sizeof(struct gmonhdr);
! 413: } else {
! 414: fseek(pfile, sizeof(struct ophdr), SEEK_SET);
! 415: size = sizeof(struct ophdr);
! 416: gmonhdr.profrate = rate = hertz();
! 417: gmonhdr.version = GMONVERSION;
! 418: }
! 419: if (hz == 0) {
! 420: hz = rate;
! 421: } else if (hz != rate) {
! 422: fprintf(stderr,
! 423: "%s: profile clock rate (%d) %s (%d) in first gmon file\n",
! 424: filename, rate, "incompatible with clock rate", hz);
! 425: done();
! 426: }
! 427: s_lowpc = (unsigned long) gmonhdr.lpc;
! 428: s_highpc = (unsigned long) gmonhdr.hpc;
! 429: lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT);
! 430: highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT);
! 431: sampbytes = gmonhdr.ncnt - size;
! 432: nsamples = sampbytes / sizeof (UNIT);
! 433: # ifdef DEBUG
! 434: if ( debug & SAMPLEDEBUG ) {
! 435: printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n",
! 436: gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt );
! 437: printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" ,
! 438: s_lowpc , s_highpc );
! 439: printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" ,
! 440: lowpc , highpc );
! 441: printf( "[openpfile] sampbytes %d nsamples %d\n" ,
! 442: sampbytes , nsamples );
! 443: printf( "[openpfile] sample rate %d\n" , hz );
! 444: }
! 445: # endif DEBUG
! 446: return(pfile);
! 447: }
! 448:
! 449: tally( rawp )
! 450: struct rawarc *rawp;
! 451: {
! 452: nltype *parentp;
! 453: nltype *childp;
! 454:
! 455: parentp = nllookup( rawp -> raw_frompc );
! 456: childp = nllookup( rawp -> raw_selfpc );
! 457: if ( parentp == 0 || childp == 0 )
! 458: return;
! 459: if ( kflag
! 460: && onlist( kfromlist , parentp -> name )
! 461: && onlist( ktolist , childp -> name ) ) {
! 462: return;
! 463: }
! 464: childp -> ncall += rawp -> raw_count;
! 465: # ifdef DEBUG
! 466: if ( debug & TALLYDEBUG ) {
! 467: printf( "[tally] arc from %s to %s traversed %d times\n" ,
! 468: parentp -> name , childp -> name , rawp -> raw_count );
! 469: }
! 470: # endif DEBUG
! 471: addarc( parentp , childp , rawp -> raw_count );
! 472: }
! 473:
! 474: /*
! 475: * dump out the gmon.sum file
! 476: */
! 477: dumpsum( sumfile )
! 478: char *sumfile;
! 479: {
! 480: register nltype *nlp;
! 481: register arctype *arcp;
! 482: struct rawarc arc;
! 483: FILE *sfile;
! 484:
! 485: if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
! 486: perror( sumfile );
! 487: done();
! 488: }
! 489: /*
! 490: * dump the header; use the last header read in
! 491: */
! 492: if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) {
! 493: perror( sumfile );
! 494: done();
! 495: }
! 496: /*
! 497: * dump the samples
! 498: */
! 499: if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
! 500: perror( sumfile );
! 501: done();
! 502: }
! 503: /*
! 504: * dump the normalized raw arc information
! 505: */
! 506: for ( nlp = nl ; nlp < npe ; nlp++ ) {
! 507: for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
! 508: arc.raw_frompc = arcp -> arc_parentp -> value;
! 509: arc.raw_selfpc = arcp -> arc_childp -> value;
! 510: arc.raw_count = arcp -> arc_count;
! 511: if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
! 512: perror( sumfile );
! 513: done();
! 514: }
! 515: # ifdef DEBUG
! 516: if ( debug & SAMPLEDEBUG ) {
! 517: printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
! 518: arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
! 519: }
! 520: # endif DEBUG
! 521: }
! 522: }
! 523: fclose( sfile );
! 524: }
! 525:
! 526: valcmp(p1, p2)
! 527: nltype *p1, *p2;
! 528: {
! 529: if ( p1 -> value < p2 -> value ) {
! 530: return LESSTHAN;
! 531: }
! 532: if ( p1 -> value > p2 -> value ) {
! 533: return GREATERTHAN;
! 534: }
! 535: return EQUALTO;
! 536: }
! 537:
! 538: readsamples(pfile)
! 539: FILE *pfile;
! 540: {
! 541: register i;
! 542: UNIT sample;
! 543:
! 544: if (samples == 0) {
! 545: samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
! 546: if (samples == 0) {
! 547: fprintf( stderr , "%s: No room for %d sample pc's\n",
! 548: whoami , sampbytes / sizeof (UNIT));
! 549: done();
! 550: }
! 551: }
! 552: for (i = 0; i < nsamples; i++) {
! 553: fread(&sample, sizeof (UNIT), 1, pfile);
! 554: if (feof(pfile))
! 555: break;
! 556: samples[i] += sample;
! 557: }
! 558: if (i != nsamples) {
! 559: fprintf(stderr,
! 560: "%s: unexpected EOF after reading %d/%d samples\n",
! 561: whoami , --i , nsamples );
! 562: done();
! 563: }
! 564: }
! 565:
! 566: /*
! 567: * Assign samples to the procedures to which they belong.
! 568: *
! 569: * There are three cases as to where pcl and pch can be
! 570: * with respect to the routine entry addresses svalue0 and svalue1
! 571: * as shown in the following diagram. overlap computes the
! 572: * distance between the arrows, the fraction of the sample
! 573: * that is to be credited to the routine which starts at svalue0.
! 574: *
! 575: * svalue0 svalue1
! 576: * | |
! 577: * v v
! 578: *
! 579: * +-----------------------------------------------+
! 580: * | |
! 581: * | ->| |<- ->| |<- ->| |<- |
! 582: * | | | | | |
! 583: * +---------+ +---------+ +---------+
! 584: *
! 585: * ^ ^ ^ ^ ^ ^
! 586: * | | | | | |
! 587: * pcl pch pcl pch pcl pch
! 588: *
! 589: * For the vax we assert that samples will never fall in the first
! 590: * two bytes of any routine, since that is the entry mask,
! 591: * thus we give call alignentries() to adjust the entry points if
! 592: * the entry mask falls in one bucket but the code for the routine
! 593: * doesn't start until the next bucket. In conjunction with the
! 594: * alignment of routine addresses, this should allow us to have
! 595: * only one sample for every four bytes of text space and never
! 596: * have any overlap (the two end cases, above).
! 597: */
! 598: asgnsamples()
! 599: {
! 600: register int j;
! 601: UNIT ccnt;
! 602: double time;
! 603: unsigned long pcl, pch;
! 604: register int i;
! 605: unsigned long overlap;
! 606: unsigned long svalue0, svalue1;
! 607:
! 608: /* read samples and assign to namelist symbols */
! 609: scale = highpc - lowpc;
! 610: scale /= nsamples;
! 611: alignentries();
! 612: for (i = 0, j = 1; i < nsamples; i++) {
! 613: ccnt = samples[i];
! 614: if (ccnt == 0)
! 615: continue;
! 616: pcl = lowpc + scale * i;
! 617: pch = lowpc + scale * (i + 1);
! 618: time = ccnt;
! 619: # ifdef DEBUG
! 620: if ( debug & SAMPLEDEBUG ) {
! 621: printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
! 622: pcl , pch , ccnt );
! 623: }
! 624: # endif DEBUG
! 625: totime += time;
! 626: for (j = j - 1; j < nname; j++) {
! 627: svalue0 = nl[j].svalue;
! 628: svalue1 = nl[j+1].svalue;
! 629: /*
! 630: * if high end of tick is below entry address,
! 631: * go for next tick.
! 632: */
! 633: if (pch < svalue0)
! 634: break;
! 635: /*
! 636: * if low end of tick into next routine,
! 637: * go for next routine.
! 638: */
! 639: if (pcl >= svalue1)
! 640: continue;
! 641: overlap = min(pch, svalue1) - max(pcl, svalue0);
! 642: if (overlap > 0) {
! 643: # ifdef DEBUG
! 644: if (debug & SAMPLEDEBUG) {
! 645: printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
! 646: nl[j].value/sizeof(UNIT), svalue0, svalue1,
! 647: nl[j].name,
! 648: overlap * time / scale, overlap);
! 649: }
! 650: # endif DEBUG
! 651: nl[j].time += overlap * time / scale;
! 652: }
! 653: }
! 654: }
! 655: # ifdef DEBUG
! 656: if (debug & SAMPLEDEBUG) {
! 657: printf("[asgnsamples] totime %f\n", totime);
! 658: }
! 659: # endif DEBUG
! 660: }
! 661:
! 662:
! 663: unsigned long
! 664: min(a, b)
! 665: unsigned long a,b;
! 666: {
! 667: if (a<b)
! 668: return(a);
! 669: return(b);
! 670: }
! 671:
! 672: unsigned long
! 673: max(a, b)
! 674: unsigned long a,b;
! 675: {
! 676: if (a>b)
! 677: return(a);
! 678: return(b);
! 679: }
! 680:
! 681: /*
! 682: * calculate scaled entry point addresses (to save time in asgnsamples),
! 683: * and possibly push the scaled entry points over the entry mask,
! 684: * if it turns out that the entry point is in one bucket and the code
! 685: * for a routine is in the next bucket.
! 686: */
! 687: alignentries()
! 688: {
! 689: register struct nl *nlp;
! 690: unsigned long bucket_of_entry;
! 691: unsigned long bucket_of_code;
! 692:
! 693: for (nlp = nl; nlp < npe; nlp++) {
! 694: nlp -> svalue = nlp -> value / sizeof(UNIT);
! 695: bucket_of_entry = (nlp->svalue - lowpc) / scale;
! 696: bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
! 697: if (bucket_of_entry < bucket_of_code) {
! 698: # ifdef DEBUG
! 699: if (debug & SAMPLEDEBUG) {
! 700: printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
! 701: nlp->svalue, nlp->svalue + UNITS_TO_CODE);
! 702: }
! 703: # endif DEBUG
! 704: nlp->svalue += UNITS_TO_CODE;
! 705: }
! 706: }
! 707: }
! 708:
! 709: bool
! 710: funcsymbol( nlistp )
! 711: struct nlist *nlistp;
! 712: {
! 713: extern char *strtab; /* string table from a.out */
! 714: extern int aflag; /* if static functions aren't desired */
! 715: char *name, c;
! 716:
! 717: /*
! 718: * must be a text symbol,
! 719: * and static text symbols don't qualify if aflag set.
! 720: */
! 721: if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
! 722: || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
! 723: return FALSE;
! 724: }
! 725: /*
! 726: * can't have any `funny' characters in name,
! 727: * where `funny' includes `.', .o file names
! 728: * and `$', pascal labels.
! 729: * need to make an exception for sparc .mul & co.
! 730: * perhaps we should just drop this code entirely...
! 731: */
! 732: name = strtab + nlistp -> n_un.n_strx;
! 733: #ifdef sparc
! 734: if (nlistp -> n_value & 3)
! 735: return FALSE;
! 736: if ( *name == '.' ) {
! 737: char *p = name + 1;
! 738: if ( *p == 'u' )
! 739: p++;
! 740: if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 ||
! 741: strcmp ( p, "rem" ) == 0 )
! 742: return TRUE;
! 743: }
! 744: #endif
! 745: while ( c = *name++ ) {
! 746: if ( c == '.' || c == '$' ) {
! 747: return FALSE;
! 748: }
! 749: }
! 750: return TRUE;
! 751: }
! 752:
! 753: done()
! 754: {
! 755:
! 756: exit(0);
! 757: }