gprof.c revision 105243
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1983, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3527313Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 40105243Scharnier#if 0 411590Srgrimes#ifndef lint 421590Srgrimesstatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 43105243Scharnier#endif /* not lint */ 4427313Scharnier#endif 45105243Scharnier 4699112Sobrien#include <sys/cdefs.h> 4799112Sobrien__FBSDID("$FreeBSD: head/usr.bin/gprof/gprof.c 105243 2002-10-16 13:50:09Z charnier $"); 481590Srgrimes 4927313Scharnier#include <err.h> 5091738Sbde#include <limits.h> 5193123Smike#include <stdint.h> 521590Srgrimes#include "gprof.h" 531590Srgrimes 5438928Sjdpstatic int valcmp(const void *, const void *); 551590Srgrimes 5638928Sjdp 571590Srgrimesstatic struct gmonhdr gmonhdr; 585190Swollmanstatic int lflag; 595190Swollmanstatic int Lflag; 601590Srgrimes 61105243Scharnierint 621590Srgrimesmain(argc, argv) 631590Srgrimes int argc; 641590Srgrimes char **argv; 651590Srgrimes{ 661590Srgrimes char **sp; 671590Srgrimes nltype **timesortnlp; 6838928Sjdp char **defaultEs; 691590Srgrimes 701590Srgrimes --argc; 711590Srgrimes argv++; 721590Srgrimes debug = 0; 731590Srgrimes bflag = TRUE; 741590Srgrimes while ( *argv != 0 && **argv == '-' ) { 751590Srgrimes (*argv)++; 761590Srgrimes switch ( **argv ) { 771590Srgrimes case 'a': 781590Srgrimes aflag = TRUE; 791590Srgrimes break; 801590Srgrimes case 'b': 811590Srgrimes bflag = FALSE; 821590Srgrimes break; 831590Srgrimes case 'C': 841590Srgrimes Cflag = TRUE; 851590Srgrimes cyclethreshold = atoi( *++argv ); 861590Srgrimes break; 871590Srgrimes case 'c': 881590Srgrimes#if defined(vax) || defined(tahoe) 891590Srgrimes cflag = TRUE; 901590Srgrimes#else 9127313Scharnier errx(1, "-c isn't supported on this architecture yet"); 921590Srgrimes#endif 931590Srgrimes break; 941590Srgrimes case 'd': 951590Srgrimes dflag = TRUE; 961590Srgrimes setlinebuf(stdout); 971590Srgrimes debug |= atoi( *++argv ); 981590Srgrimes debug |= ANYDEBUG; 991590Srgrimes# ifdef DEBUG 1001590Srgrimes printf("[main] debug = %d\n", debug); 10197631Swollman# else /* not DEBUG */ 10227313Scharnier printf("gprof: -d ignored\n"); 10397631Swollman# endif /* DEBUG */ 1041590Srgrimes break; 1051590Srgrimes case 'E': 1061590Srgrimes ++argv; 1071590Srgrimes addlist( Elist , *argv ); 1081590Srgrimes Eflag = TRUE; 1091590Srgrimes addlist( elist , *argv ); 1101590Srgrimes eflag = TRUE; 1111590Srgrimes break; 1121590Srgrimes case 'e': 1131590Srgrimes addlist( elist , *++argv ); 1141590Srgrimes eflag = TRUE; 1151590Srgrimes break; 1161590Srgrimes case 'F': 1171590Srgrimes ++argv; 1181590Srgrimes addlist( Flist , *argv ); 1191590Srgrimes Fflag = TRUE; 1201590Srgrimes addlist( flist , *argv ); 1211590Srgrimes fflag = TRUE; 1221590Srgrimes break; 1231590Srgrimes case 'f': 1241590Srgrimes addlist( flist , *++argv ); 1251590Srgrimes fflag = TRUE; 1261590Srgrimes break; 1271590Srgrimes case 'k': 1281590Srgrimes addlist( kfromlist , *++argv ); 1291590Srgrimes addlist( ktolist , *++argv ); 1301590Srgrimes kflag = TRUE; 1311590Srgrimes break; 13285739Sgreen case 'K': 13385739Sgreen Kflag = TRUE; 13485739Sgreen break; 135105243Scharnier case 'l': 1365190Swollman lflag = 1; 1375190Swollman Lflag = 0; 1385190Swollman break; 139105243Scharnier case 'L': 1405190Swollman Lflag = 1; 1415190Swollman lflag = 0; 1425190Swollman break; 143105243Scharnier case 's': 1441590Srgrimes sflag = TRUE; 1451590Srgrimes break; 1462513Sbde case 'u': 1472513Sbde uflag = TRUE; 1482513Sbde break; 1491590Srgrimes case 'z': 1501590Srgrimes zflag = TRUE; 1511590Srgrimes break; 1521590Srgrimes } 1531590Srgrimes argv++; 1541590Srgrimes } 1551590Srgrimes if ( *argv != 0 ) { 1561590Srgrimes a_outname = *argv; 1571590Srgrimes argv++; 1581590Srgrimes } else { 1591590Srgrimes a_outname = A_OUTNAME; 1601590Srgrimes } 1611590Srgrimes if ( *argv != 0 ) { 1621590Srgrimes gmonname = *argv; 1631590Srgrimes argv++; 1641590Srgrimes } else { 16547420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 16647420Sjmz strcpy(gmonname, a_outname); 16747420Sjmz strcat(gmonname, ".gmon"); 1681590Srgrimes } 1691590Srgrimes /* 17038928Sjdp * get information from the executable file. 17138928Sjdp */ 17285739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 17385739Sgreen (elf_getnfile(a_outname, &defaultEs) == -1 && 17485739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 17538928Sjdp errx(1, "%s: bad format", a_outname); 17638928Sjdp /* 17738928Sjdp * sort symbol table. 17838928Sjdp */ 17938928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 18038928Sjdp /* 1811590Srgrimes * turn off default functions 1821590Srgrimes */ 18338928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1841590Srgrimes Eflag = TRUE; 1851590Srgrimes addlist( Elist , *sp ); 1861590Srgrimes eflag = TRUE; 1871590Srgrimes addlist( elist , *sp ); 1881590Srgrimes } 1891590Srgrimes /* 1901590Srgrimes * get information about mon.out file(s). 1911590Srgrimes */ 1921590Srgrimes do { 1931590Srgrimes getpfile( gmonname ); 1941590Srgrimes if ( *argv != 0 ) { 1951590Srgrimes gmonname = *argv; 1961590Srgrimes } 1971590Srgrimes } while ( *argv++ != 0 ); 1981590Srgrimes /* 1991590Srgrimes * how many ticks per second? 2001590Srgrimes * if we can't tell, report time in ticks. 2011590Srgrimes */ 2021590Srgrimes if (hz == 0) { 2031590Srgrimes hz = 1; 2041590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 2051590Srgrimes } 2061590Srgrimes /* 2071590Srgrimes * dump out a gmon.sum file if requested 2081590Srgrimes */ 2091590Srgrimes if ( sflag ) { 2101590Srgrimes dumpsum( GMONSUM ); 2111590Srgrimes } 2121590Srgrimes /* 2131590Srgrimes * assign samples to procedures 2141590Srgrimes */ 2151590Srgrimes asgnsamples(); 2161590Srgrimes /* 2171590Srgrimes * assemble the dynamic profile 2181590Srgrimes */ 2191590Srgrimes timesortnlp = doarcs(); 2201590Srgrimes /* 2211590Srgrimes * print the dynamic profile 2221590Srgrimes */ 2235190Swollman if(!lflag) { 2248874Srgrimes printgprof( timesortnlp ); 2255190Swollman } 2261590Srgrimes /* 2271590Srgrimes * print the flat profile 2281590Srgrimes */ 2295190Swollman if(!Lflag) { 2305190Swollman printprof(); 2315190Swollman } 2321590Srgrimes /* 2331590Srgrimes * print the index 2341590Srgrimes */ 2358874Srgrimes printindex(); 236105243Scharnier exit(0); 2371590Srgrimes} 2381590Srgrimes 2391590Srgrimes /* 2401590Srgrimes * information from a gmon.out file is in two parts: 2411590Srgrimes * an array of sampling hits within pc ranges, 2421590Srgrimes * and the arcs. 2431590Srgrimes */ 244105243Scharniervoid 2451590Srgrimesgetpfile(filename) 2461590Srgrimes char *filename; 2471590Srgrimes{ 2481590Srgrimes FILE *pfile; 2491590Srgrimes FILE *openpfile(); 2501590Srgrimes struct rawarc arc; 2511590Srgrimes 2521590Srgrimes pfile = openpfile(filename); 2531590Srgrimes readsamples(pfile); 2541590Srgrimes /* 2551590Srgrimes * the rest of the file consists of 2561590Srgrimes * a bunch of <from,self,count> tuples. 2571590Srgrimes */ 2581590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2591590Srgrimes# ifdef DEBUG 2601590Srgrimes if ( debug & SAMPLEDEBUG ) { 26191018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2621590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2631590Srgrimes } 26497631Swollman# endif /* DEBUG */ 2651590Srgrimes /* 2661590Srgrimes * add this arc 2671590Srgrimes */ 2681590Srgrimes tally( &arc ); 2691590Srgrimes } 2701590Srgrimes fclose(pfile); 2711590Srgrimes} 2721590Srgrimes 2731590SrgrimesFILE * 2741590Srgrimesopenpfile(filename) 2751590Srgrimes char *filename; 2761590Srgrimes{ 2771590Srgrimes struct gmonhdr tmp; 2781590Srgrimes FILE *pfile; 2791590Srgrimes int size; 2801590Srgrimes int rate; 2811590Srgrimes 282105243Scharnier if((pfile = fopen(filename, "r")) == NULL) 283105243Scharnier err(1, "%s", filename); 2841590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2851590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 286105243Scharnier tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) 287105243Scharnier errx(1, "%s: incompatible with first gmon file", filename); 2881590Srgrimes gmonhdr = tmp; 2891590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2901590Srgrimes rate = gmonhdr.profrate; 2911590Srgrimes size = sizeof(struct gmonhdr); 2921590Srgrimes } else { 2931590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2941590Srgrimes size = sizeof(struct ophdr); 2951590Srgrimes gmonhdr.profrate = rate = hertz(); 2961590Srgrimes gmonhdr.version = GMONVERSION; 2971590Srgrimes } 2981590Srgrimes if (hz == 0) { 2991590Srgrimes hz = rate; 300105243Scharnier } else if (hz != rate) 301105243Scharnier errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file", 3021590Srgrimes filename, rate, "incompatible with clock rate", hz); 30391738Sbde if ( gmonhdr.histcounter_type == 0 ) { 30491738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 30591738Sbde histcounter_type = 16; 30691738Sbde histcounter_size = 2; 30791738Sbde } else { 30891738Sbde histcounter_type = gmonhdr.histcounter_type; 30991738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 31091738Sbde } 3111590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3121590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 31391735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 31491735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3151590Srgrimes sampbytes = gmonhdr.ncnt - size; 31691738Sbde nsamples = sampbytes / histcounter_size; 3171590Srgrimes# ifdef DEBUG 3181590Srgrimes if ( debug & SAMPLEDEBUG ) { 31991018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3201590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 32191018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3221590Srgrimes s_lowpc , s_highpc ); 32391018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3241590Srgrimes lowpc , highpc ); 3251590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3261590Srgrimes sampbytes , nsamples ); 32791018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3281590Srgrimes } 32997631Swollman# endif /* DEBUG */ 3301590Srgrimes return(pfile); 3311590Srgrimes} 3321590Srgrimes 333105243Scharniervoid 3341590Srgrimestally( rawp ) 3351590Srgrimes struct rawarc *rawp; 3361590Srgrimes{ 3371590Srgrimes nltype *parentp; 3381590Srgrimes nltype *childp; 3391590Srgrimes 3401590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3411590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3421590Srgrimes if ( parentp == 0 || childp == 0 ) 3431590Srgrimes return; 3441590Srgrimes if ( kflag 3451590Srgrimes && onlist( kfromlist , parentp -> name ) 3461590Srgrimes && onlist( ktolist , childp -> name ) ) { 3471590Srgrimes return; 3481590Srgrimes } 3491590Srgrimes childp -> ncall += rawp -> raw_count; 3501590Srgrimes# ifdef DEBUG 3511590Srgrimes if ( debug & TALLYDEBUG ) { 35291018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3531590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3541590Srgrimes } 35597631Swollman# endif /* DEBUG */ 3561590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3571590Srgrimes} 3581590Srgrimes 3591590Srgrimes/* 3601590Srgrimes * dump out the gmon.sum file 3611590Srgrimes */ 362105243Scharniervoid 3631590Srgrimesdumpsum( sumfile ) 3641590Srgrimes char *sumfile; 3651590Srgrimes{ 3661590Srgrimes register nltype *nlp; 3671590Srgrimes register arctype *arcp; 3681590Srgrimes struct rawarc arc; 3691590Srgrimes FILE *sfile; 3701590Srgrimes 371105243Scharnier if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) 372105243Scharnier err( 1 , "%s" , sumfile ); 3731590Srgrimes /* 3741590Srgrimes * dump the header; use the last header read in 3751590Srgrimes */ 376105243Scharnier if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) 377105243Scharnier err( 1 , "%s" , sumfile ); 3781590Srgrimes /* 3791590Srgrimes * dump the samples 3801590Srgrimes */ 381105243Scharnier if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) 382105243Scharnier err( 1 , "%s" , sumfile ); 3831590Srgrimes /* 3841590Srgrimes * dump the normalized raw arc information 3851590Srgrimes */ 3861590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3871590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3881590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3891590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3901590Srgrimes arc.raw_count = arcp -> arc_count; 391105243Scharnier if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) 392105243Scharnier err( 1 , "%s" , sumfile ); 3931590Srgrimes# ifdef DEBUG 3941590Srgrimes if ( debug & SAMPLEDEBUG ) { 39591018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 3961590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3971590Srgrimes } 39897631Swollman# endif /* DEBUG */ 3991590Srgrimes } 4001590Srgrimes } 4011590Srgrimes fclose( sfile ); 4021590Srgrimes} 4031590Srgrimes 40438928Sjdpstatic int 40538928Sjdpvalcmp(v1, v2) 40638928Sjdp const void *v1; 40738928Sjdp const void *v2; 4081590Srgrimes{ 40938928Sjdp const nltype *p1 = (const nltype *)v1; 41038928Sjdp const nltype *p2 = (const nltype *)v2; 41138928Sjdp 4121590Srgrimes if ( p1 -> value < p2 -> value ) { 4131590Srgrimes return LESSTHAN; 4141590Srgrimes } 4151590Srgrimes if ( p1 -> value > p2 -> value ) { 4161590Srgrimes return GREATERTHAN; 4171590Srgrimes } 4181590Srgrimes return EQUALTO; 4191590Srgrimes} 4201590Srgrimes 421105243Scharniervoid 4221590Srgrimesreadsamples(pfile) 4231590Srgrimes FILE *pfile; 4241590Srgrimes{ 4251590Srgrimes register i; 42691738Sbde intmax_t sample; 4278874Srgrimes 4281590Srgrimes if (samples == 0) { 42991738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 430105243Scharnier if (samples == 0) 431105243Scharnier errx(0, "no room for %d sample pc's", nsamples); 4321590Srgrimes } 4331590Srgrimes for (i = 0; i < nsamples; i++) { 43491738Sbde fread(&sample, histcounter_size, 1, pfile); 4351590Srgrimes if (feof(pfile)) 4361590Srgrimes break; 43791738Sbde switch ( histcounter_type ) { 43891738Sbde case -8: 43991738Sbde samples[i] += *(int8_t *)&sample; 44091738Sbde break; 44191738Sbde case 8: 44291738Sbde samples[i] += *(u_int8_t *)&sample; 44391738Sbde break; 44491738Sbde case -16: 44591738Sbde samples[i] += *(int16_t *)&sample; 44691738Sbde break; 44791738Sbde case 16: 44891738Sbde samples[i] += *(u_int16_t *)&sample; 44991738Sbde break; 45091738Sbde case -32: 45191738Sbde samples[i] += *(int32_t *)&sample; 45291738Sbde break; 45391738Sbde case 32: 45491738Sbde samples[i] += *(u_int32_t *)&sample; 45591738Sbde break; 45691738Sbde case -64: 45791738Sbde samples[i] += *(int64_t *)&sample; 45891738Sbde break; 45991738Sbde case 64: 46091738Sbde samples[i] += *(u_int64_t *)&sample; 46191738Sbde break; 46291738Sbde default: 46391738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 46491738Sbde } 4651590Srgrimes } 466105243Scharnier if (i != nsamples) 467105243Scharnier errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples ); 4681590Srgrimes} 4691590Srgrimes 4701590Srgrimes/* 4711590Srgrimes * Assign samples to the procedures to which they belong. 4721590Srgrimes * 4731590Srgrimes * There are three cases as to where pcl and pch can be 4741590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4751590Srgrimes * as shown in the following diagram. overlap computes the 4761590Srgrimes * distance between the arrows, the fraction of the sample 4771590Srgrimes * that is to be credited to the routine which starts at svalue0. 4781590Srgrimes * 4791590Srgrimes * svalue0 svalue1 4801590Srgrimes * | | 4811590Srgrimes * v v 4821590Srgrimes * 4831590Srgrimes * +-----------------------------------------------+ 4841590Srgrimes * | | 4851590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4861590Srgrimes * | | | | | | 4871590Srgrimes * +---------+ +---------+ +---------+ 4881590Srgrimes * 4891590Srgrimes * ^ ^ ^ ^ ^ ^ 4901590Srgrimes * | | | | | | 4911590Srgrimes * pcl pch pcl pch pcl pch 4921590Srgrimes * 4931590Srgrimes * For the vax we assert that samples will never fall in the first 4941590Srgrimes * two bytes of any routine, since that is the entry mask, 4951590Srgrimes * thus we give call alignentries() to adjust the entry points if 4961590Srgrimes * the entry mask falls in one bucket but the code for the routine 4971590Srgrimes * doesn't start until the next bucket. In conjunction with the 4981590Srgrimes * alignment of routine addresses, this should allow us to have 4991590Srgrimes * only one sample for every four bytes of text space and never 5001590Srgrimes * have any overlap (the two end cases, above). 5011590Srgrimes */ 502105243Scharniervoid 5031590Srgrimesasgnsamples() 5041590Srgrimes{ 5051590Srgrimes register int j; 50691738Sbde double ccnt; 5071590Srgrimes double time; 5081590Srgrimes unsigned long pcl, pch; 5091590Srgrimes register int i; 5101590Srgrimes unsigned long overlap; 5111590Srgrimes unsigned long svalue0, svalue1; 5121590Srgrimes 5131590Srgrimes /* read samples and assign to namelist symbols */ 5141590Srgrimes scale = highpc - lowpc; 5151590Srgrimes scale /= nsamples; 5161590Srgrimes alignentries(); 5171590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5181590Srgrimes ccnt = samples[i]; 5191590Srgrimes if (ccnt == 0) 5201590Srgrimes continue; 52148839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 52248839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5231590Srgrimes time = ccnt; 5241590Srgrimes# ifdef DEBUG 5251590Srgrimes if ( debug & SAMPLEDEBUG ) { 52691738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5271590Srgrimes pcl , pch , ccnt ); 5281590Srgrimes } 52997631Swollman# endif /* DEBUG */ 5301590Srgrimes totime += time; 5311590Srgrimes for (j = j - 1; j < nname; j++) { 5321590Srgrimes svalue0 = nl[j].svalue; 5331590Srgrimes svalue1 = nl[j+1].svalue; 5341590Srgrimes /* 5358874Srgrimes * if high end of tick is below entry address, 5361590Srgrimes * go for next tick. 5371590Srgrimes */ 5381590Srgrimes if (pch < svalue0) 5391590Srgrimes break; 5401590Srgrimes /* 5411590Srgrimes * if low end of tick into next routine, 5421590Srgrimes * go for next routine. 5431590Srgrimes */ 5441590Srgrimes if (pcl >= svalue1) 5451590Srgrimes continue; 5461590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5471590Srgrimes if (overlap > 0) { 5481590Srgrimes# ifdef DEBUG 5491590Srgrimes if (debug & SAMPLEDEBUG) { 55091018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 55191735Sbde nl[j].value / HISTORICAL_SCALE_2, 55291735Sbde svalue0, svalue1, nl[j].name, 5531590Srgrimes overlap * time / scale, overlap); 5541590Srgrimes } 55597631Swollman# endif /* DEBUG */ 5561590Srgrimes nl[j].time += overlap * time / scale; 5571590Srgrimes } 5581590Srgrimes } 5591590Srgrimes } 5601590Srgrimes# ifdef DEBUG 5611590Srgrimes if (debug & SAMPLEDEBUG) { 5621590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5631590Srgrimes } 56497631Swollman# endif /* DEBUG */ 5651590Srgrimes} 5661590Srgrimes 5671590Srgrimes 5681590Srgrimesunsigned long 5691590Srgrimesmin(a, b) 5701590Srgrimes unsigned long a,b; 5711590Srgrimes{ 5721590Srgrimes if (a<b) 5731590Srgrimes return(a); 5741590Srgrimes return(b); 5751590Srgrimes} 5761590Srgrimes 5771590Srgrimesunsigned long 5781590Srgrimesmax(a, b) 5791590Srgrimes unsigned long a,b; 5801590Srgrimes{ 5811590Srgrimes if (a>b) 5821590Srgrimes return(a); 5831590Srgrimes return(b); 5841590Srgrimes} 5851590Srgrimes 5861590Srgrimes /* 5871590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5881590Srgrimes * and possibly push the scaled entry points over the entry mask, 5891590Srgrimes * if it turns out that the entry point is in one bucket and the code 5901590Srgrimes * for a routine is in the next bucket. 5911590Srgrimes */ 592105243Scharniervoid 5931590Srgrimesalignentries() 5941590Srgrimes{ 5951590Srgrimes register struct nl *nlp; 5961590Srgrimes unsigned long bucket_of_entry; 5971590Srgrimes unsigned long bucket_of_code; 5981590Srgrimes 5991590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 60091735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 6011590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 60291735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 60391735Sbde lowpc) / scale; 6041590Srgrimes if (bucket_of_entry < bucket_of_code) { 6051590Srgrimes# ifdef DEBUG 6061590Srgrimes if (debug & SAMPLEDEBUG) { 60791018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 60891735Sbde nlp->svalue, 60991735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6101590Srgrimes } 61197631Swollman# endif /* DEBUG */ 61291735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6131590Srgrimes } 6141590Srgrimes } 6151590Srgrimes} 616