121960Sdist /* 221960Sdist * Copyright (c) 1983 Regents of the University of California. 334199Sbostic * All rights reserved. 434199Sbostic * 542683Sbostic * %sccs.include.redist.c% 621960Sdist */ 721960Sdist 84510Speter #ifndef lint 921960Sdist char copyright[] = 1021960Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1121960Sdist All rights reserved.\n"; 1234199Sbostic #endif /* not lint */ 134510Speter 1421960Sdist #ifndef lint 15*54806Storek static char sccsid[] = "@(#)gprof.c 5.11 (Berkeley) 07/08/92"; 1634199Sbostic #endif /* not lint */ 1721960Sdist 184563Speter #include "gprof.h" 194510Speter 207128Speter char *whoami = "gprof"; 217128Speter 227223Speter /* 237223Speter * things which get -E excluded by default. 247223Speter */ 257223Speter char *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; 267173Speter 27*54806Storek static struct gmonhdr gmonhdr; 2852812Smckusick 294510Speter main(argc, argv) 307173Speter int argc; 317173Speter char **argv; 324510Speter { 337173Speter char **sp; 3416852Smckusick nltype **timesortnlp; 354510Speter 364510Speter --argc; 374510Speter argv++; 384510Speter debug = 0; 3912385Smckusick bflag = TRUE; 404510Speter while ( *argv != 0 && **argv == '-' ) { 414510Speter (*argv)++; 424866Smckusic switch ( **argv ) { 437173Speter case 'a': 447173Speter aflag = TRUE; 457173Speter break; 467173Speter case 'b': 4712385Smckusick bflag = FALSE; 487173Speter break; 4952650Smckusick case 'C': 5052650Smckusick Cflag = TRUE; 5152650Smckusick cyclethreshold = atoi( *++argv ); 5252650Smckusick break; 537173Speter case 'c': 5448700Sdonn #if defined(vax) || defined(tahoe) 557173Speter cflag = TRUE; 5648700Sdonn #else 5748700Sdonn fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n"); 5848700Sdonn exit(1); 5948700Sdonn #endif 607173Speter break; 614866Smckusic case 'd': 627173Speter dflag = TRUE; 63*54806Storek setlinebuf(stdout); 6452650Smckusick debug |= atoi( *++argv ); 654510Speter debug |= ANYDEBUG; 664510Speter # ifdef DEBUG 6711807Smckusick printf("[main] debug = %d\n", debug); 6811807Smckusick # else not DEBUG 6911807Smckusick printf("%s: -d ignored\n", whoami); 704510Speter # endif DEBUG 714866Smckusic break; 727223Speter case 'E': 737223Speter ++argv; 747223Speter addlist( Elist , *argv ); 757223Speter Eflag = TRUE; 767223Speter addlist( elist , *argv ); 777223Speter eflag = TRUE; 787223Speter break; 797173Speter case 'e': 807223Speter addlist( elist , *++argv ); 817173Speter eflag = TRUE; 824866Smckusic break; 837223Speter case 'F': 847223Speter ++argv; 857223Speter addlist( Flist , *argv ); 867223Speter Fflag = TRUE; 877223Speter addlist( flist , *argv ); 887223Speter fflag = TRUE; 897223Speter break; 907173Speter case 'f': 917223Speter addlist( flist , *++argv ); 927173Speter fflag = TRUE; 934866Smckusic break; 9430963Smckusick case 'k': 9530963Smckusick addlist( kfromlist , *++argv ); 9630963Smckusick addlist( ktolist , *++argv ); 9730963Smckusick kflag = TRUE; 9830963Smckusick break; 994866Smckusic case 's': 1007173Speter sflag = TRUE; 1014866Smckusic break; 1024866Smckusic case 'z': 1037173Speter zflag = TRUE; 1044866Smckusic break; 1054510Speter } 1064510Speter argv++; 1074510Speter } 1084510Speter if ( *argv != 0 ) { 1094510Speter a_outname = *argv; 1104510Speter argv++; 1114510Speter } else { 1124510Speter a_outname = A_OUTNAME; 1134510Speter } 1144510Speter if ( *argv != 0 ) { 1154563Speter gmonname = *argv; 1164510Speter argv++; 1174510Speter } else { 1184563Speter gmonname = GMONNAME; 1194510Speter } 1204510Speter /* 1217173Speter * turn off default functions 1227173Speter */ 1237223Speter for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 1247223Speter Eflag = TRUE; 1257223Speter addlist( Elist , *sp ); 1267173Speter eflag = TRUE; 1277223Speter addlist( elist , *sp ); 1287173Speter } 1297173Speter /* 1304510Speter * get information about a.out file. 1314510Speter */ 1324510Speter getnfile(); 1334510Speter /* 1344510Speter * get information about mon.out file(s). 1354510Speter */ 1364866Smckusic do { 1374866Smckusic getpfile( gmonname ); 1384866Smckusic if ( *argv != 0 ) { 1394866Smckusic gmonname = *argv; 1404866Smckusic } 1417128Speter } while ( *argv++ != 0 ); 1424510Speter /* 14352812Smckusick * how many ticks per second? 14452812Smckusick * if we can't tell, report time in ticks. 14552812Smckusick */ 14652812Smckusick if (hz == 0) { 14752812Smckusick hz = 1; 14852812Smckusick fprintf(stderr, "time is in ticks, not seconds\n"); 14952812Smckusick } 15052812Smckusick /* 1514866Smckusic * dump out a gmon.sum file if requested 1524866Smckusic */ 1537128Speter if ( sflag ) { 1547128Speter dumpsum( GMONSUM ); 1557128Speter } 1564866Smckusic /* 1574510Speter * assign samples to procedures 1584510Speter */ 1594510Speter asgnsamples(); 1604510Speter /* 16116852Smckusick * assemble the dynamic profile 1624510Speter */ 16316852Smckusick timesortnlp = doarcs(); 16416852Smckusick /* 16516852Smckusick * print the dynamic profile 16616852Smckusick */ 16716852Smckusick printgprof( timesortnlp ); 16816852Smckusick /* 16916852Smckusick * print the flat profile 17016852Smckusick */ 1714510Speter printprof(); 1724510Speter /* 17316852Smckusick * print the index 1744510Speter */ 17516852Smckusick printindex(); 1764510Speter done(); 1774510Speter } 1784510Speter 1797128Speter /* 1807128Speter * Set up string and symbol tables from a.out. 1817128Speter * and optionally the text space. 1827128Speter * On return symbol table is sorted by value. 1837128Speter */ 1844510Speter getnfile() 1854510Speter { 1864510Speter FILE *nfile; 18733226Sbostic int valcmp(); 1884510Speter 1894510Speter nfile = fopen( a_outname ,"r"); 1904510Speter if (nfile == NULL) { 1914510Speter perror( a_outname ); 1924510Speter done(); 1934510Speter } 1944510Speter fread(&xbuf, 1, sizeof(xbuf), nfile); 1954510Speter if (N_BADMAG(xbuf)) { 1967128Speter fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 1974510Speter done(); 1984510Speter } 1994510Speter getstrtab(nfile); 2004510Speter getsymtab(nfile); 2014720Speter gettextspace( nfile ); 2024510Speter qsort(nl, nname, sizeof(nltype), valcmp); 2034510Speter fclose(nfile); 2044510Speter # ifdef DEBUG 2054510Speter if ( debug & AOUTDEBUG ) { 2064510Speter register int j; 2074510Speter 2084510Speter for (j = 0; j < nname; j++){ 2094510Speter printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 2104510Speter } 2114510Speter } 2124510Speter # endif DEBUG 2134510Speter } 2144510Speter 2154510Speter getstrtab(nfile) 2164510Speter FILE *nfile; 2174510Speter { 2184510Speter 2194510Speter fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 2204510Speter if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 2217128Speter fprintf(stderr, "%s: %s: no string table (old format?)\n" , 2227128Speter whoami , a_outname ); 2234510Speter done(); 2244510Speter } 225*54806Storek strtab = calloc(ssiz, 1); 2264510Speter if (strtab == NULL) { 227*54806Storek fprintf(stderr, "%s: %s: no room for %d bytes of string table\n", 2287128Speter whoami , a_outname , ssiz); 2294510Speter done(); 2304510Speter } 2314510Speter if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 2327128Speter fprintf(stderr, "%s: %s: error reading string table\n", 2337128Speter whoami , a_outname ); 2344510Speter done(); 2354510Speter } 2364510Speter } 2374510Speter 2384510Speter /* 2394510Speter * Read in symbol table 2404510Speter */ 2414510Speter getsymtab(nfile) 2424510Speter FILE *nfile; 2434510Speter { 2444510Speter register long i; 2454510Speter int askfor; 2464510Speter struct nlist nbuf; 2474510Speter 2484510Speter /* pass1 - count symbols */ 2494510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2504510Speter nname = 0; 2514510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2524510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2534845Speter if ( ! funcsymbol( &nbuf ) ) { 2544510Speter continue; 2554510Speter } 2564510Speter nname++; 2574510Speter } 2584510Speter if (nname == 0) { 2597128Speter fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 2604510Speter done(); 2614510Speter } 2627128Speter askfor = nname + 1; 2634510Speter nl = (nltype *) calloc( askfor , sizeof(nltype) ); 2644510Speter if (nl == 0) { 2657128Speter fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 2667128Speter whoami, askfor * sizeof(nltype) ); 2674510Speter done(); 2684510Speter } 2694510Speter 2704510Speter /* pass2 - read symbols */ 2714510Speter fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2724510Speter npe = nl; 2734510Speter nname = 0; 2744510Speter for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2754510Speter fread(&nbuf, sizeof(nbuf), 1, nfile); 2764845Speter if ( ! funcsymbol( &nbuf ) ) { 2774845Speter # ifdef DEBUG 2784845Speter if ( debug & AOUTDEBUG ) { 2794845Speter printf( "[getsymtab] rejecting: 0x%x %s\n" , 2804845Speter nbuf.n_type , strtab + nbuf.n_un.n_strx ); 2814845Speter } 2824845Speter # endif DEBUG 2834510Speter continue; 2844510Speter } 2854510Speter npe->value = nbuf.n_value; 2864510Speter npe->name = strtab+nbuf.n_un.n_strx; 2874510Speter # ifdef DEBUG 2884510Speter if ( debug & AOUTDEBUG ) { 2894510Speter printf( "[getsymtab] %d %s 0x%08x\n" , 2904510Speter nname , npe -> name , npe -> value ); 2914510Speter } 2924510Speter # endif DEBUG 2934510Speter npe++; 2944510Speter nname++; 2954510Speter } 2964510Speter npe->value = -1; 2974510Speter } 2984510Speter 2994510Speter /* 3004720Speter * read in the text space of an a.out file 3014720Speter */ 3024720Speter gettextspace( nfile ) 3034720Speter FILE *nfile; 3044720Speter { 305*54806Storek 3064720Speter if ( cflag == 0 ) { 3074720Speter return; 3084720Speter } 30933226Sbostic textspace = (u_char *) malloc( xbuf.a_text ); 3104720Speter if ( textspace == 0 ) { 3117128Speter fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 3127128Speter whoami , xbuf.a_text ); 3137128Speter fprintf( stderr , "can't do -c\n" ); 3144720Speter return; 3154720Speter } 3164720Speter (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 3174720Speter if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 3187128Speter fprintf( stderr , "%s: couldn't read text space: " , whoami ); 3197128Speter fprintf( stderr , "can't do -c\n" ); 3204720Speter free( textspace ); 3214720Speter textspace = 0; 3224720Speter return; 3234720Speter } 3244720Speter } 3254720Speter /* 3264563Speter * information from a gmon.out file is in two parts: 3274510Speter * an array of sampling hits within pc ranges, 3284510Speter * and the arcs. 3294510Speter */ 3304510Speter getpfile(filename) 3314510Speter char *filename; 3324510Speter { 3334510Speter FILE *pfile; 3344510Speter FILE *openpfile(); 3354510Speter struct rawarc arc; 3364510Speter 3374510Speter pfile = openpfile(filename); 3384510Speter readsamples(pfile); 3394510Speter /* 3404510Speter * the rest of the file consists of 3414510Speter * a bunch of <from,self,count> tuples. 3424510Speter */ 3434510Speter while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 3444510Speter # ifdef DEBUG 3454510Speter if ( debug & SAMPLEDEBUG ) { 3464752Speter printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 3474510Speter arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3484510Speter } 3494510Speter # endif DEBUG 3504510Speter /* 3514510Speter * add this arc 3524510Speter */ 3534510Speter tally( &arc ); 3544510Speter } 3554510Speter fclose(pfile); 3564510Speter } 3574510Speter 3584841Speter FILE * 3594841Speter openpfile(filename) 3604510Speter char *filename; 3614510Speter { 362*54806Storek struct gmonhdr tmp; 36352812Smckusick FILE *pfile; 36452812Smckusick int size; 36552812Smckusick int rate; 3664510Speter 3674510Speter if((pfile = fopen(filename, "r")) == NULL) { 3684510Speter perror(filename); 3694510Speter done(); 3704510Speter } 371*54806Storek fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 372*54806Storek if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 373*54806Storek tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 3744866Smckusic fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 3754866Smckusic done(); 3764866Smckusic } 377*54806Storek gmonhdr = tmp; 378*54806Storek if ( gmonhdr.version == GMONVERSION ) { 379*54806Storek rate = gmonhdr.profrate; 380*54806Storek size = sizeof(struct gmonhdr); 38152812Smckusick } else { 382*54806Storek fseek(pfile, sizeof(struct ophdr), SEEK_SET); 38352812Smckusick size = sizeof(struct ophdr); 384*54806Storek gmonhdr.profrate = rate = hertz(); 385*54806Storek gmonhdr.version = GMONVERSION; 38652812Smckusick } 38752812Smckusick if (hz == 0) { 38852812Smckusick hz = rate; 38952812Smckusick } else if (hz != rate) { 39052812Smckusick fprintf(stderr, 39152812Smckusick "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 39252812Smckusick filename, rate, "incompatible with clock rate", hz); 39352812Smckusick done(); 39452812Smckusick } 395*54806Storek s_lowpc = (unsigned long) gmonhdr.lpc; 396*54806Storek s_highpc = (unsigned long) gmonhdr.hpc; 397*54806Storek lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 398*54806Storek highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 399*54806Storek sampbytes = gmonhdr.ncnt - size; 40033226Sbostic nsamples = sampbytes / sizeof (UNIT); 4017226Speter # ifdef DEBUG 4027226Speter if ( debug & SAMPLEDEBUG ) { 40352812Smckusick printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 404*54806Storek gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 4057226Speter printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 4067226Speter s_lowpc , s_highpc ); 4077226Speter printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 4087226Speter lowpc , highpc ); 4097226Speter printf( "[openpfile] sampbytes %d nsamples %d\n" , 4107226Speter sampbytes , nsamples ); 41152812Smckusick printf( "[openpfile] sample rate %d\n" , hz ); 4127226Speter } 4137226Speter # endif DEBUG 4144510Speter return(pfile); 4154510Speter } 4164510Speter 4174510Speter tally( rawp ) 4184510Speter struct rawarc *rawp; 4194510Speter { 4204510Speter nltype *parentp; 4214510Speter nltype *childp; 4224510Speter 4234510Speter parentp = nllookup( rawp -> raw_frompc ); 4244510Speter childp = nllookup( rawp -> raw_selfpc ); 42552581Smckusick if ( parentp == 0 || childp == 0 ) 42652581Smckusick return; 42730963Smckusick if ( kflag 42830963Smckusick && onlist( kfromlist , parentp -> name ) 42930963Smckusick && onlist( ktolist , childp -> name ) ) { 43030963Smckusick return; 43130963Smckusick } 4324510Speter childp -> ncall += rawp -> raw_count; 4334510Speter # ifdef DEBUG 4344510Speter if ( debug & TALLYDEBUG ) { 4354510Speter printf( "[tally] arc from %s to %s traversed %d times\n" , 4364510Speter parentp -> name , childp -> name , rawp -> raw_count ); 4374510Speter } 4384510Speter # endif DEBUG 4394720Speter addarc( parentp , childp , rawp -> raw_count ); 4404510Speter } 4414510Speter 4424866Smckusic /* 4434866Smckusic * dump out the gmon.sum file 4444866Smckusic */ 4454866Smckusic dumpsum( sumfile ) 4464866Smckusic char *sumfile; 4474866Smckusic { 4484866Smckusic register nltype *nlp; 4494866Smckusic register arctype *arcp; 4504866Smckusic struct rawarc arc; 4514866Smckusic FILE *sfile; 4524866Smckusic 4534866Smckusic if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 4544866Smckusic perror( sumfile ); 4554866Smckusic done(); 4564866Smckusic } 4574866Smckusic /* 4584866Smckusic * dump the header; use the last header read in 4594866Smckusic */ 460*54806Storek if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 4614866Smckusic perror( sumfile ); 4624866Smckusic done(); 4634866Smckusic } 4644866Smckusic /* 4654866Smckusic * dump the samples 4664866Smckusic */ 46733226Sbostic if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 4684866Smckusic perror( sumfile ); 4694866Smckusic done(); 4704866Smckusic } 4714866Smckusic /* 4724866Smckusic * dump the normalized raw arc information 4734866Smckusic */ 47411807Smckusick for ( nlp = nl ; nlp < npe ; nlp++ ) { 4754866Smckusic for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 4764866Smckusic arc.raw_frompc = arcp -> arc_parentp -> value; 4774866Smckusic arc.raw_selfpc = arcp -> arc_childp -> value; 4784866Smckusic arc.raw_count = arcp -> arc_count; 4794866Smckusic if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 4804866Smckusic perror( sumfile ); 4814866Smckusic done(); 4824866Smckusic } 4834866Smckusic # ifdef DEBUG 4844866Smckusic if ( debug & SAMPLEDEBUG ) { 4854866Smckusic printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 4864866Smckusic arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4874866Smckusic } 4884866Smckusic # endif DEBUG 4894866Smckusic } 4904866Smckusic } 4914866Smckusic fclose( sfile ); 4924866Smckusic } 4934866Smckusic 4944510Speter valcmp(p1, p2) 4954510Speter nltype *p1, *p2; 4964510Speter { 4974510Speter if ( p1 -> value < p2 -> value ) { 4984510Speter return LESSTHAN; 4994510Speter } 5004510Speter if ( p1 -> value > p2 -> value ) { 5014510Speter return GREATERTHAN; 5024510Speter } 5034510Speter return EQUALTO; 5044510Speter } 5054510Speter 5064510Speter readsamples(pfile) 5074510Speter FILE *pfile; 5084510Speter { 5094510Speter register i; 51033226Sbostic UNIT sample; 5114510Speter 5124510Speter if (samples == 0) { 51333226Sbostic samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 5144510Speter if (samples == 0) { 5157128Speter fprintf( stderr , "%s: No room for %d sample pc's\n", 51633226Sbostic whoami , sampbytes / sizeof (UNIT)); 5174510Speter done(); 5184510Speter } 5194510Speter } 5204510Speter for (i = 0; i < nsamples; i++) { 52133226Sbostic fread(&sample, sizeof (UNIT), 1, pfile); 5224510Speter if (feof(pfile)) 5234510Speter break; 5244510Speter samples[i] += sample; 5254510Speter } 5264510Speter if (i != nsamples) { 5274510Speter fprintf(stderr, 5287128Speter "%s: unexpected EOF after reading %d/%d samples\n", 5297128Speter whoami , --i , nsamples ); 5304510Speter done(); 5314510Speter } 5324510Speter } 5334510Speter 5344510Speter /* 53511523Smckusick * Assign samples to the procedures to which they belong. 53611523Smckusick * 53711523Smckusick * There are three cases as to where pcl and pch can be 53811523Smckusick * with respect to the routine entry addresses svalue0 and svalue1 53911523Smckusick * as shown in the following diagram. overlap computes the 54011523Smckusick * distance between the arrows, the fraction of the sample 54111523Smckusick * that is to be credited to the routine which starts at svalue0. 54211523Smckusick * 54311523Smckusick * svalue0 svalue1 54411523Smckusick * | | 54511523Smckusick * v v 54611523Smckusick * 54711523Smckusick * +-----------------------------------------------+ 54811523Smckusick * | | 54911523Smckusick * | ->| |<- ->| |<- ->| |<- | 55011523Smckusick * | | | | | | 55111523Smckusick * +---------+ +---------+ +---------+ 55211523Smckusick * 55311523Smckusick * ^ ^ ^ ^ ^ ^ 55411523Smckusick * | | | | | | 55511523Smckusick * pcl pch pcl pch pcl pch 55611523Smckusick * 55711523Smckusick * For the vax we assert that samples will never fall in the first 55811807Smckusick * two bytes of any routine, since that is the entry mask, 55911807Smckusick * thus we give call alignentries() to adjust the entry points if 56011807Smckusick * the entry mask falls in one bucket but the code for the routine 56111807Smckusick * doesn't start until the next bucket. In conjunction with the 56211807Smckusick * alignment of routine addresses, this should allow us to have 56311807Smckusick * only one sample for every four bytes of text space and never 56411807Smckusick * have any overlap (the two end cases, above). 5654510Speter */ 5664510Speter asgnsamples() 5674510Speter { 5684510Speter register int j; 56933226Sbostic UNIT ccnt; 5704510Speter double time; 5714510Speter unsigned long pcl, pch; 5724510Speter register int i; 5734841Speter unsigned long overlap; 5744510Speter unsigned long svalue0, svalue1; 5754510Speter 5764510Speter /* read samples and assign to namelist symbols */ 5774510Speter scale = highpc - lowpc; 5784510Speter scale /= nsamples; 57911807Smckusick alignentries(); 5807257Smckusick for (i = 0, j = 1; i < nsamples; i++) { 5814510Speter ccnt = samples[i]; 5824510Speter if (ccnt == 0) 5834510Speter continue; 58411523Smckusick pcl = lowpc + scale * i; 58511523Smckusick pch = lowpc + scale * (i + 1); 5864510Speter time = ccnt; 5874510Speter # ifdef DEBUG 5884510Speter if ( debug & SAMPLEDEBUG ) { 5895072Smckusic printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 5905072Smckusic pcl , pch , ccnt ); 5914510Speter } 5924510Speter # endif DEBUG 5934510Speter totime += time; 5947252Smckusick for (j = j - 1; j < nname; j++) { 59511807Smckusick svalue0 = nl[j].svalue; 59611807Smckusick svalue1 = nl[j+1].svalue; 59711807Smckusick /* 59811807Smckusick * if high end of tick is below entry address, 59911807Smckusick * go for next tick. 60011807Smckusick */ 6014510Speter if (pch < svalue0) 6024510Speter break; 60311807Smckusick /* 60411807Smckusick * if low end of tick into next routine, 60511807Smckusick * go for next routine. 60611807Smckusick */ 6074510Speter if (pcl >= svalue1) 6084510Speter continue; 60911807Smckusick overlap = min(pch, svalue1) - max(pcl, svalue0); 61011523Smckusick if (overlap > 0) { 6114510Speter # ifdef DEBUG 61211523Smckusick if (debug & SAMPLEDEBUG) { 61311807Smckusick printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 61411807Smckusick nl[j].value/sizeof(UNIT), svalue0, svalue1, 61511807Smckusick nl[j].name, 61611807Smckusick overlap * time / scale, overlap); 6174510Speter } 6184510Speter # endif DEBUG 61911523Smckusick nl[j].time += overlap * time / scale; 6204510Speter } 6214510Speter } 6224510Speter } 6234510Speter # ifdef DEBUG 62411523Smckusick if (debug & SAMPLEDEBUG) { 62511523Smckusick printf("[asgnsamples] totime %f\n", totime); 6264510Speter } 6274510Speter # endif DEBUG 6284510Speter } 6294510Speter 6304510Speter 6314841Speter unsigned long 6324510Speter min(a, b) 6334841Speter unsigned long a,b; 6344510Speter { 6354510Speter if (a<b) 6364510Speter return(a); 6374510Speter return(b); 6384510Speter } 6394510Speter 6404841Speter unsigned long 6414510Speter max(a, b) 6424841Speter unsigned long a,b; 6434510Speter { 6444510Speter if (a>b) 6454510Speter return(a); 6464510Speter return(b); 6474510Speter } 6484510Speter 64911807Smckusick /* 65011807Smckusick * calculate scaled entry point addresses (to save time in asgnsamples), 65111807Smckusick * and possibly push the scaled entry points over the entry mask, 65211807Smckusick * if it turns out that the entry point is in one bucket and the code 65311807Smckusick * for a routine is in the next bucket. 65411807Smckusick */ 65511807Smckusick alignentries() 65611807Smckusick { 65711807Smckusick register struct nl *nlp; 65811807Smckusick unsigned long bucket_of_entry; 65911807Smckusick unsigned long bucket_of_code; 66011807Smckusick 66111807Smckusick for (nlp = nl; nlp < npe; nlp++) { 66211807Smckusick nlp -> svalue = nlp -> value / sizeof(UNIT); 66311807Smckusick bucket_of_entry = (nlp->svalue - lowpc) / scale; 66411807Smckusick bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 66511807Smckusick if (bucket_of_entry < bucket_of_code) { 66611807Smckusick # ifdef DEBUG 66711807Smckusick if (debug & SAMPLEDEBUG) { 66811807Smckusick printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 66911807Smckusick nlp->svalue, nlp->svalue + UNITS_TO_CODE); 67011807Smckusick } 67111807Smckusick # endif DEBUG 67211807Smckusick nlp->svalue += UNITS_TO_CODE; 67311807Smckusick } 67411807Smckusick } 67511807Smckusick } 67611807Smckusick 6774845Speter bool 6784845Speter funcsymbol( nlistp ) 6794845Speter struct nlist *nlistp; 6804845Speter { 6814845Speter extern char *strtab; /* string table from a.out */ 6824851Speter extern int aflag; /* if static functions aren't desired */ 683*54806Storek char *name, c; 6844845Speter 6854845Speter /* 6864845Speter * must be a text symbol, 6874851Speter * and static text symbols don't qualify if aflag set. 6884845Speter */ 6894845Speter if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 6904851Speter || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 6914845Speter return FALSE; 6924845Speter } 6934845Speter /* 6947128Speter * can't have any `funny' characters in name, 6954845Speter * where `funny' includes `.', .o file names 6964845Speter * and `$', pascal labels. 697*54806Storek * need to make an exception for sparc .mul & co. 698*54806Storek * perhaps we should just drop this code entirely... 6994845Speter */ 700*54806Storek name = strtab + nlistp -> n_un.n_strx; 701*54806Storek #ifdef sparc 702*54806Storek if ( *name == '.' ) { 703*54806Storek char *p = name + 1; 704*54806Storek if ( *p == 'u' ) 705*54806Storek p++; 706*54806Storek if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 || 707*54806Storek strcmp ( p, "rem" ) == 0 ) 708*54806Storek return TRUE; 709*54806Storek } 710*54806Storek #endif 711*54806Storek while ( c = *name++ ) { 712*54806Storek if ( c == '.' || c == '$' ) { 7134845Speter return FALSE; 7144845Speter } 7154845Speter } 7164845Speter return TRUE; 7174845Speter } 7184845Speter 7194510Speter done() 7204510Speter { 7214510Speter 7224510Speter exit(0); 7234510Speter } 724