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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127313Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 36105243Scharnier#if 0 371590Srgrimes#ifndef lint 381590Srgrimesstatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 39105243Scharnier#endif /* not lint */ 4027313Scharnier#endif 41105243Scharnier 4299112Sobrien#include <sys/cdefs.h> 4399112Sobrien__FBSDID("$FreeBSD: releng/10.3/usr.bin/gprof/gprof.c 246783 2013-02-14 08:16:03Z charnier $"); 441590Srgrimes 4527313Scharnier#include <err.h> 4691738Sbde#include <limits.h> 4793123Smike#include <stdint.h> 48129657Sstefanf#include <string.h> 49129657Sstefanf 501590Srgrimes#include "gprof.h" 511590Srgrimes 5238928Sjdpstatic int valcmp(const void *, const void *); 531590Srgrimes 541590Srgrimesstatic struct gmonhdr gmonhdr; 555190Swollmanstatic int lflag; 565190Swollmanstatic int Lflag; 571590Srgrimes 58105243Scharnierint 59246783Scharniermain(int argc, char **argv) 601590Srgrimes{ 611590Srgrimes char **sp; 621590Srgrimes nltype **timesortnlp; 6338928Sjdp char **defaultEs; 641590Srgrimes 651590Srgrimes --argc; 661590Srgrimes argv++; 671590Srgrimes debug = 0; 681590Srgrimes bflag = TRUE; 691590Srgrimes while ( *argv != 0 && **argv == '-' ) { 701590Srgrimes (*argv)++; 711590Srgrimes switch ( **argv ) { 721590Srgrimes case 'a': 731590Srgrimes aflag = TRUE; 741590Srgrimes break; 751590Srgrimes case 'b': 761590Srgrimes bflag = FALSE; 771590Srgrimes break; 781590Srgrimes case 'C': 791590Srgrimes Cflag = TRUE; 801590Srgrimes cyclethreshold = atoi( *++argv ); 811590Srgrimes break; 821590Srgrimes case 'd': 831590Srgrimes dflag = TRUE; 841590Srgrimes setlinebuf(stdout); 851590Srgrimes debug |= atoi( *++argv ); 861590Srgrimes debug |= ANYDEBUG; 871590Srgrimes# ifdef DEBUG 881590Srgrimes printf("[main] debug = %d\n", debug); 8997631Swollman# else /* not DEBUG */ 9027313Scharnier printf("gprof: -d ignored\n"); 9197631Swollman# endif /* DEBUG */ 921590Srgrimes break; 931590Srgrimes case 'E': 941590Srgrimes ++argv; 951590Srgrimes addlist( Elist , *argv ); 961590Srgrimes Eflag = TRUE; 971590Srgrimes addlist( elist , *argv ); 981590Srgrimes eflag = TRUE; 991590Srgrimes break; 1001590Srgrimes case 'e': 1011590Srgrimes addlist( elist , *++argv ); 1021590Srgrimes eflag = TRUE; 1031590Srgrimes break; 1041590Srgrimes case 'F': 1051590Srgrimes ++argv; 1061590Srgrimes addlist( Flist , *argv ); 1071590Srgrimes Fflag = TRUE; 1081590Srgrimes addlist( flist , *argv ); 1091590Srgrimes fflag = TRUE; 1101590Srgrimes break; 1111590Srgrimes case 'f': 1121590Srgrimes addlist( flist , *++argv ); 1131590Srgrimes fflag = TRUE; 1141590Srgrimes break; 1151590Srgrimes case 'k': 1161590Srgrimes addlist( kfromlist , *++argv ); 1171590Srgrimes addlist( ktolist , *++argv ); 1181590Srgrimes kflag = TRUE; 1191590Srgrimes break; 12085739Sgreen case 'K': 12185739Sgreen Kflag = TRUE; 12285739Sgreen break; 123105243Scharnier case 'l': 1245190Swollman lflag = 1; 1255190Swollman Lflag = 0; 1265190Swollman break; 127105243Scharnier case 'L': 1285190Swollman Lflag = 1; 1295190Swollman lflag = 0; 1305190Swollman break; 131105243Scharnier case 's': 1321590Srgrimes sflag = TRUE; 1331590Srgrimes break; 1342513Sbde case 'u': 1352513Sbde uflag = TRUE; 1362513Sbde break; 1371590Srgrimes case 'z': 1381590Srgrimes zflag = TRUE; 1391590Srgrimes break; 1401590Srgrimes } 1411590Srgrimes argv++; 1421590Srgrimes } 1431590Srgrimes if ( *argv != 0 ) { 1441590Srgrimes a_outname = *argv; 1451590Srgrimes argv++; 1461590Srgrimes } else { 1471590Srgrimes a_outname = A_OUTNAME; 1481590Srgrimes } 1491590Srgrimes if ( *argv != 0 ) { 1501590Srgrimes gmonname = *argv; 1511590Srgrimes argv++; 1521590Srgrimes } else { 15347420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 15447420Sjmz strcpy(gmonname, a_outname); 15547420Sjmz strcat(gmonname, ".gmon"); 1561590Srgrimes } 1571590Srgrimes /* 15838928Sjdp * get information from the executable file. 15938928Sjdp */ 16085739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 161187116Sobrien (!Kflag && elf_getnfile(a_outname, &defaultEs) == -1 && 16285739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 16338928Sjdp errx(1, "%s: bad format", a_outname); 16438928Sjdp /* 16538928Sjdp * sort symbol table. 16638928Sjdp */ 16738928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 16838928Sjdp /* 1691590Srgrimes * turn off default functions 1701590Srgrimes */ 17138928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1721590Srgrimes Eflag = TRUE; 1731590Srgrimes addlist( Elist , *sp ); 1741590Srgrimes eflag = TRUE; 1751590Srgrimes addlist( elist , *sp ); 1761590Srgrimes } 1771590Srgrimes /* 1781590Srgrimes * get information about mon.out file(s). 1791590Srgrimes */ 1801590Srgrimes do { 1811590Srgrimes getpfile( gmonname ); 1821590Srgrimes if ( *argv != 0 ) { 1831590Srgrimes gmonname = *argv; 1841590Srgrimes } 1851590Srgrimes } while ( *argv++ != 0 ); 1861590Srgrimes /* 1871590Srgrimes * how many ticks per second? 1881590Srgrimes * if we can't tell, report time in ticks. 1891590Srgrimes */ 1901590Srgrimes if (hz == 0) { 1911590Srgrimes hz = 1; 1921590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1931590Srgrimes } 1941590Srgrimes /* 1951590Srgrimes * dump out a gmon.sum file if requested 1961590Srgrimes */ 1971590Srgrimes if ( sflag ) { 1981590Srgrimes dumpsum( GMONSUM ); 1991590Srgrimes } 2001590Srgrimes /* 2011590Srgrimes * assign samples to procedures 2021590Srgrimes */ 2031590Srgrimes asgnsamples(); 2041590Srgrimes /* 2051590Srgrimes * assemble the dynamic profile 2061590Srgrimes */ 2071590Srgrimes timesortnlp = doarcs(); 2081590Srgrimes /* 2091590Srgrimes * print the dynamic profile 2101590Srgrimes */ 2115190Swollman if(!lflag) { 2128874Srgrimes printgprof( timesortnlp ); 2135190Swollman } 2141590Srgrimes /* 2151590Srgrimes * print the flat profile 2161590Srgrimes */ 2175190Swollman if(!Lflag) { 2185190Swollman printprof(); 2195190Swollman } 2201590Srgrimes /* 2211590Srgrimes * print the index 2221590Srgrimes */ 2238874Srgrimes printindex(); 224105243Scharnier exit(0); 2251590Srgrimes} 2261590Srgrimes 2271590Srgrimes /* 2281590Srgrimes * information from a gmon.out file is in two parts: 2291590Srgrimes * an array of sampling hits within pc ranges, 2301590Srgrimes * and the arcs. 2311590Srgrimes */ 232105243Scharniervoid 233246783Scharniergetpfile(char *filename) 2341590Srgrimes{ 2351590Srgrimes FILE *pfile; 2361590Srgrimes struct rawarc arc; 2371590Srgrimes 2381590Srgrimes pfile = openpfile(filename); 2391590Srgrimes readsamples(pfile); 2401590Srgrimes /* 2411590Srgrimes * the rest of the file consists of 2421590Srgrimes * a bunch of <from,self,count> tuples. 2431590Srgrimes */ 2441590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2451590Srgrimes# ifdef DEBUG 2461590Srgrimes if ( debug & SAMPLEDEBUG ) { 24791018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2481590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2491590Srgrimes } 25097631Swollman# endif /* DEBUG */ 2511590Srgrimes /* 2521590Srgrimes * add this arc 2531590Srgrimes */ 2541590Srgrimes tally( &arc ); 2551590Srgrimes } 2561590Srgrimes fclose(pfile); 2571590Srgrimes} 2581590Srgrimes 2591590SrgrimesFILE * 260246783Scharnieropenpfile(char *filename) 2611590Srgrimes{ 2621590Srgrimes struct gmonhdr tmp; 2631590Srgrimes FILE *pfile; 2641590Srgrimes int size; 2651590Srgrimes int rate; 2661590Srgrimes 267105243Scharnier if((pfile = fopen(filename, "r")) == NULL) 268105243Scharnier err(1, "%s", filename); 2691590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2701590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 271105243Scharnier tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) 272105243Scharnier errx(1, "%s: incompatible with first gmon file", filename); 2731590Srgrimes gmonhdr = tmp; 2741590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2751590Srgrimes rate = gmonhdr.profrate; 2761590Srgrimes size = sizeof(struct gmonhdr); 2771590Srgrimes } else { 2781590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2791590Srgrimes size = sizeof(struct ophdr); 2801590Srgrimes gmonhdr.profrate = rate = hertz(); 2811590Srgrimes gmonhdr.version = GMONVERSION; 2821590Srgrimes } 2831590Srgrimes if (hz == 0) { 2841590Srgrimes hz = rate; 285105243Scharnier } else if (hz != rate) 286105243Scharnier errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file", 2871590Srgrimes filename, rate, "incompatible with clock rate", hz); 28891738Sbde if ( gmonhdr.histcounter_type == 0 ) { 28991738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 29091738Sbde histcounter_type = 16; 29191738Sbde histcounter_size = 2; 29291738Sbde } else { 29391738Sbde histcounter_type = gmonhdr.histcounter_type; 29491738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 29591738Sbde } 2961590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 2971590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 29891735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 29991735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3001590Srgrimes sampbytes = gmonhdr.ncnt - size; 30191738Sbde nsamples = sampbytes / histcounter_size; 3021590Srgrimes# ifdef DEBUG 3031590Srgrimes if ( debug & SAMPLEDEBUG ) { 30491018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3051590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 30691018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3071590Srgrimes s_lowpc , s_highpc ); 30891018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3091590Srgrimes lowpc , highpc ); 3101590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3111590Srgrimes sampbytes , nsamples ); 31291018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3131590Srgrimes } 31497631Swollman# endif /* DEBUG */ 3151590Srgrimes return(pfile); 3161590Srgrimes} 3171590Srgrimes 318105243Scharniervoid 319246783Scharniertally(struct rawarc *rawp) 3201590Srgrimes{ 3211590Srgrimes nltype *parentp; 3221590Srgrimes nltype *childp; 3231590Srgrimes 3241590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3251590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3261590Srgrimes if ( parentp == 0 || childp == 0 ) 3271590Srgrimes return; 3281590Srgrimes if ( kflag 3291590Srgrimes && onlist( kfromlist , parentp -> name ) 3301590Srgrimes && onlist( ktolist , childp -> name ) ) { 3311590Srgrimes return; 3321590Srgrimes } 3331590Srgrimes childp -> ncall += rawp -> raw_count; 3341590Srgrimes# ifdef DEBUG 3351590Srgrimes if ( debug & TALLYDEBUG ) { 33691018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3371590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3381590Srgrimes } 33997631Swollman# endif /* DEBUG */ 3401590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3411590Srgrimes} 3421590Srgrimes 3431590Srgrimes/* 3441590Srgrimes * dump out the gmon.sum file 3451590Srgrimes */ 346105243Scharniervoid 347246783Scharnierdumpsum(const char *sumfile) 3481590Srgrimes{ 3491590Srgrimes register nltype *nlp; 3501590Srgrimes register arctype *arcp; 3511590Srgrimes struct rawarc arc; 3521590Srgrimes FILE *sfile; 3531590Srgrimes 354105243Scharnier if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) 355105243Scharnier err( 1 , "%s" , sumfile ); 3561590Srgrimes /* 3571590Srgrimes * dump the header; use the last header read in 3581590Srgrimes */ 359105243Scharnier if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) 360105243Scharnier err( 1 , "%s" , sumfile ); 3611590Srgrimes /* 3621590Srgrimes * dump the samples 3631590Srgrimes */ 364105243Scharnier if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) 365105243Scharnier err( 1 , "%s" , sumfile ); 3661590Srgrimes /* 3671590Srgrimes * dump the normalized raw arc information 3681590Srgrimes */ 3691590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3701590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3711590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3721590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3731590Srgrimes arc.raw_count = arcp -> arc_count; 374105243Scharnier if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) 375105243Scharnier err( 1 , "%s" , sumfile ); 3761590Srgrimes# ifdef DEBUG 3771590Srgrimes if ( debug & SAMPLEDEBUG ) { 37891018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 3791590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3801590Srgrimes } 38197631Swollman# endif /* DEBUG */ 3821590Srgrimes } 3831590Srgrimes } 3841590Srgrimes fclose( sfile ); 3851590Srgrimes} 3861590Srgrimes 38738928Sjdpstatic int 388246783Scharniervalcmp(const void *v1, const void *v2) 3891590Srgrimes{ 39038928Sjdp const nltype *p1 = (const nltype *)v1; 39138928Sjdp const nltype *p2 = (const nltype *)v2; 39238928Sjdp 3931590Srgrimes if ( p1 -> value < p2 -> value ) { 3941590Srgrimes return LESSTHAN; 3951590Srgrimes } 3961590Srgrimes if ( p1 -> value > p2 -> value ) { 3971590Srgrimes return GREATERTHAN; 3981590Srgrimes } 3991590Srgrimes return EQUALTO; 4001590Srgrimes} 4011590Srgrimes 402105243Scharniervoid 403246783Scharnierreadsamples(FILE *pfile) 4041590Srgrimes{ 405131990Sstefanf int i; 40691738Sbde intmax_t sample; 4078874Srgrimes 4081590Srgrimes if (samples == 0) { 40991738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 410105243Scharnier if (samples == 0) 411105243Scharnier errx(0, "no room for %d sample pc's", nsamples); 4121590Srgrimes } 4131590Srgrimes for (i = 0; i < nsamples; i++) { 41491738Sbde fread(&sample, histcounter_size, 1, pfile); 4151590Srgrimes if (feof(pfile)) 4161590Srgrimes break; 41791738Sbde switch ( histcounter_type ) { 41891738Sbde case -8: 41991738Sbde samples[i] += *(int8_t *)&sample; 42091738Sbde break; 42191738Sbde case 8: 42291738Sbde samples[i] += *(u_int8_t *)&sample; 42391738Sbde break; 42491738Sbde case -16: 42591738Sbde samples[i] += *(int16_t *)&sample; 42691738Sbde break; 42791738Sbde case 16: 42891738Sbde samples[i] += *(u_int16_t *)&sample; 42991738Sbde break; 43091738Sbde case -32: 43191738Sbde samples[i] += *(int32_t *)&sample; 43291738Sbde break; 43391738Sbde case 32: 43491738Sbde samples[i] += *(u_int32_t *)&sample; 43591738Sbde break; 43691738Sbde case -64: 43791738Sbde samples[i] += *(int64_t *)&sample; 43891738Sbde break; 43991738Sbde case 64: 44091738Sbde samples[i] += *(u_int64_t *)&sample; 44191738Sbde break; 44291738Sbde default: 44391738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 44491738Sbde } 4451590Srgrimes } 446105243Scharnier if (i != nsamples) 447105243Scharnier errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples ); 4481590Srgrimes} 4491590Srgrimes 4501590Srgrimes/* 4511590Srgrimes * Assign samples to the procedures to which they belong. 4521590Srgrimes * 4531590Srgrimes * There are three cases as to where pcl and pch can be 4541590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4551590Srgrimes * as shown in the following diagram. overlap computes the 4561590Srgrimes * distance between the arrows, the fraction of the sample 4571590Srgrimes * that is to be credited to the routine which starts at svalue0. 4581590Srgrimes * 4591590Srgrimes * svalue0 svalue1 4601590Srgrimes * | | 4611590Srgrimes * v v 4621590Srgrimes * 4631590Srgrimes * +-----------------------------------------------+ 4641590Srgrimes * | | 4651590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4661590Srgrimes * | | | | | | 4671590Srgrimes * +---------+ +---------+ +---------+ 4681590Srgrimes * 4691590Srgrimes * ^ ^ ^ ^ ^ ^ 4701590Srgrimes * | | | | | | 4711590Srgrimes * pcl pch pcl pch pcl pch 4721590Srgrimes * 4731590Srgrimes * For the vax we assert that samples will never fall in the first 4741590Srgrimes * two bytes of any routine, since that is the entry mask, 4751590Srgrimes * thus we give call alignentries() to adjust the entry points if 4761590Srgrimes * the entry mask falls in one bucket but the code for the routine 4771590Srgrimes * doesn't start until the next bucket. In conjunction with the 4781590Srgrimes * alignment of routine addresses, this should allow us to have 4791590Srgrimes * only one sample for every four bytes of text space and never 4801590Srgrimes * have any overlap (the two end cases, above). 4811590Srgrimes */ 482105243Scharniervoid 483246783Scharnierasgnsamples(void) 4841590Srgrimes{ 4851590Srgrimes register int j; 48691738Sbde double ccnt; 487246783Scharnier double thetime; 4881590Srgrimes unsigned long pcl, pch; 4891590Srgrimes register int i; 4901590Srgrimes unsigned long overlap; 4911590Srgrimes unsigned long svalue0, svalue1; 4921590Srgrimes 4931590Srgrimes /* read samples and assign to namelist symbols */ 4941590Srgrimes scale = highpc - lowpc; 4951590Srgrimes scale /= nsamples; 4961590Srgrimes alignentries(); 4971590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 4981590Srgrimes ccnt = samples[i]; 4991590Srgrimes if (ccnt == 0) 5001590Srgrimes continue; 50148839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 50248839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 503246783Scharnier thetime = ccnt; 5041590Srgrimes# ifdef DEBUG 5051590Srgrimes if ( debug & SAMPLEDEBUG ) { 50691738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5071590Srgrimes pcl , pch , ccnt ); 5081590Srgrimes } 50997631Swollman# endif /* DEBUG */ 510246783Scharnier totime += thetime; 5111590Srgrimes for (j = j - 1; j < nname; j++) { 5121590Srgrimes svalue0 = nl[j].svalue; 5131590Srgrimes svalue1 = nl[j+1].svalue; 5141590Srgrimes /* 5158874Srgrimes * if high end of tick is below entry address, 5161590Srgrimes * go for next tick. 5171590Srgrimes */ 5181590Srgrimes if (pch < svalue0) 5191590Srgrimes break; 5201590Srgrimes /* 5211590Srgrimes * if low end of tick into next routine, 5221590Srgrimes * go for next routine. 5231590Srgrimes */ 5241590Srgrimes if (pcl >= svalue1) 5251590Srgrimes continue; 5261590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5271590Srgrimes if (overlap > 0) { 5281590Srgrimes# ifdef DEBUG 5291590Srgrimes if (debug & SAMPLEDEBUG) { 53091018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 53191735Sbde nl[j].value / HISTORICAL_SCALE_2, 53291735Sbde svalue0, svalue1, nl[j].name, 533246783Scharnier overlap * thetime / scale, overlap); 5341590Srgrimes } 53597631Swollman# endif /* DEBUG */ 536246783Scharnier nl[j].time += overlap * thetime / scale; 5371590Srgrimes } 5381590Srgrimes } 5391590Srgrimes } 5401590Srgrimes# ifdef DEBUG 5411590Srgrimes if (debug & SAMPLEDEBUG) { 5421590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5431590Srgrimes } 54497631Swollman# endif /* DEBUG */ 5451590Srgrimes} 5461590Srgrimes 5471590Srgrimes 5481590Srgrimesunsigned long 549246783Scharniermin(unsigned long a, unsigned long b) 5501590Srgrimes{ 5511590Srgrimes if (a<b) 5521590Srgrimes return(a); 5531590Srgrimes return(b); 5541590Srgrimes} 5551590Srgrimes 5561590Srgrimesunsigned long 557246783Scharniermax(unsigned long a, unsigned long b) 5581590Srgrimes{ 5591590Srgrimes if (a>b) 5601590Srgrimes return(a); 5611590Srgrimes return(b); 5621590Srgrimes} 5631590Srgrimes 5641590Srgrimes /* 5651590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5661590Srgrimes * and possibly push the scaled entry points over the entry mask, 5671590Srgrimes * if it turns out that the entry point is in one bucket and the code 5681590Srgrimes * for a routine is in the next bucket. 5691590Srgrimes */ 570105243Scharniervoid 571246783Scharnieralignentries(void) 5721590Srgrimes{ 5731590Srgrimes register struct nl *nlp; 5741590Srgrimes unsigned long bucket_of_entry; 5751590Srgrimes unsigned long bucket_of_code; 5761590Srgrimes 5771590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 57891735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 5791590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 58091735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 58191735Sbde lowpc) / scale; 5821590Srgrimes if (bucket_of_entry < bucket_of_code) { 5831590Srgrimes# ifdef DEBUG 5841590Srgrimes if (debug & SAMPLEDEBUG) { 58591018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 58691735Sbde nlp->svalue, 58791735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 5881590Srgrimes } 58997631Swollman# endif /* DEBUG */ 59091735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 5911590Srgrimes } 5921590Srgrimes } 5931590Srgrimes} 594