gprof.c revision 91738
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 401590Srgrimes#ifndef lint 4127313Scharnier#if 0 421590Srgrimesstatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 4327313Scharnier#endif 4427313Scharnierstatic const char rcsid[] = 4550477Speter "$FreeBSD: head/usr.bin/gprof/gprof.c 91738 2002-03-06 11:25:58Z bde $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 4827313Scharnier#include <err.h> 4991738Sbde#include <limits.h> 501590Srgrimes#include "gprof.h" 511590Srgrimes 5238928Sjdpstatic int valcmp(const void *, const void *); 531590Srgrimes 5438928Sjdp 551590Srgrimesstatic struct gmonhdr gmonhdr; 565190Swollmanstatic int lflag; 575190Swollmanstatic int Lflag; 581590Srgrimes 591590Srgrimesmain(argc, argv) 601590Srgrimes int argc; 611590Srgrimes char **argv; 621590Srgrimes{ 631590Srgrimes char **sp; 641590Srgrimes nltype **timesortnlp; 6538928Sjdp char **defaultEs; 661590Srgrimes 671590Srgrimes --argc; 681590Srgrimes argv++; 691590Srgrimes debug = 0; 701590Srgrimes bflag = TRUE; 711590Srgrimes while ( *argv != 0 && **argv == '-' ) { 721590Srgrimes (*argv)++; 731590Srgrimes switch ( **argv ) { 741590Srgrimes case 'a': 751590Srgrimes aflag = TRUE; 761590Srgrimes break; 771590Srgrimes case 'b': 781590Srgrimes bflag = FALSE; 791590Srgrimes break; 801590Srgrimes case 'C': 811590Srgrimes Cflag = TRUE; 821590Srgrimes cyclethreshold = atoi( *++argv ); 831590Srgrimes break; 841590Srgrimes case 'c': 851590Srgrimes#if defined(vax) || defined(tahoe) 861590Srgrimes cflag = TRUE; 871590Srgrimes#else 8827313Scharnier errx(1, "-c isn't supported on this architecture yet"); 891590Srgrimes#endif 901590Srgrimes break; 911590Srgrimes case 'd': 921590Srgrimes dflag = TRUE; 931590Srgrimes setlinebuf(stdout); 941590Srgrimes debug |= atoi( *++argv ); 951590Srgrimes debug |= ANYDEBUG; 961590Srgrimes# ifdef DEBUG 971590Srgrimes printf("[main] debug = %d\n", debug); 981590Srgrimes# else not DEBUG 9927313Scharnier printf("gprof: -d ignored\n"); 1001590Srgrimes# endif DEBUG 1011590Srgrimes break; 1021590Srgrimes case 'E': 1031590Srgrimes ++argv; 1041590Srgrimes addlist( Elist , *argv ); 1051590Srgrimes Eflag = TRUE; 1061590Srgrimes addlist( elist , *argv ); 1071590Srgrimes eflag = TRUE; 1081590Srgrimes break; 1091590Srgrimes case 'e': 1101590Srgrimes addlist( elist , *++argv ); 1111590Srgrimes eflag = TRUE; 1121590Srgrimes break; 1131590Srgrimes case 'F': 1141590Srgrimes ++argv; 1151590Srgrimes addlist( Flist , *argv ); 1161590Srgrimes Fflag = TRUE; 1171590Srgrimes addlist( flist , *argv ); 1181590Srgrimes fflag = TRUE; 1191590Srgrimes break; 1201590Srgrimes case 'f': 1211590Srgrimes addlist( flist , *++argv ); 1221590Srgrimes fflag = TRUE; 1231590Srgrimes break; 1241590Srgrimes case 'k': 1251590Srgrimes addlist( kfromlist , *++argv ); 1261590Srgrimes addlist( ktolist , *++argv ); 1271590Srgrimes kflag = TRUE; 1281590Srgrimes break; 12985739Sgreen case 'K': 13085739Sgreen Kflag = TRUE; 13185739Sgreen break; 1325190Swollman case 'l': 1335190Swollman lflag = 1; 1345190Swollman Lflag = 0; 1355190Swollman break; 1365190Swollman case 'L': 1375190Swollman Lflag = 1; 1385190Swollman lflag = 0; 1395190Swollman break; 1405190Swollman case 's': 1411590Srgrimes sflag = TRUE; 1421590Srgrimes break; 1432513Sbde case 'u': 1442513Sbde uflag = TRUE; 1452513Sbde break; 1461590Srgrimes case 'z': 1471590Srgrimes zflag = TRUE; 1481590Srgrimes break; 1491590Srgrimes } 1501590Srgrimes argv++; 1511590Srgrimes } 1521590Srgrimes if ( *argv != 0 ) { 1531590Srgrimes a_outname = *argv; 1541590Srgrimes argv++; 1551590Srgrimes } else { 1561590Srgrimes a_outname = A_OUTNAME; 1571590Srgrimes } 1581590Srgrimes if ( *argv != 0 ) { 1591590Srgrimes gmonname = *argv; 1601590Srgrimes argv++; 1611590Srgrimes } else { 16247420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 16347420Sjmz strcpy(gmonname, a_outname); 16447420Sjmz strcat(gmonname, ".gmon"); 1651590Srgrimes } 1661590Srgrimes /* 16738928Sjdp * get information from the executable file. 16838928Sjdp */ 16985739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 17085739Sgreen (elf_getnfile(a_outname, &defaultEs) == -1 && 17185739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 17238928Sjdp errx(1, "%s: bad format", a_outname); 17338928Sjdp /* 17438928Sjdp * sort symbol table. 17538928Sjdp */ 17638928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17738928Sjdp /* 1781590Srgrimes * turn off default functions 1791590Srgrimes */ 18038928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1811590Srgrimes Eflag = TRUE; 1821590Srgrimes addlist( Elist , *sp ); 1831590Srgrimes eflag = TRUE; 1841590Srgrimes addlist( elist , *sp ); 1851590Srgrimes } 1861590Srgrimes /* 1871590Srgrimes * get information about mon.out file(s). 1881590Srgrimes */ 1891590Srgrimes do { 1901590Srgrimes getpfile( gmonname ); 1911590Srgrimes if ( *argv != 0 ) { 1921590Srgrimes gmonname = *argv; 1931590Srgrimes } 1941590Srgrimes } while ( *argv++ != 0 ); 1951590Srgrimes /* 1961590Srgrimes * how many ticks per second? 1971590Srgrimes * if we can't tell, report time in ticks. 1981590Srgrimes */ 1991590Srgrimes if (hz == 0) { 2001590Srgrimes hz = 1; 2011590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 2021590Srgrimes } 2031590Srgrimes /* 2041590Srgrimes * dump out a gmon.sum file if requested 2051590Srgrimes */ 2061590Srgrimes if ( sflag ) { 2071590Srgrimes dumpsum( GMONSUM ); 2081590Srgrimes } 2091590Srgrimes /* 2101590Srgrimes * assign samples to procedures 2111590Srgrimes */ 2121590Srgrimes asgnsamples(); 2131590Srgrimes /* 2141590Srgrimes * assemble the dynamic profile 2151590Srgrimes */ 2161590Srgrimes timesortnlp = doarcs(); 2171590Srgrimes /* 2181590Srgrimes * print the dynamic profile 2191590Srgrimes */ 2205190Swollman if(!lflag) { 2218874Srgrimes printgprof( timesortnlp ); 2225190Swollman } 2231590Srgrimes /* 2241590Srgrimes * print the flat profile 2251590Srgrimes */ 2265190Swollman if(!Lflag) { 2275190Swollman printprof(); 2285190Swollman } 2291590Srgrimes /* 2301590Srgrimes * print the index 2311590Srgrimes */ 2328874Srgrimes printindex(); 2331590Srgrimes done(); 2341590Srgrimes} 2351590Srgrimes 2361590Srgrimes /* 2371590Srgrimes * information from a gmon.out file is in two parts: 2381590Srgrimes * an array of sampling hits within pc ranges, 2391590Srgrimes * and the arcs. 2401590Srgrimes */ 2411590Srgrimesgetpfile(filename) 2421590Srgrimes char *filename; 2431590Srgrimes{ 2441590Srgrimes FILE *pfile; 2451590Srgrimes FILE *openpfile(); 2461590Srgrimes struct rawarc arc; 2471590Srgrimes 2481590Srgrimes pfile = openpfile(filename); 2491590Srgrimes readsamples(pfile); 2501590Srgrimes /* 2511590Srgrimes * the rest of the file consists of 2521590Srgrimes * a bunch of <from,self,count> tuples. 2531590Srgrimes */ 2541590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2551590Srgrimes# ifdef DEBUG 2561590Srgrimes if ( debug & SAMPLEDEBUG ) { 25791018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2581590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2591590Srgrimes } 2601590Srgrimes# endif DEBUG 2611590Srgrimes /* 2621590Srgrimes * add this arc 2631590Srgrimes */ 2641590Srgrimes tally( &arc ); 2651590Srgrimes } 2661590Srgrimes fclose(pfile); 2671590Srgrimes} 2681590Srgrimes 2691590SrgrimesFILE * 2701590Srgrimesopenpfile(filename) 2711590Srgrimes char *filename; 2721590Srgrimes{ 2731590Srgrimes struct gmonhdr tmp; 2741590Srgrimes FILE *pfile; 2751590Srgrimes int size; 2761590Srgrimes int rate; 2771590Srgrimes 2781590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 2791590Srgrimes perror(filename); 2801590Srgrimes done(); 2811590Srgrimes } 2821590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2831590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 2841590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 28527313Scharnier warnx("%s: incompatible with first gmon file", filename); 2861590Srgrimes done(); 2871590Srgrimes } 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; 3001590Srgrimes } else if (hz != rate) { 3011590Srgrimes fprintf(stderr, 30291018Sbde "%s: profile clock rate (%d) %s (%ld) in first gmon file\n", 3031590Srgrimes filename, rate, "incompatible with clock rate", hz); 3041590Srgrimes done(); 3051590Srgrimes } 30691738Sbde if ( gmonhdr.histcounter_type == 0 ) { 30791738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 30891738Sbde histcounter_type = 16; 30991738Sbde histcounter_size = 2; 31091738Sbde } else { 31191738Sbde histcounter_type = gmonhdr.histcounter_type; 31291738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 31391738Sbde } 3141590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3151590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 31691735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 31791735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3181590Srgrimes sampbytes = gmonhdr.ncnt - size; 31991738Sbde nsamples = sampbytes / histcounter_size; 3201590Srgrimes# ifdef DEBUG 3211590Srgrimes if ( debug & SAMPLEDEBUG ) { 32291018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3231590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 32491018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3251590Srgrimes s_lowpc , s_highpc ); 32691018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3271590Srgrimes lowpc , highpc ); 3281590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3291590Srgrimes sampbytes , nsamples ); 33091018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3311590Srgrimes } 3321590Srgrimes# endif DEBUG 3331590Srgrimes return(pfile); 3341590Srgrimes} 3351590Srgrimes 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 } 3571590Srgrimes# endif DEBUG 3581590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3591590Srgrimes} 3601590Srgrimes 3611590Srgrimes/* 3621590Srgrimes * dump out the gmon.sum file 3631590Srgrimes */ 3641590Srgrimesdumpsum( sumfile ) 3651590Srgrimes char *sumfile; 3661590Srgrimes{ 3671590Srgrimes register nltype *nlp; 3681590Srgrimes register arctype *arcp; 3691590Srgrimes struct rawarc arc; 3701590Srgrimes FILE *sfile; 3711590Srgrimes 3721590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3731590Srgrimes perror( sumfile ); 3741590Srgrimes done(); 3751590Srgrimes } 3761590Srgrimes /* 3771590Srgrimes * dump the header; use the last header read in 3781590Srgrimes */ 3791590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 3801590Srgrimes perror( sumfile ); 3811590Srgrimes done(); 3821590Srgrimes } 3831590Srgrimes /* 3841590Srgrimes * dump the samples 3851590Srgrimes */ 38691738Sbde if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) { 3871590Srgrimes perror( sumfile ); 3881590Srgrimes done(); 3891590Srgrimes } 3901590Srgrimes /* 3911590Srgrimes * dump the normalized raw arc information 3921590Srgrimes */ 3931590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3941590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3951590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3961590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3971590Srgrimes arc.raw_count = arcp -> arc_count; 3981590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3991590Srgrimes perror( sumfile ); 4001590Srgrimes done(); 4011590Srgrimes } 4021590Srgrimes# ifdef DEBUG 4031590Srgrimes if ( debug & SAMPLEDEBUG ) { 40491018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 4051590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4061590Srgrimes } 4071590Srgrimes# endif DEBUG 4081590Srgrimes } 4091590Srgrimes } 4101590Srgrimes fclose( sfile ); 4111590Srgrimes} 4121590Srgrimes 41338928Sjdpstatic int 41438928Sjdpvalcmp(v1, v2) 41538928Sjdp const void *v1; 41638928Sjdp const void *v2; 4171590Srgrimes{ 41838928Sjdp const nltype *p1 = (const nltype *)v1; 41938928Sjdp const nltype *p2 = (const nltype *)v2; 42038928Sjdp 4211590Srgrimes if ( p1 -> value < p2 -> value ) { 4221590Srgrimes return LESSTHAN; 4231590Srgrimes } 4241590Srgrimes if ( p1 -> value > p2 -> value ) { 4251590Srgrimes return GREATERTHAN; 4261590Srgrimes } 4271590Srgrimes return EQUALTO; 4281590Srgrimes} 4291590Srgrimes 4301590Srgrimesreadsamples(pfile) 4311590Srgrimes FILE *pfile; 4321590Srgrimes{ 4331590Srgrimes register i; 43491738Sbde intmax_t sample; 4358874Srgrimes 4361590Srgrimes if (samples == 0) { 43791738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 4381590Srgrimes if (samples == 0) { 43991738Sbde warnx("no room for %d sample pc's", nsamples); 4401590Srgrimes done(); 4411590Srgrimes } 4421590Srgrimes } 4431590Srgrimes for (i = 0; i < nsamples; i++) { 44491738Sbde fread(&sample, histcounter_size, 1, pfile); 4451590Srgrimes if (feof(pfile)) 4461590Srgrimes break; 44791738Sbde switch ( histcounter_type ) { 44891738Sbde case -8: 44991738Sbde samples[i] += *(int8_t *)&sample; 45091738Sbde break; 45191738Sbde case 8: 45291738Sbde samples[i] += *(u_int8_t *)&sample; 45391738Sbde break; 45491738Sbde case -16: 45591738Sbde samples[i] += *(int16_t *)&sample; 45691738Sbde break; 45791738Sbde case 16: 45891738Sbde samples[i] += *(u_int16_t *)&sample; 45991738Sbde break; 46091738Sbde case -32: 46191738Sbde samples[i] += *(int32_t *)&sample; 46291738Sbde break; 46391738Sbde case 32: 46491738Sbde samples[i] += *(u_int32_t *)&sample; 46591738Sbde break; 46691738Sbde case -64: 46791738Sbde samples[i] += *(int64_t *)&sample; 46891738Sbde break; 46991738Sbde case 64: 47091738Sbde samples[i] += *(u_int64_t *)&sample; 47191738Sbde break; 47291738Sbde default: 47391738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 47491738Sbde } 4751590Srgrimes } 4761590Srgrimes if (i != nsamples) { 47727313Scharnier warnx("unexpected EOF after reading %d/%d samples", --i , nsamples ); 4781590Srgrimes done(); 4791590Srgrimes } 4801590Srgrimes} 4811590Srgrimes 4821590Srgrimes/* 4831590Srgrimes * Assign samples to the procedures to which they belong. 4841590Srgrimes * 4851590Srgrimes * There are three cases as to where pcl and pch can be 4861590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4871590Srgrimes * as shown in the following diagram. overlap computes the 4881590Srgrimes * distance between the arrows, the fraction of the sample 4891590Srgrimes * that is to be credited to the routine which starts at svalue0. 4901590Srgrimes * 4911590Srgrimes * svalue0 svalue1 4921590Srgrimes * | | 4931590Srgrimes * v v 4941590Srgrimes * 4951590Srgrimes * +-----------------------------------------------+ 4961590Srgrimes * | | 4971590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4981590Srgrimes * | | | | | | 4991590Srgrimes * +---------+ +---------+ +---------+ 5001590Srgrimes * 5011590Srgrimes * ^ ^ ^ ^ ^ ^ 5021590Srgrimes * | | | | | | 5031590Srgrimes * pcl pch pcl pch pcl pch 5041590Srgrimes * 5051590Srgrimes * For the vax we assert that samples will never fall in the first 5061590Srgrimes * two bytes of any routine, since that is the entry mask, 5071590Srgrimes * thus we give call alignentries() to adjust the entry points if 5081590Srgrimes * the entry mask falls in one bucket but the code for the routine 5091590Srgrimes * doesn't start until the next bucket. In conjunction with the 5101590Srgrimes * alignment of routine addresses, this should allow us to have 5111590Srgrimes * only one sample for every four bytes of text space and never 5121590Srgrimes * have any overlap (the two end cases, above). 5131590Srgrimes */ 5141590Srgrimesasgnsamples() 5151590Srgrimes{ 5161590Srgrimes register int j; 51791738Sbde double ccnt; 5181590Srgrimes double time; 5191590Srgrimes unsigned long pcl, pch; 5201590Srgrimes register int i; 5211590Srgrimes unsigned long overlap; 5221590Srgrimes unsigned long svalue0, svalue1; 5231590Srgrimes 5241590Srgrimes /* read samples and assign to namelist symbols */ 5251590Srgrimes scale = highpc - lowpc; 5261590Srgrimes scale /= nsamples; 5271590Srgrimes alignentries(); 5281590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5291590Srgrimes ccnt = samples[i]; 5301590Srgrimes if (ccnt == 0) 5311590Srgrimes continue; 53248839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 53348839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5341590Srgrimes time = ccnt; 5351590Srgrimes# ifdef DEBUG 5361590Srgrimes if ( debug & SAMPLEDEBUG ) { 53791738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5381590Srgrimes pcl , pch , ccnt ); 5391590Srgrimes } 5401590Srgrimes# endif DEBUG 5411590Srgrimes totime += time; 5421590Srgrimes for (j = j - 1; j < nname; j++) { 5431590Srgrimes svalue0 = nl[j].svalue; 5441590Srgrimes svalue1 = nl[j+1].svalue; 5451590Srgrimes /* 5468874Srgrimes * if high end of tick is below entry address, 5471590Srgrimes * go for next tick. 5481590Srgrimes */ 5491590Srgrimes if (pch < svalue0) 5501590Srgrimes break; 5511590Srgrimes /* 5521590Srgrimes * if low end of tick into next routine, 5531590Srgrimes * go for next routine. 5541590Srgrimes */ 5551590Srgrimes if (pcl >= svalue1) 5561590Srgrimes continue; 5571590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5581590Srgrimes if (overlap > 0) { 5591590Srgrimes# ifdef DEBUG 5601590Srgrimes if (debug & SAMPLEDEBUG) { 56191018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 56291735Sbde nl[j].value / HISTORICAL_SCALE_2, 56391735Sbde svalue0, svalue1, nl[j].name, 5641590Srgrimes overlap * time / scale, overlap); 5651590Srgrimes } 5661590Srgrimes# endif DEBUG 5671590Srgrimes nl[j].time += overlap * time / scale; 5681590Srgrimes } 5691590Srgrimes } 5701590Srgrimes } 5711590Srgrimes# ifdef DEBUG 5721590Srgrimes if (debug & SAMPLEDEBUG) { 5731590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5741590Srgrimes } 5751590Srgrimes# endif DEBUG 5761590Srgrimes} 5771590Srgrimes 5781590Srgrimes 5791590Srgrimesunsigned long 5801590Srgrimesmin(a, b) 5811590Srgrimes unsigned long a,b; 5821590Srgrimes{ 5831590Srgrimes if (a<b) 5841590Srgrimes return(a); 5851590Srgrimes return(b); 5861590Srgrimes} 5871590Srgrimes 5881590Srgrimesunsigned long 5891590Srgrimesmax(a, b) 5901590Srgrimes unsigned long a,b; 5911590Srgrimes{ 5921590Srgrimes if (a>b) 5931590Srgrimes return(a); 5941590Srgrimes return(b); 5951590Srgrimes} 5961590Srgrimes 5971590Srgrimes /* 5981590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5991590Srgrimes * and possibly push the scaled entry points over the entry mask, 6001590Srgrimes * if it turns out that the entry point is in one bucket and the code 6011590Srgrimes * for a routine is in the next bucket. 6021590Srgrimes */ 6031590Srgrimesalignentries() 6041590Srgrimes{ 6051590Srgrimes register struct nl *nlp; 6061590Srgrimes unsigned long bucket_of_entry; 6071590Srgrimes unsigned long bucket_of_code; 6081590Srgrimes 6091590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 61091735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 6111590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 61291735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 61391735Sbde lowpc) / scale; 6141590Srgrimes if (bucket_of_entry < bucket_of_code) { 6151590Srgrimes# ifdef DEBUG 6161590Srgrimes if (debug & SAMPLEDEBUG) { 61791018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 61891735Sbde nlp->svalue, 61991735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6201590Srgrimes } 6211590Srgrimes# endif DEBUG 62291735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6231590Srgrimes } 6241590Srgrimes } 6251590Srgrimes} 6261590Srgrimes 6271590Srgrimesdone() 6281590Srgrimes{ 6291590Srgrimes 6301590Srgrimes exit(0); 6311590Srgrimes} 632