gprof.c revision 93123
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 93123 2002-03-25 05:23:45Z mike $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 4827313Scharnier#include <err.h> 4991738Sbde#include <limits.h> 5093123Smike#include <stdint.h> 511590Srgrimes#include "gprof.h" 521590Srgrimes 5338928Sjdpstatic int valcmp(const void *, const void *); 541590Srgrimes 5538928Sjdp 561590Srgrimesstatic struct gmonhdr gmonhdr; 575190Swollmanstatic int lflag; 585190Swollmanstatic int Lflag; 591590Srgrimes 601590Srgrimesmain(argc, argv) 611590Srgrimes int argc; 621590Srgrimes char **argv; 631590Srgrimes{ 641590Srgrimes char **sp; 651590Srgrimes nltype **timesortnlp; 6638928Sjdp char **defaultEs; 671590Srgrimes 681590Srgrimes --argc; 691590Srgrimes argv++; 701590Srgrimes debug = 0; 711590Srgrimes bflag = TRUE; 721590Srgrimes while ( *argv != 0 && **argv == '-' ) { 731590Srgrimes (*argv)++; 741590Srgrimes switch ( **argv ) { 751590Srgrimes case 'a': 761590Srgrimes aflag = TRUE; 771590Srgrimes break; 781590Srgrimes case 'b': 791590Srgrimes bflag = FALSE; 801590Srgrimes break; 811590Srgrimes case 'C': 821590Srgrimes Cflag = TRUE; 831590Srgrimes cyclethreshold = atoi( *++argv ); 841590Srgrimes break; 851590Srgrimes case 'c': 861590Srgrimes#if defined(vax) || defined(tahoe) 871590Srgrimes cflag = TRUE; 881590Srgrimes#else 8927313Scharnier errx(1, "-c isn't supported on this architecture yet"); 901590Srgrimes#endif 911590Srgrimes break; 921590Srgrimes case 'd': 931590Srgrimes dflag = TRUE; 941590Srgrimes setlinebuf(stdout); 951590Srgrimes debug |= atoi( *++argv ); 961590Srgrimes debug |= ANYDEBUG; 971590Srgrimes# ifdef DEBUG 981590Srgrimes printf("[main] debug = %d\n", debug); 991590Srgrimes# else not DEBUG 10027313Scharnier printf("gprof: -d ignored\n"); 1011590Srgrimes# endif DEBUG 1021590Srgrimes break; 1031590Srgrimes case 'E': 1041590Srgrimes ++argv; 1051590Srgrimes addlist( Elist , *argv ); 1061590Srgrimes Eflag = TRUE; 1071590Srgrimes addlist( elist , *argv ); 1081590Srgrimes eflag = TRUE; 1091590Srgrimes break; 1101590Srgrimes case 'e': 1111590Srgrimes addlist( elist , *++argv ); 1121590Srgrimes eflag = TRUE; 1131590Srgrimes break; 1141590Srgrimes case 'F': 1151590Srgrimes ++argv; 1161590Srgrimes addlist( Flist , *argv ); 1171590Srgrimes Fflag = TRUE; 1181590Srgrimes addlist( flist , *argv ); 1191590Srgrimes fflag = TRUE; 1201590Srgrimes break; 1211590Srgrimes case 'f': 1221590Srgrimes addlist( flist , *++argv ); 1231590Srgrimes fflag = TRUE; 1241590Srgrimes break; 1251590Srgrimes case 'k': 1261590Srgrimes addlist( kfromlist , *++argv ); 1271590Srgrimes addlist( ktolist , *++argv ); 1281590Srgrimes kflag = TRUE; 1291590Srgrimes break; 13085739Sgreen case 'K': 13185739Sgreen Kflag = TRUE; 13285739Sgreen break; 1335190Swollman case 'l': 1345190Swollman lflag = 1; 1355190Swollman Lflag = 0; 1365190Swollman break; 1375190Swollman case 'L': 1385190Swollman Lflag = 1; 1395190Swollman lflag = 0; 1405190Swollman break; 1415190Swollman case 's': 1421590Srgrimes sflag = TRUE; 1431590Srgrimes break; 1442513Sbde case 'u': 1452513Sbde uflag = TRUE; 1462513Sbde break; 1471590Srgrimes case 'z': 1481590Srgrimes zflag = TRUE; 1491590Srgrimes break; 1501590Srgrimes } 1511590Srgrimes argv++; 1521590Srgrimes } 1531590Srgrimes if ( *argv != 0 ) { 1541590Srgrimes a_outname = *argv; 1551590Srgrimes argv++; 1561590Srgrimes } else { 1571590Srgrimes a_outname = A_OUTNAME; 1581590Srgrimes } 1591590Srgrimes if ( *argv != 0 ) { 1601590Srgrimes gmonname = *argv; 1611590Srgrimes argv++; 1621590Srgrimes } else { 16347420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 16447420Sjmz strcpy(gmonname, a_outname); 16547420Sjmz strcat(gmonname, ".gmon"); 1661590Srgrimes } 1671590Srgrimes /* 16838928Sjdp * get information from the executable file. 16938928Sjdp */ 17085739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 17185739Sgreen (elf_getnfile(a_outname, &defaultEs) == -1 && 17285739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 17338928Sjdp errx(1, "%s: bad format", a_outname); 17438928Sjdp /* 17538928Sjdp * sort symbol table. 17638928Sjdp */ 17738928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17838928Sjdp /* 1791590Srgrimes * turn off default functions 1801590Srgrimes */ 18138928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1821590Srgrimes Eflag = TRUE; 1831590Srgrimes addlist( Elist , *sp ); 1841590Srgrimes eflag = TRUE; 1851590Srgrimes addlist( elist , *sp ); 1861590Srgrimes } 1871590Srgrimes /* 1881590Srgrimes * get information about mon.out file(s). 1891590Srgrimes */ 1901590Srgrimes do { 1911590Srgrimes getpfile( gmonname ); 1921590Srgrimes if ( *argv != 0 ) { 1931590Srgrimes gmonname = *argv; 1941590Srgrimes } 1951590Srgrimes } while ( *argv++ != 0 ); 1961590Srgrimes /* 1971590Srgrimes * how many ticks per second? 1981590Srgrimes * if we can't tell, report time in ticks. 1991590Srgrimes */ 2001590Srgrimes if (hz == 0) { 2011590Srgrimes hz = 1; 2021590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 2031590Srgrimes } 2041590Srgrimes /* 2051590Srgrimes * dump out a gmon.sum file if requested 2061590Srgrimes */ 2071590Srgrimes if ( sflag ) { 2081590Srgrimes dumpsum( GMONSUM ); 2091590Srgrimes } 2101590Srgrimes /* 2111590Srgrimes * assign samples to procedures 2121590Srgrimes */ 2131590Srgrimes asgnsamples(); 2141590Srgrimes /* 2151590Srgrimes * assemble the dynamic profile 2161590Srgrimes */ 2171590Srgrimes timesortnlp = doarcs(); 2181590Srgrimes /* 2191590Srgrimes * print the dynamic profile 2201590Srgrimes */ 2215190Swollman if(!lflag) { 2228874Srgrimes printgprof( timesortnlp ); 2235190Swollman } 2241590Srgrimes /* 2251590Srgrimes * print the flat profile 2261590Srgrimes */ 2275190Swollman if(!Lflag) { 2285190Swollman printprof(); 2295190Swollman } 2301590Srgrimes /* 2311590Srgrimes * print the index 2321590Srgrimes */ 2338874Srgrimes printindex(); 2341590Srgrimes done(); 2351590Srgrimes} 2361590Srgrimes 2371590Srgrimes /* 2381590Srgrimes * information from a gmon.out file is in two parts: 2391590Srgrimes * an array of sampling hits within pc ranges, 2401590Srgrimes * and the arcs. 2411590Srgrimes */ 2421590Srgrimesgetpfile(filename) 2431590Srgrimes char *filename; 2441590Srgrimes{ 2451590Srgrimes FILE *pfile; 2461590Srgrimes FILE *openpfile(); 2471590Srgrimes struct rawarc arc; 2481590Srgrimes 2491590Srgrimes pfile = openpfile(filename); 2501590Srgrimes readsamples(pfile); 2511590Srgrimes /* 2521590Srgrimes * the rest of the file consists of 2531590Srgrimes * a bunch of <from,self,count> tuples. 2541590Srgrimes */ 2551590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2561590Srgrimes# ifdef DEBUG 2571590Srgrimes if ( debug & SAMPLEDEBUG ) { 25891018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2591590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2601590Srgrimes } 2611590Srgrimes# endif DEBUG 2621590Srgrimes /* 2631590Srgrimes * add this arc 2641590Srgrimes */ 2651590Srgrimes tally( &arc ); 2661590Srgrimes } 2671590Srgrimes fclose(pfile); 2681590Srgrimes} 2691590Srgrimes 2701590SrgrimesFILE * 2711590Srgrimesopenpfile(filename) 2721590Srgrimes char *filename; 2731590Srgrimes{ 2741590Srgrimes struct gmonhdr tmp; 2751590Srgrimes FILE *pfile; 2761590Srgrimes int size; 2771590Srgrimes int rate; 2781590Srgrimes 2791590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 2801590Srgrimes perror(filename); 2811590Srgrimes done(); 2821590Srgrimes } 2831590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2841590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 2851590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 28627313Scharnier warnx("%s: incompatible with first gmon file", filename); 2871590Srgrimes done(); 2881590Srgrimes } 2891590Srgrimes gmonhdr = tmp; 2901590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2911590Srgrimes rate = gmonhdr.profrate; 2921590Srgrimes size = sizeof(struct gmonhdr); 2931590Srgrimes } else { 2941590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2951590Srgrimes size = sizeof(struct ophdr); 2961590Srgrimes gmonhdr.profrate = rate = hertz(); 2971590Srgrimes gmonhdr.version = GMONVERSION; 2981590Srgrimes } 2991590Srgrimes if (hz == 0) { 3001590Srgrimes hz = rate; 3011590Srgrimes } else if (hz != rate) { 3021590Srgrimes fprintf(stderr, 30391018Sbde "%s: profile clock rate (%d) %s (%ld) in first gmon file\n", 3041590Srgrimes filename, rate, "incompatible with clock rate", hz); 3051590Srgrimes done(); 3061590Srgrimes } 30791738Sbde if ( gmonhdr.histcounter_type == 0 ) { 30891738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 30991738Sbde histcounter_type = 16; 31091738Sbde histcounter_size = 2; 31191738Sbde } else { 31291738Sbde histcounter_type = gmonhdr.histcounter_type; 31391738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 31491738Sbde } 3151590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3161590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 31791735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 31891735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3191590Srgrimes sampbytes = gmonhdr.ncnt - size; 32091738Sbde nsamples = sampbytes / histcounter_size; 3211590Srgrimes# ifdef DEBUG 3221590Srgrimes if ( debug & SAMPLEDEBUG ) { 32391018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3241590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 32591018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3261590Srgrimes s_lowpc , s_highpc ); 32791018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3281590Srgrimes lowpc , highpc ); 3291590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3301590Srgrimes sampbytes , nsamples ); 33191018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3321590Srgrimes } 3331590Srgrimes# endif DEBUG 3341590Srgrimes return(pfile); 3351590Srgrimes} 3361590Srgrimes 3371590Srgrimestally( rawp ) 3381590Srgrimes struct rawarc *rawp; 3391590Srgrimes{ 3401590Srgrimes nltype *parentp; 3411590Srgrimes nltype *childp; 3421590Srgrimes 3431590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3441590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3451590Srgrimes if ( parentp == 0 || childp == 0 ) 3461590Srgrimes return; 3471590Srgrimes if ( kflag 3481590Srgrimes && onlist( kfromlist , parentp -> name ) 3491590Srgrimes && onlist( ktolist , childp -> name ) ) { 3501590Srgrimes return; 3511590Srgrimes } 3521590Srgrimes childp -> ncall += rawp -> raw_count; 3531590Srgrimes# ifdef DEBUG 3541590Srgrimes if ( debug & TALLYDEBUG ) { 35591018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3561590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3571590Srgrimes } 3581590Srgrimes# endif DEBUG 3591590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3601590Srgrimes} 3611590Srgrimes 3621590Srgrimes/* 3631590Srgrimes * dump out the gmon.sum file 3641590Srgrimes */ 3651590Srgrimesdumpsum( sumfile ) 3661590Srgrimes char *sumfile; 3671590Srgrimes{ 3681590Srgrimes register nltype *nlp; 3691590Srgrimes register arctype *arcp; 3701590Srgrimes struct rawarc arc; 3711590Srgrimes FILE *sfile; 3721590Srgrimes 3731590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3741590Srgrimes perror( sumfile ); 3751590Srgrimes done(); 3761590Srgrimes } 3771590Srgrimes /* 3781590Srgrimes * dump the header; use the last header read in 3791590Srgrimes */ 3801590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 3811590Srgrimes perror( sumfile ); 3821590Srgrimes done(); 3831590Srgrimes } 3841590Srgrimes /* 3851590Srgrimes * dump the samples 3861590Srgrimes */ 38791738Sbde if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) { 3881590Srgrimes perror( sumfile ); 3891590Srgrimes done(); 3901590Srgrimes } 3911590Srgrimes /* 3921590Srgrimes * dump the normalized raw arc information 3931590Srgrimes */ 3941590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3951590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3961590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3971590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3981590Srgrimes arc.raw_count = arcp -> arc_count; 3991590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 4001590Srgrimes perror( sumfile ); 4011590Srgrimes done(); 4021590Srgrimes } 4031590Srgrimes# ifdef DEBUG 4041590Srgrimes if ( debug & SAMPLEDEBUG ) { 40591018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 4061590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 4071590Srgrimes } 4081590Srgrimes# endif DEBUG 4091590Srgrimes } 4101590Srgrimes } 4111590Srgrimes fclose( sfile ); 4121590Srgrimes} 4131590Srgrimes 41438928Sjdpstatic int 41538928Sjdpvalcmp(v1, v2) 41638928Sjdp const void *v1; 41738928Sjdp const void *v2; 4181590Srgrimes{ 41938928Sjdp const nltype *p1 = (const nltype *)v1; 42038928Sjdp const nltype *p2 = (const nltype *)v2; 42138928Sjdp 4221590Srgrimes if ( p1 -> value < p2 -> value ) { 4231590Srgrimes return LESSTHAN; 4241590Srgrimes } 4251590Srgrimes if ( p1 -> value > p2 -> value ) { 4261590Srgrimes return GREATERTHAN; 4271590Srgrimes } 4281590Srgrimes return EQUALTO; 4291590Srgrimes} 4301590Srgrimes 4311590Srgrimesreadsamples(pfile) 4321590Srgrimes FILE *pfile; 4331590Srgrimes{ 4341590Srgrimes register i; 43591738Sbde intmax_t sample; 4368874Srgrimes 4371590Srgrimes if (samples == 0) { 43891738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 4391590Srgrimes if (samples == 0) { 44091738Sbde warnx("no room for %d sample pc's", nsamples); 4411590Srgrimes done(); 4421590Srgrimes } 4431590Srgrimes } 4441590Srgrimes for (i = 0; i < nsamples; i++) { 44591738Sbde fread(&sample, histcounter_size, 1, pfile); 4461590Srgrimes if (feof(pfile)) 4471590Srgrimes break; 44891738Sbde switch ( histcounter_type ) { 44991738Sbde case -8: 45091738Sbde samples[i] += *(int8_t *)&sample; 45191738Sbde break; 45291738Sbde case 8: 45391738Sbde samples[i] += *(u_int8_t *)&sample; 45491738Sbde break; 45591738Sbde case -16: 45691738Sbde samples[i] += *(int16_t *)&sample; 45791738Sbde break; 45891738Sbde case 16: 45991738Sbde samples[i] += *(u_int16_t *)&sample; 46091738Sbde break; 46191738Sbde case -32: 46291738Sbde samples[i] += *(int32_t *)&sample; 46391738Sbde break; 46491738Sbde case 32: 46591738Sbde samples[i] += *(u_int32_t *)&sample; 46691738Sbde break; 46791738Sbde case -64: 46891738Sbde samples[i] += *(int64_t *)&sample; 46991738Sbde break; 47091738Sbde case 64: 47191738Sbde samples[i] += *(u_int64_t *)&sample; 47291738Sbde break; 47391738Sbde default: 47491738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 47591738Sbde } 4761590Srgrimes } 4771590Srgrimes if (i != nsamples) { 47827313Scharnier warnx("unexpected EOF after reading %d/%d samples", --i , nsamples ); 4791590Srgrimes done(); 4801590Srgrimes } 4811590Srgrimes} 4821590Srgrimes 4831590Srgrimes/* 4841590Srgrimes * Assign samples to the procedures to which they belong. 4851590Srgrimes * 4861590Srgrimes * There are three cases as to where pcl and pch can be 4871590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4881590Srgrimes * as shown in the following diagram. overlap computes the 4891590Srgrimes * distance between the arrows, the fraction of the sample 4901590Srgrimes * that is to be credited to the routine which starts at svalue0. 4911590Srgrimes * 4921590Srgrimes * svalue0 svalue1 4931590Srgrimes * | | 4941590Srgrimes * v v 4951590Srgrimes * 4961590Srgrimes * +-----------------------------------------------+ 4971590Srgrimes * | | 4981590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4991590Srgrimes * | | | | | | 5001590Srgrimes * +---------+ +---------+ +---------+ 5011590Srgrimes * 5021590Srgrimes * ^ ^ ^ ^ ^ ^ 5031590Srgrimes * | | | | | | 5041590Srgrimes * pcl pch pcl pch pcl pch 5051590Srgrimes * 5061590Srgrimes * For the vax we assert that samples will never fall in the first 5071590Srgrimes * two bytes of any routine, since that is the entry mask, 5081590Srgrimes * thus we give call alignentries() to adjust the entry points if 5091590Srgrimes * the entry mask falls in one bucket but the code for the routine 5101590Srgrimes * doesn't start until the next bucket. In conjunction with the 5111590Srgrimes * alignment of routine addresses, this should allow us to have 5121590Srgrimes * only one sample for every four bytes of text space and never 5131590Srgrimes * have any overlap (the two end cases, above). 5141590Srgrimes */ 5151590Srgrimesasgnsamples() 5161590Srgrimes{ 5171590Srgrimes register int j; 51891738Sbde double ccnt; 5191590Srgrimes double time; 5201590Srgrimes unsigned long pcl, pch; 5211590Srgrimes register int i; 5221590Srgrimes unsigned long overlap; 5231590Srgrimes unsigned long svalue0, svalue1; 5241590Srgrimes 5251590Srgrimes /* read samples and assign to namelist symbols */ 5261590Srgrimes scale = highpc - lowpc; 5271590Srgrimes scale /= nsamples; 5281590Srgrimes alignentries(); 5291590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5301590Srgrimes ccnt = samples[i]; 5311590Srgrimes if (ccnt == 0) 5321590Srgrimes continue; 53348839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 53448839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5351590Srgrimes time = ccnt; 5361590Srgrimes# ifdef DEBUG 5371590Srgrimes if ( debug & SAMPLEDEBUG ) { 53891738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5391590Srgrimes pcl , pch , ccnt ); 5401590Srgrimes } 5411590Srgrimes# endif DEBUG 5421590Srgrimes totime += time; 5431590Srgrimes for (j = j - 1; j < nname; j++) { 5441590Srgrimes svalue0 = nl[j].svalue; 5451590Srgrimes svalue1 = nl[j+1].svalue; 5461590Srgrimes /* 5478874Srgrimes * if high end of tick is below entry address, 5481590Srgrimes * go for next tick. 5491590Srgrimes */ 5501590Srgrimes if (pch < svalue0) 5511590Srgrimes break; 5521590Srgrimes /* 5531590Srgrimes * if low end of tick into next routine, 5541590Srgrimes * go for next routine. 5551590Srgrimes */ 5561590Srgrimes if (pcl >= svalue1) 5571590Srgrimes continue; 5581590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5591590Srgrimes if (overlap > 0) { 5601590Srgrimes# ifdef DEBUG 5611590Srgrimes if (debug & SAMPLEDEBUG) { 56291018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 56391735Sbde nl[j].value / HISTORICAL_SCALE_2, 56491735Sbde svalue0, svalue1, nl[j].name, 5651590Srgrimes overlap * time / scale, overlap); 5661590Srgrimes } 5671590Srgrimes# endif DEBUG 5681590Srgrimes nl[j].time += overlap * time / scale; 5691590Srgrimes } 5701590Srgrimes } 5711590Srgrimes } 5721590Srgrimes# ifdef DEBUG 5731590Srgrimes if (debug & SAMPLEDEBUG) { 5741590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5751590Srgrimes } 5761590Srgrimes# endif DEBUG 5771590Srgrimes} 5781590Srgrimes 5791590Srgrimes 5801590Srgrimesunsigned long 5811590Srgrimesmin(a, b) 5821590Srgrimes unsigned long a,b; 5831590Srgrimes{ 5841590Srgrimes if (a<b) 5851590Srgrimes return(a); 5861590Srgrimes return(b); 5871590Srgrimes} 5881590Srgrimes 5891590Srgrimesunsigned long 5901590Srgrimesmax(a, b) 5911590Srgrimes unsigned long a,b; 5921590Srgrimes{ 5931590Srgrimes if (a>b) 5941590Srgrimes return(a); 5951590Srgrimes return(b); 5961590Srgrimes} 5971590Srgrimes 5981590Srgrimes /* 5991590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 6001590Srgrimes * and possibly push the scaled entry points over the entry mask, 6011590Srgrimes * if it turns out that the entry point is in one bucket and the code 6021590Srgrimes * for a routine is in the next bucket. 6031590Srgrimes */ 6041590Srgrimesalignentries() 6051590Srgrimes{ 6061590Srgrimes register struct nl *nlp; 6071590Srgrimes unsigned long bucket_of_entry; 6081590Srgrimes unsigned long bucket_of_code; 6091590Srgrimes 6101590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 61191735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 6121590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 61391735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 61491735Sbde lowpc) / scale; 6151590Srgrimes if (bucket_of_entry < bucket_of_code) { 6161590Srgrimes# ifdef DEBUG 6171590Srgrimes if (debug & SAMPLEDEBUG) { 61891018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 61991735Sbde nlp->svalue, 62091735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6211590Srgrimes } 6221590Srgrimes# endif DEBUG 62391735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6241590Srgrimes } 6251590Srgrimes } 6261590Srgrimes} 6271590Srgrimes 6281590Srgrimesdone() 6291590Srgrimes{ 6301590Srgrimes 6311590Srgrimes exit(0); 6321590Srgrimes} 633