gprof.c revision 187116
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 187116 2009-01-12 21:49:42Z obrien $"); 481590Srgrimes 4927313Scharnier#include <err.h> 5091738Sbde#include <limits.h> 5193123Smike#include <stdint.h> 52129657Sstefanf#include <string.h> 53129657Sstefanf 541590Srgrimes#include "gprof.h" 551590Srgrimes 5638928Sjdpstatic int valcmp(const void *, const void *); 571590Srgrimes 5838928Sjdp 591590Srgrimesstatic struct gmonhdr gmonhdr; 605190Swollmanstatic int lflag; 615190Swollmanstatic int Lflag; 621590Srgrimes 63105243Scharnierint 641590Srgrimesmain(argc, argv) 651590Srgrimes int argc; 661590Srgrimes char **argv; 671590Srgrimes{ 681590Srgrimes char **sp; 691590Srgrimes nltype **timesortnlp; 7038928Sjdp char **defaultEs; 711590Srgrimes 721590Srgrimes --argc; 731590Srgrimes argv++; 741590Srgrimes debug = 0; 751590Srgrimes bflag = TRUE; 761590Srgrimes while ( *argv != 0 && **argv == '-' ) { 771590Srgrimes (*argv)++; 781590Srgrimes switch ( **argv ) { 791590Srgrimes case 'a': 801590Srgrimes aflag = TRUE; 811590Srgrimes break; 821590Srgrimes case 'b': 831590Srgrimes bflag = FALSE; 841590Srgrimes break; 851590Srgrimes case 'C': 861590Srgrimes Cflag = TRUE; 871590Srgrimes cyclethreshold = atoi( *++argv ); 881590Srgrimes break; 891590Srgrimes case 'd': 901590Srgrimes dflag = TRUE; 911590Srgrimes setlinebuf(stdout); 921590Srgrimes debug |= atoi( *++argv ); 931590Srgrimes debug |= ANYDEBUG; 941590Srgrimes# ifdef DEBUG 951590Srgrimes printf("[main] debug = %d\n", debug); 9697631Swollman# else /* not DEBUG */ 9727313Scharnier printf("gprof: -d ignored\n"); 9897631Swollman# endif /* DEBUG */ 991590Srgrimes break; 1001590Srgrimes case 'E': 1011590Srgrimes ++argv; 1021590Srgrimes addlist( Elist , *argv ); 1031590Srgrimes Eflag = TRUE; 1041590Srgrimes addlist( elist , *argv ); 1051590Srgrimes eflag = TRUE; 1061590Srgrimes break; 1071590Srgrimes case 'e': 1081590Srgrimes addlist( elist , *++argv ); 1091590Srgrimes eflag = TRUE; 1101590Srgrimes break; 1111590Srgrimes case 'F': 1121590Srgrimes ++argv; 1131590Srgrimes addlist( Flist , *argv ); 1141590Srgrimes Fflag = TRUE; 1151590Srgrimes addlist( flist , *argv ); 1161590Srgrimes fflag = TRUE; 1171590Srgrimes break; 1181590Srgrimes case 'f': 1191590Srgrimes addlist( flist , *++argv ); 1201590Srgrimes fflag = TRUE; 1211590Srgrimes break; 1221590Srgrimes case 'k': 1231590Srgrimes addlist( kfromlist , *++argv ); 1241590Srgrimes addlist( ktolist , *++argv ); 1251590Srgrimes kflag = TRUE; 1261590Srgrimes break; 12785739Sgreen case 'K': 12885739Sgreen Kflag = TRUE; 12985739Sgreen break; 130105243Scharnier case 'l': 1315190Swollman lflag = 1; 1325190Swollman Lflag = 0; 1335190Swollman break; 134105243Scharnier case 'L': 1355190Swollman Lflag = 1; 1365190Swollman lflag = 0; 1375190Swollman break; 138105243Scharnier case 's': 1391590Srgrimes sflag = TRUE; 1401590Srgrimes break; 1412513Sbde case 'u': 1422513Sbde uflag = TRUE; 1432513Sbde break; 1441590Srgrimes case 'z': 1451590Srgrimes zflag = TRUE; 1461590Srgrimes break; 1471590Srgrimes } 1481590Srgrimes argv++; 1491590Srgrimes } 1501590Srgrimes if ( *argv != 0 ) { 1511590Srgrimes a_outname = *argv; 1521590Srgrimes argv++; 1531590Srgrimes } else { 1541590Srgrimes a_outname = A_OUTNAME; 1551590Srgrimes } 1561590Srgrimes if ( *argv != 0 ) { 1571590Srgrimes gmonname = *argv; 1581590Srgrimes argv++; 1591590Srgrimes } else { 16047420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 16147420Sjmz strcpy(gmonname, a_outname); 16247420Sjmz strcat(gmonname, ".gmon"); 1631590Srgrimes } 1641590Srgrimes /* 16538928Sjdp * get information from the executable file. 16638928Sjdp */ 16785739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 168187116Sobrien (!Kflag && elf_getnfile(a_outname, &defaultEs) == -1 && 16985739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 17038928Sjdp errx(1, "%s: bad format", a_outname); 17138928Sjdp /* 17238928Sjdp * sort symbol table. 17338928Sjdp */ 17438928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17538928Sjdp /* 1761590Srgrimes * turn off default functions 1771590Srgrimes */ 17838928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1791590Srgrimes Eflag = TRUE; 1801590Srgrimes addlist( Elist , *sp ); 1811590Srgrimes eflag = TRUE; 1821590Srgrimes addlist( elist , *sp ); 1831590Srgrimes } 1841590Srgrimes /* 1851590Srgrimes * get information about mon.out file(s). 1861590Srgrimes */ 1871590Srgrimes do { 1881590Srgrimes getpfile( gmonname ); 1891590Srgrimes if ( *argv != 0 ) { 1901590Srgrimes gmonname = *argv; 1911590Srgrimes } 1921590Srgrimes } while ( *argv++ != 0 ); 1931590Srgrimes /* 1941590Srgrimes * how many ticks per second? 1951590Srgrimes * if we can't tell, report time in ticks. 1961590Srgrimes */ 1971590Srgrimes if (hz == 0) { 1981590Srgrimes hz = 1; 1991590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 2001590Srgrimes } 2011590Srgrimes /* 2021590Srgrimes * dump out a gmon.sum file if requested 2031590Srgrimes */ 2041590Srgrimes if ( sflag ) { 2051590Srgrimes dumpsum( GMONSUM ); 2061590Srgrimes } 2071590Srgrimes /* 2081590Srgrimes * assign samples to procedures 2091590Srgrimes */ 2101590Srgrimes asgnsamples(); 2111590Srgrimes /* 2121590Srgrimes * assemble the dynamic profile 2131590Srgrimes */ 2141590Srgrimes timesortnlp = doarcs(); 2151590Srgrimes /* 2161590Srgrimes * print the dynamic profile 2171590Srgrimes */ 2185190Swollman if(!lflag) { 2198874Srgrimes printgprof( timesortnlp ); 2205190Swollman } 2211590Srgrimes /* 2221590Srgrimes * print the flat profile 2231590Srgrimes */ 2245190Swollman if(!Lflag) { 2255190Swollman printprof(); 2265190Swollman } 2271590Srgrimes /* 2281590Srgrimes * print the index 2291590Srgrimes */ 2308874Srgrimes printindex(); 231105243Scharnier exit(0); 2321590Srgrimes} 2331590Srgrimes 2341590Srgrimes /* 2351590Srgrimes * information from a gmon.out file is in two parts: 2361590Srgrimes * an array of sampling hits within pc ranges, 2371590Srgrimes * and the arcs. 2381590Srgrimes */ 239105243Scharniervoid 2401590Srgrimesgetpfile(filename) 2411590Srgrimes char *filename; 2421590Srgrimes{ 2431590Srgrimes FILE *pfile; 2441590Srgrimes FILE *openpfile(); 2451590Srgrimes struct rawarc arc; 2461590Srgrimes 2471590Srgrimes pfile = openpfile(filename); 2481590Srgrimes readsamples(pfile); 2491590Srgrimes /* 2501590Srgrimes * the rest of the file consists of 2511590Srgrimes * a bunch of <from,self,count> tuples. 2521590Srgrimes */ 2531590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2541590Srgrimes# ifdef DEBUG 2551590Srgrimes if ( debug & SAMPLEDEBUG ) { 25691018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2571590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2581590Srgrimes } 25997631Swollman# endif /* DEBUG */ 2601590Srgrimes /* 2611590Srgrimes * add this arc 2621590Srgrimes */ 2631590Srgrimes tally( &arc ); 2641590Srgrimes } 2651590Srgrimes fclose(pfile); 2661590Srgrimes} 2671590Srgrimes 2681590SrgrimesFILE * 2691590Srgrimesopenpfile(filename) 2701590Srgrimes char *filename; 2711590Srgrimes{ 2721590Srgrimes struct gmonhdr tmp; 2731590Srgrimes FILE *pfile; 2741590Srgrimes int size; 2751590Srgrimes int rate; 2761590Srgrimes 277105243Scharnier if((pfile = fopen(filename, "r")) == NULL) 278105243Scharnier err(1, "%s", filename); 2791590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2801590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 281105243Scharnier tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) 282105243Scharnier errx(1, "%s: incompatible with first gmon file", filename); 2831590Srgrimes gmonhdr = tmp; 2841590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2851590Srgrimes rate = gmonhdr.profrate; 2861590Srgrimes size = sizeof(struct gmonhdr); 2871590Srgrimes } else { 2881590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2891590Srgrimes size = sizeof(struct ophdr); 2901590Srgrimes gmonhdr.profrate = rate = hertz(); 2911590Srgrimes gmonhdr.version = GMONVERSION; 2921590Srgrimes } 2931590Srgrimes if (hz == 0) { 2941590Srgrimes hz = rate; 295105243Scharnier } else if (hz != rate) 296105243Scharnier errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file", 2971590Srgrimes filename, rate, "incompatible with clock rate", hz); 29891738Sbde if ( gmonhdr.histcounter_type == 0 ) { 29991738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 30091738Sbde histcounter_type = 16; 30191738Sbde histcounter_size = 2; 30291738Sbde } else { 30391738Sbde histcounter_type = gmonhdr.histcounter_type; 30491738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 30591738Sbde } 3061590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3071590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 30891735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 30991735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3101590Srgrimes sampbytes = gmonhdr.ncnt - size; 31191738Sbde nsamples = sampbytes / histcounter_size; 3121590Srgrimes# ifdef DEBUG 3131590Srgrimes if ( debug & SAMPLEDEBUG ) { 31491018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3151590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 31691018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3171590Srgrimes s_lowpc , s_highpc ); 31891018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3191590Srgrimes lowpc , highpc ); 3201590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3211590Srgrimes sampbytes , nsamples ); 32291018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3231590Srgrimes } 32497631Swollman# endif /* DEBUG */ 3251590Srgrimes return(pfile); 3261590Srgrimes} 3271590Srgrimes 328105243Scharniervoid 3291590Srgrimestally( rawp ) 3301590Srgrimes struct rawarc *rawp; 3311590Srgrimes{ 3321590Srgrimes nltype *parentp; 3331590Srgrimes nltype *childp; 3341590Srgrimes 3351590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3361590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3371590Srgrimes if ( parentp == 0 || childp == 0 ) 3381590Srgrimes return; 3391590Srgrimes if ( kflag 3401590Srgrimes && onlist( kfromlist , parentp -> name ) 3411590Srgrimes && onlist( ktolist , childp -> name ) ) { 3421590Srgrimes return; 3431590Srgrimes } 3441590Srgrimes childp -> ncall += rawp -> raw_count; 3451590Srgrimes# ifdef DEBUG 3461590Srgrimes if ( debug & TALLYDEBUG ) { 34791018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3481590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3491590Srgrimes } 35097631Swollman# endif /* DEBUG */ 3511590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3521590Srgrimes} 3531590Srgrimes 3541590Srgrimes/* 3551590Srgrimes * dump out the gmon.sum file 3561590Srgrimes */ 357105243Scharniervoid 3581590Srgrimesdumpsum( sumfile ) 3591590Srgrimes char *sumfile; 3601590Srgrimes{ 3611590Srgrimes register nltype *nlp; 3621590Srgrimes register arctype *arcp; 3631590Srgrimes struct rawarc arc; 3641590Srgrimes FILE *sfile; 3651590Srgrimes 366105243Scharnier if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) 367105243Scharnier err( 1 , "%s" , sumfile ); 3681590Srgrimes /* 3691590Srgrimes * dump the header; use the last header read in 3701590Srgrimes */ 371105243Scharnier if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) 372105243Scharnier err( 1 , "%s" , sumfile ); 3731590Srgrimes /* 3741590Srgrimes * dump the samples 3751590Srgrimes */ 376105243Scharnier if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) 377105243Scharnier err( 1 , "%s" , sumfile ); 3781590Srgrimes /* 3791590Srgrimes * dump the normalized raw arc information 3801590Srgrimes */ 3811590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3821590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3831590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3841590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3851590Srgrimes arc.raw_count = arcp -> arc_count; 386105243Scharnier if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) 387105243Scharnier err( 1 , "%s" , sumfile ); 3881590Srgrimes# ifdef DEBUG 3891590Srgrimes if ( debug & SAMPLEDEBUG ) { 39091018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 3911590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3921590Srgrimes } 39397631Swollman# endif /* DEBUG */ 3941590Srgrimes } 3951590Srgrimes } 3961590Srgrimes fclose( sfile ); 3971590Srgrimes} 3981590Srgrimes 39938928Sjdpstatic int 40038928Sjdpvalcmp(v1, v2) 40138928Sjdp const void *v1; 40238928Sjdp const void *v2; 4031590Srgrimes{ 40438928Sjdp const nltype *p1 = (const nltype *)v1; 40538928Sjdp const nltype *p2 = (const nltype *)v2; 40638928Sjdp 4071590Srgrimes if ( p1 -> value < p2 -> value ) { 4081590Srgrimes return LESSTHAN; 4091590Srgrimes } 4101590Srgrimes if ( p1 -> value > p2 -> value ) { 4111590Srgrimes return GREATERTHAN; 4121590Srgrimes } 4131590Srgrimes return EQUALTO; 4141590Srgrimes} 4151590Srgrimes 416105243Scharniervoid 4171590Srgrimesreadsamples(pfile) 4181590Srgrimes FILE *pfile; 4191590Srgrimes{ 420131990Sstefanf int i; 42191738Sbde intmax_t sample; 4228874Srgrimes 4231590Srgrimes if (samples == 0) { 42491738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 425105243Scharnier if (samples == 0) 426105243Scharnier errx(0, "no room for %d sample pc's", nsamples); 4271590Srgrimes } 4281590Srgrimes for (i = 0; i < nsamples; i++) { 42991738Sbde fread(&sample, histcounter_size, 1, pfile); 4301590Srgrimes if (feof(pfile)) 4311590Srgrimes break; 43291738Sbde switch ( histcounter_type ) { 43391738Sbde case -8: 43491738Sbde samples[i] += *(int8_t *)&sample; 43591738Sbde break; 43691738Sbde case 8: 43791738Sbde samples[i] += *(u_int8_t *)&sample; 43891738Sbde break; 43991738Sbde case -16: 44091738Sbde samples[i] += *(int16_t *)&sample; 44191738Sbde break; 44291738Sbde case 16: 44391738Sbde samples[i] += *(u_int16_t *)&sample; 44491738Sbde break; 44591738Sbde case -32: 44691738Sbde samples[i] += *(int32_t *)&sample; 44791738Sbde break; 44891738Sbde case 32: 44991738Sbde samples[i] += *(u_int32_t *)&sample; 45091738Sbde break; 45191738Sbde case -64: 45291738Sbde samples[i] += *(int64_t *)&sample; 45391738Sbde break; 45491738Sbde case 64: 45591738Sbde samples[i] += *(u_int64_t *)&sample; 45691738Sbde break; 45791738Sbde default: 45891738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 45991738Sbde } 4601590Srgrimes } 461105243Scharnier if (i != nsamples) 462105243Scharnier errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples ); 4631590Srgrimes} 4641590Srgrimes 4651590Srgrimes/* 4661590Srgrimes * Assign samples to the procedures to which they belong. 4671590Srgrimes * 4681590Srgrimes * There are three cases as to where pcl and pch can be 4691590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4701590Srgrimes * as shown in the following diagram. overlap computes the 4711590Srgrimes * distance between the arrows, the fraction of the sample 4721590Srgrimes * that is to be credited to the routine which starts at svalue0. 4731590Srgrimes * 4741590Srgrimes * svalue0 svalue1 4751590Srgrimes * | | 4761590Srgrimes * v v 4771590Srgrimes * 4781590Srgrimes * +-----------------------------------------------+ 4791590Srgrimes * | | 4801590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4811590Srgrimes * | | | | | | 4821590Srgrimes * +---------+ +---------+ +---------+ 4831590Srgrimes * 4841590Srgrimes * ^ ^ ^ ^ ^ ^ 4851590Srgrimes * | | | | | | 4861590Srgrimes * pcl pch pcl pch pcl pch 4871590Srgrimes * 4881590Srgrimes * For the vax we assert that samples will never fall in the first 4891590Srgrimes * two bytes of any routine, since that is the entry mask, 4901590Srgrimes * thus we give call alignentries() to adjust the entry points if 4911590Srgrimes * the entry mask falls in one bucket but the code for the routine 4921590Srgrimes * doesn't start until the next bucket. In conjunction with the 4931590Srgrimes * alignment of routine addresses, this should allow us to have 4941590Srgrimes * only one sample for every four bytes of text space and never 4951590Srgrimes * have any overlap (the two end cases, above). 4961590Srgrimes */ 497105243Scharniervoid 4981590Srgrimesasgnsamples() 4991590Srgrimes{ 5001590Srgrimes register int j; 50191738Sbde double ccnt; 5021590Srgrimes double time; 5031590Srgrimes unsigned long pcl, pch; 5041590Srgrimes register int i; 5051590Srgrimes unsigned long overlap; 5061590Srgrimes unsigned long svalue0, svalue1; 5071590Srgrimes 5081590Srgrimes /* read samples and assign to namelist symbols */ 5091590Srgrimes scale = highpc - lowpc; 5101590Srgrimes scale /= nsamples; 5111590Srgrimes alignentries(); 5121590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5131590Srgrimes ccnt = samples[i]; 5141590Srgrimes if (ccnt == 0) 5151590Srgrimes continue; 51648839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 51748839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5181590Srgrimes time = ccnt; 5191590Srgrimes# ifdef DEBUG 5201590Srgrimes if ( debug & SAMPLEDEBUG ) { 52191738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5221590Srgrimes pcl , pch , ccnt ); 5231590Srgrimes } 52497631Swollman# endif /* DEBUG */ 5251590Srgrimes totime += time; 5261590Srgrimes for (j = j - 1; j < nname; j++) { 5271590Srgrimes svalue0 = nl[j].svalue; 5281590Srgrimes svalue1 = nl[j+1].svalue; 5291590Srgrimes /* 5308874Srgrimes * if high end of tick is below entry address, 5311590Srgrimes * go for next tick. 5321590Srgrimes */ 5331590Srgrimes if (pch < svalue0) 5341590Srgrimes break; 5351590Srgrimes /* 5361590Srgrimes * if low end of tick into next routine, 5371590Srgrimes * go for next routine. 5381590Srgrimes */ 5391590Srgrimes if (pcl >= svalue1) 5401590Srgrimes continue; 5411590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5421590Srgrimes if (overlap > 0) { 5431590Srgrimes# ifdef DEBUG 5441590Srgrimes if (debug & SAMPLEDEBUG) { 54591018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 54691735Sbde nl[j].value / HISTORICAL_SCALE_2, 54791735Sbde svalue0, svalue1, nl[j].name, 5481590Srgrimes overlap * time / scale, overlap); 5491590Srgrimes } 55097631Swollman# endif /* DEBUG */ 5511590Srgrimes nl[j].time += overlap * time / scale; 5521590Srgrimes } 5531590Srgrimes } 5541590Srgrimes } 5551590Srgrimes# ifdef DEBUG 5561590Srgrimes if (debug & SAMPLEDEBUG) { 5571590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5581590Srgrimes } 55997631Swollman# endif /* DEBUG */ 5601590Srgrimes} 5611590Srgrimes 5621590Srgrimes 5631590Srgrimesunsigned long 5641590Srgrimesmin(a, b) 5651590Srgrimes unsigned long a,b; 5661590Srgrimes{ 5671590Srgrimes if (a<b) 5681590Srgrimes return(a); 5691590Srgrimes return(b); 5701590Srgrimes} 5711590Srgrimes 5721590Srgrimesunsigned long 5731590Srgrimesmax(a, b) 5741590Srgrimes unsigned long a,b; 5751590Srgrimes{ 5761590Srgrimes if (a>b) 5771590Srgrimes return(a); 5781590Srgrimes return(b); 5791590Srgrimes} 5801590Srgrimes 5811590Srgrimes /* 5821590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5831590Srgrimes * and possibly push the scaled entry points over the entry mask, 5841590Srgrimes * if it turns out that the entry point is in one bucket and the code 5851590Srgrimes * for a routine is in the next bucket. 5861590Srgrimes */ 587105243Scharniervoid 5881590Srgrimesalignentries() 5891590Srgrimes{ 5901590Srgrimes register struct nl *nlp; 5911590Srgrimes unsigned long bucket_of_entry; 5921590Srgrimes unsigned long bucket_of_code; 5931590Srgrimes 5941590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 59591735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 5961590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 59791735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 59891735Sbde lowpc) / scale; 5991590Srgrimes if (bucket_of_entry < bucket_of_code) { 6001590Srgrimes# ifdef DEBUG 6011590Srgrimes if (debug & SAMPLEDEBUG) { 60291018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 60391735Sbde nlp->svalue, 60491735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6051590Srgrimes } 60697631Swollman# endif /* DEBUG */ 60791735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6081590Srgrimes } 6091590Srgrimes } 6101590Srgrimes} 611