gprof.c revision 129657
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 129657 2004-05-24 12:44:00Z stefanf $"); 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 'c': 90121735Stjr#if 0 911590Srgrimes cflag = TRUE; 921590Srgrimes#else 9327313Scharnier errx(1, "-c isn't supported on this architecture yet"); 941590Srgrimes#endif 951590Srgrimes break; 961590Srgrimes case 'd': 971590Srgrimes dflag = TRUE; 981590Srgrimes setlinebuf(stdout); 991590Srgrimes debug |= atoi( *++argv ); 1001590Srgrimes debug |= ANYDEBUG; 1011590Srgrimes# ifdef DEBUG 1021590Srgrimes printf("[main] debug = %d\n", debug); 10397631Swollman# else /* not DEBUG */ 10427313Scharnier printf("gprof: -d ignored\n"); 10597631Swollman# endif /* DEBUG */ 1061590Srgrimes break; 1071590Srgrimes case 'E': 1081590Srgrimes ++argv; 1091590Srgrimes addlist( Elist , *argv ); 1101590Srgrimes Eflag = TRUE; 1111590Srgrimes addlist( elist , *argv ); 1121590Srgrimes eflag = TRUE; 1131590Srgrimes break; 1141590Srgrimes case 'e': 1151590Srgrimes addlist( elist , *++argv ); 1161590Srgrimes eflag = TRUE; 1171590Srgrimes break; 1181590Srgrimes case 'F': 1191590Srgrimes ++argv; 1201590Srgrimes addlist( Flist , *argv ); 1211590Srgrimes Fflag = TRUE; 1221590Srgrimes addlist( flist , *argv ); 1231590Srgrimes fflag = TRUE; 1241590Srgrimes break; 1251590Srgrimes case 'f': 1261590Srgrimes addlist( flist , *++argv ); 1271590Srgrimes fflag = TRUE; 1281590Srgrimes break; 1291590Srgrimes case 'k': 1301590Srgrimes addlist( kfromlist , *++argv ); 1311590Srgrimes addlist( ktolist , *++argv ); 1321590Srgrimes kflag = TRUE; 1331590Srgrimes break; 13485739Sgreen case 'K': 13585739Sgreen Kflag = TRUE; 13685739Sgreen break; 137105243Scharnier case 'l': 1385190Swollman lflag = 1; 1395190Swollman Lflag = 0; 1405190Swollman break; 141105243Scharnier case 'L': 1425190Swollman Lflag = 1; 1435190Swollman lflag = 0; 1445190Swollman break; 145105243Scharnier case 's': 1461590Srgrimes sflag = TRUE; 1471590Srgrimes break; 1482513Sbde case 'u': 1492513Sbde uflag = TRUE; 1502513Sbde break; 1511590Srgrimes case 'z': 1521590Srgrimes zflag = TRUE; 1531590Srgrimes break; 1541590Srgrimes } 1551590Srgrimes argv++; 1561590Srgrimes } 1571590Srgrimes if ( *argv != 0 ) { 1581590Srgrimes a_outname = *argv; 1591590Srgrimes argv++; 1601590Srgrimes } else { 1611590Srgrimes a_outname = A_OUTNAME; 1621590Srgrimes } 1631590Srgrimes if ( *argv != 0 ) { 1641590Srgrimes gmonname = *argv; 1651590Srgrimes argv++; 1661590Srgrimes } else { 16747420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 16847420Sjmz strcpy(gmonname, a_outname); 16947420Sjmz strcat(gmonname, ".gmon"); 1701590Srgrimes } 1711590Srgrimes /* 17238928Sjdp * get information from the executable file. 17338928Sjdp */ 17485739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 17585739Sgreen (elf_getnfile(a_outname, &defaultEs) == -1 && 17685739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 17738928Sjdp errx(1, "%s: bad format", a_outname); 17838928Sjdp /* 17938928Sjdp * sort symbol table. 18038928Sjdp */ 18138928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 18238928Sjdp /* 1831590Srgrimes * turn off default functions 1841590Srgrimes */ 18538928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1861590Srgrimes Eflag = TRUE; 1871590Srgrimes addlist( Elist , *sp ); 1881590Srgrimes eflag = TRUE; 1891590Srgrimes addlist( elist , *sp ); 1901590Srgrimes } 1911590Srgrimes /* 1921590Srgrimes * get information about mon.out file(s). 1931590Srgrimes */ 1941590Srgrimes do { 1951590Srgrimes getpfile( gmonname ); 1961590Srgrimes if ( *argv != 0 ) { 1971590Srgrimes gmonname = *argv; 1981590Srgrimes } 1991590Srgrimes } while ( *argv++ != 0 ); 2001590Srgrimes /* 2011590Srgrimes * how many ticks per second? 2021590Srgrimes * if we can't tell, report time in ticks. 2031590Srgrimes */ 2041590Srgrimes if (hz == 0) { 2051590Srgrimes hz = 1; 2061590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 2071590Srgrimes } 2081590Srgrimes /* 2091590Srgrimes * dump out a gmon.sum file if requested 2101590Srgrimes */ 2111590Srgrimes if ( sflag ) { 2121590Srgrimes dumpsum( GMONSUM ); 2131590Srgrimes } 2141590Srgrimes /* 2151590Srgrimes * assign samples to procedures 2161590Srgrimes */ 2171590Srgrimes asgnsamples(); 2181590Srgrimes /* 2191590Srgrimes * assemble the dynamic profile 2201590Srgrimes */ 2211590Srgrimes timesortnlp = doarcs(); 2221590Srgrimes /* 2231590Srgrimes * print the dynamic profile 2241590Srgrimes */ 2255190Swollman if(!lflag) { 2268874Srgrimes printgprof( timesortnlp ); 2275190Swollman } 2281590Srgrimes /* 2291590Srgrimes * print the flat profile 2301590Srgrimes */ 2315190Swollman if(!Lflag) { 2325190Swollman printprof(); 2335190Swollman } 2341590Srgrimes /* 2351590Srgrimes * print the index 2361590Srgrimes */ 2378874Srgrimes printindex(); 238105243Scharnier exit(0); 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimes /* 2421590Srgrimes * information from a gmon.out file is in two parts: 2431590Srgrimes * an array of sampling hits within pc ranges, 2441590Srgrimes * and the arcs. 2451590Srgrimes */ 246105243Scharniervoid 2471590Srgrimesgetpfile(filename) 2481590Srgrimes char *filename; 2491590Srgrimes{ 2501590Srgrimes FILE *pfile; 2511590Srgrimes FILE *openpfile(); 2521590Srgrimes struct rawarc arc; 2531590Srgrimes 2541590Srgrimes pfile = openpfile(filename); 2551590Srgrimes readsamples(pfile); 2561590Srgrimes /* 2571590Srgrimes * the rest of the file consists of 2581590Srgrimes * a bunch of <from,self,count> tuples. 2591590Srgrimes */ 2601590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2611590Srgrimes# ifdef DEBUG 2621590Srgrimes if ( debug & SAMPLEDEBUG ) { 26391018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2641590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2651590Srgrimes } 26697631Swollman# endif /* DEBUG */ 2671590Srgrimes /* 2681590Srgrimes * add this arc 2691590Srgrimes */ 2701590Srgrimes tally( &arc ); 2711590Srgrimes } 2721590Srgrimes fclose(pfile); 2731590Srgrimes} 2741590Srgrimes 2751590SrgrimesFILE * 2761590Srgrimesopenpfile(filename) 2771590Srgrimes char *filename; 2781590Srgrimes{ 2791590Srgrimes struct gmonhdr tmp; 2801590Srgrimes FILE *pfile; 2811590Srgrimes int size; 2821590Srgrimes int rate; 2831590Srgrimes 284105243Scharnier if((pfile = fopen(filename, "r")) == NULL) 285105243Scharnier err(1, "%s", filename); 2861590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2871590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 288105243Scharnier tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) 289105243Scharnier errx(1, "%s: incompatible with first gmon file", filename); 2901590Srgrimes gmonhdr = tmp; 2911590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2921590Srgrimes rate = gmonhdr.profrate; 2931590Srgrimes size = sizeof(struct gmonhdr); 2941590Srgrimes } else { 2951590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2961590Srgrimes size = sizeof(struct ophdr); 2971590Srgrimes gmonhdr.profrate = rate = hertz(); 2981590Srgrimes gmonhdr.version = GMONVERSION; 2991590Srgrimes } 3001590Srgrimes if (hz == 0) { 3011590Srgrimes hz = rate; 302105243Scharnier } else if (hz != rate) 303105243Scharnier errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file", 3041590Srgrimes filename, rate, "incompatible with clock rate", hz); 30591738Sbde if ( gmonhdr.histcounter_type == 0 ) { 30691738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 30791738Sbde histcounter_type = 16; 30891738Sbde histcounter_size = 2; 30991738Sbde } else { 31091738Sbde histcounter_type = gmonhdr.histcounter_type; 31191738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 31291738Sbde } 3131590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3141590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 31591735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 31691735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3171590Srgrimes sampbytes = gmonhdr.ncnt - size; 31891738Sbde nsamples = sampbytes / histcounter_size; 3191590Srgrimes# ifdef DEBUG 3201590Srgrimes if ( debug & SAMPLEDEBUG ) { 32191018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3221590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 32391018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3241590Srgrimes s_lowpc , s_highpc ); 32591018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3261590Srgrimes lowpc , highpc ); 3271590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3281590Srgrimes sampbytes , nsamples ); 32991018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3301590Srgrimes } 33197631Swollman# endif /* DEBUG */ 3321590Srgrimes return(pfile); 3331590Srgrimes} 3341590Srgrimes 335105243Scharniervoid 3361590Srgrimestally( rawp ) 3371590Srgrimes struct rawarc *rawp; 3381590Srgrimes{ 3391590Srgrimes nltype *parentp; 3401590Srgrimes nltype *childp; 3411590Srgrimes 3421590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3431590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3441590Srgrimes if ( parentp == 0 || childp == 0 ) 3451590Srgrimes return; 3461590Srgrimes if ( kflag 3471590Srgrimes && onlist( kfromlist , parentp -> name ) 3481590Srgrimes && onlist( ktolist , childp -> name ) ) { 3491590Srgrimes return; 3501590Srgrimes } 3511590Srgrimes childp -> ncall += rawp -> raw_count; 3521590Srgrimes# ifdef DEBUG 3531590Srgrimes if ( debug & TALLYDEBUG ) { 35491018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3551590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3561590Srgrimes } 35797631Swollman# endif /* DEBUG */ 3581590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3591590Srgrimes} 3601590Srgrimes 3611590Srgrimes/* 3621590Srgrimes * dump out the gmon.sum file 3631590Srgrimes */ 364105243Scharniervoid 3651590Srgrimesdumpsum( sumfile ) 3661590Srgrimes char *sumfile; 3671590Srgrimes{ 3681590Srgrimes register nltype *nlp; 3691590Srgrimes register arctype *arcp; 3701590Srgrimes struct rawarc arc; 3711590Srgrimes FILE *sfile; 3721590Srgrimes 373105243Scharnier if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) 374105243Scharnier err( 1 , "%s" , sumfile ); 3751590Srgrimes /* 3761590Srgrimes * dump the header; use the last header read in 3771590Srgrimes */ 378105243Scharnier if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) 379105243Scharnier err( 1 , "%s" , sumfile ); 3801590Srgrimes /* 3811590Srgrimes * dump the samples 3821590Srgrimes */ 383105243Scharnier if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) 384105243Scharnier err( 1 , "%s" , sumfile ); 3851590Srgrimes /* 3861590Srgrimes * dump the normalized raw arc information 3871590Srgrimes */ 3881590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3891590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3901590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3911590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3921590Srgrimes arc.raw_count = arcp -> arc_count; 393105243Scharnier if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) 394105243Scharnier err( 1 , "%s" , sumfile ); 3951590Srgrimes# ifdef DEBUG 3961590Srgrimes if ( debug & SAMPLEDEBUG ) { 39791018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 3981590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3991590Srgrimes } 40097631Swollman# endif /* DEBUG */ 4011590Srgrimes } 4021590Srgrimes } 4031590Srgrimes fclose( sfile ); 4041590Srgrimes} 4051590Srgrimes 40638928Sjdpstatic int 40738928Sjdpvalcmp(v1, v2) 40838928Sjdp const void *v1; 40938928Sjdp const void *v2; 4101590Srgrimes{ 41138928Sjdp const nltype *p1 = (const nltype *)v1; 41238928Sjdp const nltype *p2 = (const nltype *)v2; 41338928Sjdp 4141590Srgrimes if ( p1 -> value < p2 -> value ) { 4151590Srgrimes return LESSTHAN; 4161590Srgrimes } 4171590Srgrimes if ( p1 -> value > p2 -> value ) { 4181590Srgrimes return GREATERTHAN; 4191590Srgrimes } 4201590Srgrimes return EQUALTO; 4211590Srgrimes} 4221590Srgrimes 423105243Scharniervoid 4241590Srgrimesreadsamples(pfile) 4251590Srgrimes FILE *pfile; 4261590Srgrimes{ 4271590Srgrimes register i; 42891738Sbde intmax_t sample; 4298874Srgrimes 4301590Srgrimes if (samples == 0) { 43191738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 432105243Scharnier if (samples == 0) 433105243Scharnier errx(0, "no room for %d sample pc's", nsamples); 4341590Srgrimes } 4351590Srgrimes for (i = 0; i < nsamples; i++) { 43691738Sbde fread(&sample, histcounter_size, 1, pfile); 4371590Srgrimes if (feof(pfile)) 4381590Srgrimes break; 43991738Sbde switch ( histcounter_type ) { 44091738Sbde case -8: 44191738Sbde samples[i] += *(int8_t *)&sample; 44291738Sbde break; 44391738Sbde case 8: 44491738Sbde samples[i] += *(u_int8_t *)&sample; 44591738Sbde break; 44691738Sbde case -16: 44791738Sbde samples[i] += *(int16_t *)&sample; 44891738Sbde break; 44991738Sbde case 16: 45091738Sbde samples[i] += *(u_int16_t *)&sample; 45191738Sbde break; 45291738Sbde case -32: 45391738Sbde samples[i] += *(int32_t *)&sample; 45491738Sbde break; 45591738Sbde case 32: 45691738Sbde samples[i] += *(u_int32_t *)&sample; 45791738Sbde break; 45891738Sbde case -64: 45991738Sbde samples[i] += *(int64_t *)&sample; 46091738Sbde break; 46191738Sbde case 64: 46291738Sbde samples[i] += *(u_int64_t *)&sample; 46391738Sbde break; 46491738Sbde default: 46591738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 46691738Sbde } 4671590Srgrimes } 468105243Scharnier if (i != nsamples) 469105243Scharnier errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples ); 4701590Srgrimes} 4711590Srgrimes 4721590Srgrimes/* 4731590Srgrimes * Assign samples to the procedures to which they belong. 4741590Srgrimes * 4751590Srgrimes * There are three cases as to where pcl and pch can be 4761590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4771590Srgrimes * as shown in the following diagram. overlap computes the 4781590Srgrimes * distance between the arrows, the fraction of the sample 4791590Srgrimes * that is to be credited to the routine which starts at svalue0. 4801590Srgrimes * 4811590Srgrimes * svalue0 svalue1 4821590Srgrimes * | | 4831590Srgrimes * v v 4841590Srgrimes * 4851590Srgrimes * +-----------------------------------------------+ 4861590Srgrimes * | | 4871590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4881590Srgrimes * | | | | | | 4891590Srgrimes * +---------+ +---------+ +---------+ 4901590Srgrimes * 4911590Srgrimes * ^ ^ ^ ^ ^ ^ 4921590Srgrimes * | | | | | | 4931590Srgrimes * pcl pch pcl pch pcl pch 4941590Srgrimes * 4951590Srgrimes * For the vax we assert that samples will never fall in the first 4961590Srgrimes * two bytes of any routine, since that is the entry mask, 4971590Srgrimes * thus we give call alignentries() to adjust the entry points if 4981590Srgrimes * the entry mask falls in one bucket but the code for the routine 4991590Srgrimes * doesn't start until the next bucket. In conjunction with the 5001590Srgrimes * alignment of routine addresses, this should allow us to have 5011590Srgrimes * only one sample for every four bytes of text space and never 5021590Srgrimes * have any overlap (the two end cases, above). 5031590Srgrimes */ 504105243Scharniervoid 5051590Srgrimesasgnsamples() 5061590Srgrimes{ 5071590Srgrimes register int j; 50891738Sbde double ccnt; 5091590Srgrimes double time; 5101590Srgrimes unsigned long pcl, pch; 5111590Srgrimes register int i; 5121590Srgrimes unsigned long overlap; 5131590Srgrimes unsigned long svalue0, svalue1; 5141590Srgrimes 5151590Srgrimes /* read samples and assign to namelist symbols */ 5161590Srgrimes scale = highpc - lowpc; 5171590Srgrimes scale /= nsamples; 5181590Srgrimes alignentries(); 5191590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5201590Srgrimes ccnt = samples[i]; 5211590Srgrimes if (ccnt == 0) 5221590Srgrimes continue; 52348839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 52448839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5251590Srgrimes time = ccnt; 5261590Srgrimes# ifdef DEBUG 5271590Srgrimes if ( debug & SAMPLEDEBUG ) { 52891738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5291590Srgrimes pcl , pch , ccnt ); 5301590Srgrimes } 53197631Swollman# endif /* DEBUG */ 5321590Srgrimes totime += time; 5331590Srgrimes for (j = j - 1; j < nname; j++) { 5341590Srgrimes svalue0 = nl[j].svalue; 5351590Srgrimes svalue1 = nl[j+1].svalue; 5361590Srgrimes /* 5378874Srgrimes * if high end of tick is below entry address, 5381590Srgrimes * go for next tick. 5391590Srgrimes */ 5401590Srgrimes if (pch < svalue0) 5411590Srgrimes break; 5421590Srgrimes /* 5431590Srgrimes * if low end of tick into next routine, 5441590Srgrimes * go for next routine. 5451590Srgrimes */ 5461590Srgrimes if (pcl >= svalue1) 5471590Srgrimes continue; 5481590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5491590Srgrimes if (overlap > 0) { 5501590Srgrimes# ifdef DEBUG 5511590Srgrimes if (debug & SAMPLEDEBUG) { 55291018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 55391735Sbde nl[j].value / HISTORICAL_SCALE_2, 55491735Sbde svalue0, svalue1, nl[j].name, 5551590Srgrimes overlap * time / scale, overlap); 5561590Srgrimes } 55797631Swollman# endif /* DEBUG */ 5581590Srgrimes nl[j].time += overlap * time / scale; 5591590Srgrimes } 5601590Srgrimes } 5611590Srgrimes } 5621590Srgrimes# ifdef DEBUG 5631590Srgrimes if (debug & SAMPLEDEBUG) { 5641590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5651590Srgrimes } 56697631Swollman# endif /* DEBUG */ 5671590Srgrimes} 5681590Srgrimes 5691590Srgrimes 5701590Srgrimesunsigned long 5711590Srgrimesmin(a, b) 5721590Srgrimes unsigned long a,b; 5731590Srgrimes{ 5741590Srgrimes if (a<b) 5751590Srgrimes return(a); 5761590Srgrimes return(b); 5771590Srgrimes} 5781590Srgrimes 5791590Srgrimesunsigned long 5801590Srgrimesmax(a, b) 5811590Srgrimes unsigned long a,b; 5821590Srgrimes{ 5831590Srgrimes if (a>b) 5841590Srgrimes return(a); 5851590Srgrimes return(b); 5861590Srgrimes} 5871590Srgrimes 5881590Srgrimes /* 5891590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5901590Srgrimes * and possibly push the scaled entry points over the entry mask, 5911590Srgrimes * if it turns out that the entry point is in one bucket and the code 5921590Srgrimes * for a routine is in the next bucket. 5931590Srgrimes */ 594105243Scharniervoid 5951590Srgrimesalignentries() 5961590Srgrimes{ 5971590Srgrimes register struct nl *nlp; 5981590Srgrimes unsigned long bucket_of_entry; 5991590Srgrimes unsigned long bucket_of_code; 6001590Srgrimes 6011590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 60291735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 6031590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 60491735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 60591735Sbde lowpc) / scale; 6061590Srgrimes if (bucket_of_entry < bucket_of_code) { 6071590Srgrimes# ifdef DEBUG 6081590Srgrimes if (debug & SAMPLEDEBUG) { 60991018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 61091735Sbde nlp->svalue, 61191735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6121590Srgrimes } 61397631Swollman# endif /* DEBUG */ 61491735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6151590Srgrimes } 6161590Srgrimes } 6171590Srgrimes} 618