gprof.c revision 38928
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[] = 4538928Sjdp "$Id: gprof.c,v 1.7 1998/08/08 17:48:26 jdp Exp $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 4827313Scharnier#include <err.h> 491590Srgrimes#include "gprof.h" 501590Srgrimes 5138928Sjdpstatic int valcmp(const void *, const void *); 521590Srgrimes 5338928Sjdp 541590Srgrimesstatic struct gmonhdr gmonhdr; 555190Swollmanstatic int lflag; 565190Swollmanstatic int Lflag; 571590Srgrimes 581590Srgrimesmain(argc, argv) 591590Srgrimes int argc; 601590Srgrimes char **argv; 611590Srgrimes{ 621590Srgrimes char **sp; 631590Srgrimes nltype **timesortnlp; 6438928Sjdp char **defaultEs; 651590Srgrimes 661590Srgrimes --argc; 671590Srgrimes argv++; 681590Srgrimes debug = 0; 691590Srgrimes bflag = TRUE; 701590Srgrimes while ( *argv != 0 && **argv == '-' ) { 711590Srgrimes (*argv)++; 721590Srgrimes switch ( **argv ) { 731590Srgrimes case 'a': 741590Srgrimes aflag = TRUE; 751590Srgrimes break; 761590Srgrimes case 'b': 771590Srgrimes bflag = FALSE; 781590Srgrimes break; 791590Srgrimes case 'C': 801590Srgrimes Cflag = TRUE; 811590Srgrimes cyclethreshold = atoi( *++argv ); 821590Srgrimes break; 831590Srgrimes case 'c': 841590Srgrimes#if defined(vax) || defined(tahoe) 851590Srgrimes cflag = TRUE; 861590Srgrimes#else 8727313Scharnier errx(1, "-c isn't supported on this architecture yet"); 881590Srgrimes#endif 891590Srgrimes break; 901590Srgrimes case 'd': 911590Srgrimes dflag = TRUE; 921590Srgrimes setlinebuf(stdout); 931590Srgrimes debug |= atoi( *++argv ); 941590Srgrimes debug |= ANYDEBUG; 951590Srgrimes# ifdef DEBUG 961590Srgrimes printf("[main] debug = %d\n", debug); 971590Srgrimes# else not DEBUG 9827313Scharnier printf("gprof: -d ignored\n"); 991590Srgrimes# endif DEBUG 1001590Srgrimes break; 1011590Srgrimes case 'E': 1021590Srgrimes ++argv; 1031590Srgrimes addlist( Elist , *argv ); 1041590Srgrimes Eflag = TRUE; 1051590Srgrimes addlist( elist , *argv ); 1061590Srgrimes eflag = TRUE; 1071590Srgrimes break; 1081590Srgrimes case 'e': 1091590Srgrimes addlist( elist , *++argv ); 1101590Srgrimes eflag = TRUE; 1111590Srgrimes break; 1121590Srgrimes case 'F': 1131590Srgrimes ++argv; 1141590Srgrimes addlist( Flist , *argv ); 1151590Srgrimes Fflag = TRUE; 1161590Srgrimes addlist( flist , *argv ); 1171590Srgrimes fflag = TRUE; 1181590Srgrimes break; 1191590Srgrimes case 'f': 1201590Srgrimes addlist( flist , *++argv ); 1211590Srgrimes fflag = TRUE; 1221590Srgrimes break; 1231590Srgrimes case 'k': 1241590Srgrimes addlist( kfromlist , *++argv ); 1251590Srgrimes addlist( ktolist , *++argv ); 1261590Srgrimes kflag = TRUE; 1271590Srgrimes break; 1285190Swollman case 'l': 1295190Swollman lflag = 1; 1305190Swollman Lflag = 0; 1315190Swollman break; 1325190Swollman case 'L': 1335190Swollman Lflag = 1; 1345190Swollman lflag = 0; 1355190Swollman break; 1365190Swollman case 's': 1371590Srgrimes sflag = TRUE; 1381590Srgrimes break; 1392513Sbde case 'u': 1402513Sbde uflag = TRUE; 1412513Sbde break; 1421590Srgrimes case 'z': 1431590Srgrimes zflag = TRUE; 1441590Srgrimes break; 1451590Srgrimes } 1461590Srgrimes argv++; 1471590Srgrimes } 1481590Srgrimes if ( *argv != 0 ) { 1491590Srgrimes a_outname = *argv; 1501590Srgrimes argv++; 1511590Srgrimes } else { 1521590Srgrimes a_outname = A_OUTNAME; 1531590Srgrimes } 1541590Srgrimes if ( *argv != 0 ) { 1551590Srgrimes gmonname = *argv; 1561590Srgrimes argv++; 1571590Srgrimes } else { 1581590Srgrimes gmonname = GMONNAME; 1591590Srgrimes } 1601590Srgrimes /* 16138928Sjdp * get information from the executable file. 16238928Sjdp */ 16338928Sjdp if (elf_getnfile(a_outname, &defaultEs) == -1 && 16438928Sjdp aout_getnfile(a_outname, &defaultEs) == -1) 16538928Sjdp errx(1, "%s: bad format", a_outname); 16638928Sjdp /* 16738928Sjdp * sort symbol table. 16838928Sjdp */ 16938928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17038928Sjdp /* 1711590Srgrimes * turn off default functions 1721590Srgrimes */ 17338928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1741590Srgrimes Eflag = TRUE; 1751590Srgrimes addlist( Elist , *sp ); 1761590Srgrimes eflag = TRUE; 1771590Srgrimes addlist( elist , *sp ); 1781590Srgrimes } 1791590Srgrimes /* 1801590Srgrimes * get information about mon.out file(s). 1811590Srgrimes */ 1821590Srgrimes do { 1831590Srgrimes getpfile( gmonname ); 1841590Srgrimes if ( *argv != 0 ) { 1851590Srgrimes gmonname = *argv; 1861590Srgrimes } 1871590Srgrimes } while ( *argv++ != 0 ); 1881590Srgrimes /* 1891590Srgrimes * how many ticks per second? 1901590Srgrimes * if we can't tell, report time in ticks. 1911590Srgrimes */ 1921590Srgrimes if (hz == 0) { 1931590Srgrimes hz = 1; 1941590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1951590Srgrimes } 1961590Srgrimes /* 1971590Srgrimes * dump out a gmon.sum file if requested 1981590Srgrimes */ 1991590Srgrimes if ( sflag ) { 2001590Srgrimes dumpsum( GMONSUM ); 2011590Srgrimes } 2021590Srgrimes /* 2031590Srgrimes * assign samples to procedures 2041590Srgrimes */ 2051590Srgrimes asgnsamples(); 2061590Srgrimes /* 2071590Srgrimes * assemble the dynamic profile 2081590Srgrimes */ 2091590Srgrimes timesortnlp = doarcs(); 2101590Srgrimes /* 2111590Srgrimes * print the dynamic profile 2121590Srgrimes */ 2135190Swollman if(!lflag) { 2148874Srgrimes printgprof( timesortnlp ); 2155190Swollman } 2161590Srgrimes /* 2171590Srgrimes * print the flat profile 2181590Srgrimes */ 2195190Swollman if(!Lflag) { 2205190Swollman printprof(); 2215190Swollman } 2221590Srgrimes /* 2231590Srgrimes * print the index 2241590Srgrimes */ 2258874Srgrimes printindex(); 2261590Srgrimes done(); 2271590Srgrimes} 2281590Srgrimes 2291590Srgrimes /* 2301590Srgrimes * information from a gmon.out file is in two parts: 2311590Srgrimes * an array of sampling hits within pc ranges, 2321590Srgrimes * and the arcs. 2331590Srgrimes */ 2341590Srgrimesgetpfile(filename) 2351590Srgrimes char *filename; 2361590Srgrimes{ 2371590Srgrimes FILE *pfile; 2381590Srgrimes FILE *openpfile(); 2391590Srgrimes struct rawarc arc; 2401590Srgrimes 2411590Srgrimes pfile = openpfile(filename); 2421590Srgrimes readsamples(pfile); 2431590Srgrimes /* 2441590Srgrimes * the rest of the file consists of 2451590Srgrimes * a bunch of <from,self,count> tuples. 2461590Srgrimes */ 2471590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2481590Srgrimes# ifdef DEBUG 2491590Srgrimes if ( debug & SAMPLEDEBUG ) { 2501590Srgrimes printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2511590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2521590Srgrimes } 2531590Srgrimes# endif DEBUG 2541590Srgrimes /* 2551590Srgrimes * add this arc 2561590Srgrimes */ 2571590Srgrimes tally( &arc ); 2581590Srgrimes } 2591590Srgrimes fclose(pfile); 2601590Srgrimes} 2611590Srgrimes 2621590SrgrimesFILE * 2631590Srgrimesopenpfile(filename) 2641590Srgrimes char *filename; 2651590Srgrimes{ 2661590Srgrimes struct gmonhdr tmp; 2671590Srgrimes FILE *pfile; 2681590Srgrimes int size; 2691590Srgrimes int rate; 2701590Srgrimes 2711590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 2721590Srgrimes perror(filename); 2731590Srgrimes done(); 2741590Srgrimes } 2751590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2761590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 2771590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 27827313Scharnier warnx("%s: incompatible with first gmon file", filename); 2791590Srgrimes done(); 2801590Srgrimes } 2811590Srgrimes gmonhdr = tmp; 2821590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2831590Srgrimes rate = gmonhdr.profrate; 2841590Srgrimes size = sizeof(struct gmonhdr); 2851590Srgrimes } else { 2861590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2871590Srgrimes size = sizeof(struct ophdr); 2881590Srgrimes gmonhdr.profrate = rate = hertz(); 2891590Srgrimes gmonhdr.version = GMONVERSION; 2901590Srgrimes } 2911590Srgrimes if (hz == 0) { 2921590Srgrimes hz = rate; 2931590Srgrimes } else if (hz != rate) { 2941590Srgrimes fprintf(stderr, 2951590Srgrimes "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 2961590Srgrimes filename, rate, "incompatible with clock rate", hz); 2971590Srgrimes done(); 2981590Srgrimes } 2991590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3001590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 3011590Srgrimes lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 3021590Srgrimes highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 3031590Srgrimes sampbytes = gmonhdr.ncnt - size; 3041590Srgrimes nsamples = sampbytes / sizeof (UNIT); 3051590Srgrimes# ifdef DEBUG 3061590Srgrimes if ( debug & SAMPLEDEBUG ) { 3071590Srgrimes printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 3081590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 3091590Srgrimes printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 3101590Srgrimes s_lowpc , s_highpc ); 3111590Srgrimes printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 3121590Srgrimes lowpc , highpc ); 3131590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3141590Srgrimes sampbytes , nsamples ); 3151590Srgrimes printf( "[openpfile] sample rate %d\n" , hz ); 3161590Srgrimes } 3171590Srgrimes# endif DEBUG 3181590Srgrimes return(pfile); 3191590Srgrimes} 3201590Srgrimes 3211590Srgrimestally( rawp ) 3221590Srgrimes struct rawarc *rawp; 3231590Srgrimes{ 3241590Srgrimes nltype *parentp; 3251590Srgrimes nltype *childp; 3261590Srgrimes 3271590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3281590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3291590Srgrimes if ( parentp == 0 || childp == 0 ) 3301590Srgrimes return; 3311590Srgrimes if ( kflag 3321590Srgrimes && onlist( kfromlist , parentp -> name ) 3331590Srgrimes && onlist( ktolist , childp -> name ) ) { 3341590Srgrimes return; 3351590Srgrimes } 3361590Srgrimes childp -> ncall += rawp -> raw_count; 3371590Srgrimes# ifdef DEBUG 3381590Srgrimes if ( debug & TALLYDEBUG ) { 3391590Srgrimes printf( "[tally] arc from %s to %s traversed %d times\n" , 3401590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3411590Srgrimes } 3421590Srgrimes# endif DEBUG 3431590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3441590Srgrimes} 3451590Srgrimes 3461590Srgrimes/* 3471590Srgrimes * dump out the gmon.sum file 3481590Srgrimes */ 3491590Srgrimesdumpsum( sumfile ) 3501590Srgrimes char *sumfile; 3511590Srgrimes{ 3521590Srgrimes register nltype *nlp; 3531590Srgrimes register arctype *arcp; 3541590Srgrimes struct rawarc arc; 3551590Srgrimes FILE *sfile; 3561590Srgrimes 3571590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3581590Srgrimes perror( sumfile ); 3591590Srgrimes done(); 3601590Srgrimes } 3611590Srgrimes /* 3621590Srgrimes * dump the header; use the last header read in 3631590Srgrimes */ 3641590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 3651590Srgrimes perror( sumfile ); 3661590Srgrimes done(); 3671590Srgrimes } 3681590Srgrimes /* 3691590Srgrimes * dump the samples 3701590Srgrimes */ 3711590Srgrimes if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 3721590Srgrimes perror( sumfile ); 3731590Srgrimes done(); 3741590Srgrimes } 3751590Srgrimes /* 3761590Srgrimes * dump the normalized raw arc information 3771590Srgrimes */ 3781590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3791590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3801590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3811590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3821590Srgrimes arc.raw_count = arcp -> arc_count; 3831590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3841590Srgrimes perror( sumfile ); 3851590Srgrimes done(); 3861590Srgrimes } 3871590Srgrimes# ifdef DEBUG 3881590Srgrimes if ( debug & SAMPLEDEBUG ) { 3891590Srgrimes printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 3901590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3911590Srgrimes } 3921590Srgrimes# endif DEBUG 3931590Srgrimes } 3941590Srgrimes } 3951590Srgrimes fclose( sfile ); 3961590Srgrimes} 3971590Srgrimes 39838928Sjdpstatic int 39938928Sjdpvalcmp(v1, v2) 40038928Sjdp const void *v1; 40138928Sjdp const void *v2; 4021590Srgrimes{ 40338928Sjdp const nltype *p1 = (const nltype *)v1; 40438928Sjdp const nltype *p2 = (const nltype *)v2; 40538928Sjdp 4061590Srgrimes if ( p1 -> value < p2 -> value ) { 4071590Srgrimes return LESSTHAN; 4081590Srgrimes } 4091590Srgrimes if ( p1 -> value > p2 -> value ) { 4101590Srgrimes return GREATERTHAN; 4111590Srgrimes } 4121590Srgrimes return EQUALTO; 4131590Srgrimes} 4141590Srgrimes 4151590Srgrimesreadsamples(pfile) 4161590Srgrimes FILE *pfile; 4171590Srgrimes{ 4181590Srgrimes register i; 4191590Srgrimes UNIT sample; 4208874Srgrimes 4211590Srgrimes if (samples == 0) { 4221590Srgrimes samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 4231590Srgrimes if (samples == 0) { 42427313Scharnier warnx("no room for %d sample pc's", sampbytes / sizeof (UNIT)); 4251590Srgrimes done(); 4261590Srgrimes } 4271590Srgrimes } 4281590Srgrimes for (i = 0; i < nsamples; i++) { 4291590Srgrimes fread(&sample, sizeof (UNIT), 1, pfile); 4301590Srgrimes if (feof(pfile)) 4311590Srgrimes break; 4321590Srgrimes samples[i] += sample; 4331590Srgrimes } 4341590Srgrimes if (i != nsamples) { 43527313Scharnier warnx("unexpected EOF after reading %d/%d samples", --i , nsamples ); 4361590Srgrimes done(); 4371590Srgrimes } 4381590Srgrimes} 4391590Srgrimes 4401590Srgrimes/* 4411590Srgrimes * Assign samples to the procedures to which they belong. 4421590Srgrimes * 4431590Srgrimes * There are three cases as to where pcl and pch can be 4441590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4451590Srgrimes * as shown in the following diagram. overlap computes the 4461590Srgrimes * distance between the arrows, the fraction of the sample 4471590Srgrimes * that is to be credited to the routine which starts at svalue0. 4481590Srgrimes * 4491590Srgrimes * svalue0 svalue1 4501590Srgrimes * | | 4511590Srgrimes * v v 4521590Srgrimes * 4531590Srgrimes * +-----------------------------------------------+ 4541590Srgrimes * | | 4551590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4561590Srgrimes * | | | | | | 4571590Srgrimes * +---------+ +---------+ +---------+ 4581590Srgrimes * 4591590Srgrimes * ^ ^ ^ ^ ^ ^ 4601590Srgrimes * | | | | | | 4611590Srgrimes * pcl pch pcl pch pcl pch 4621590Srgrimes * 4631590Srgrimes * For the vax we assert that samples will never fall in the first 4641590Srgrimes * two bytes of any routine, since that is the entry mask, 4651590Srgrimes * thus we give call alignentries() to adjust the entry points if 4661590Srgrimes * the entry mask falls in one bucket but the code for the routine 4671590Srgrimes * doesn't start until the next bucket. In conjunction with the 4681590Srgrimes * alignment of routine addresses, this should allow us to have 4691590Srgrimes * only one sample for every four bytes of text space and never 4701590Srgrimes * have any overlap (the two end cases, above). 4711590Srgrimes */ 4721590Srgrimesasgnsamples() 4731590Srgrimes{ 4741590Srgrimes register int j; 4751590Srgrimes UNIT ccnt; 4761590Srgrimes double time; 4771590Srgrimes unsigned long pcl, pch; 4781590Srgrimes register int i; 4791590Srgrimes unsigned long overlap; 4801590Srgrimes unsigned long svalue0, svalue1; 4811590Srgrimes 4821590Srgrimes /* read samples and assign to namelist symbols */ 4831590Srgrimes scale = highpc - lowpc; 4841590Srgrimes scale /= nsamples; 4851590Srgrimes alignentries(); 4861590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 4871590Srgrimes ccnt = samples[i]; 4881590Srgrimes if (ccnt == 0) 4891590Srgrimes continue; 4901590Srgrimes pcl = lowpc + scale * i; 4911590Srgrimes pch = lowpc + scale * (i + 1); 4921590Srgrimes time = ccnt; 4931590Srgrimes# ifdef DEBUG 4941590Srgrimes if ( debug & SAMPLEDEBUG ) { 4951590Srgrimes printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4961590Srgrimes pcl , pch , ccnt ); 4971590Srgrimes } 4981590Srgrimes# endif DEBUG 4991590Srgrimes totime += time; 5001590Srgrimes for (j = j - 1; j < nname; j++) { 5011590Srgrimes svalue0 = nl[j].svalue; 5021590Srgrimes svalue1 = nl[j+1].svalue; 5031590Srgrimes /* 5048874Srgrimes * if high end of tick is below entry address, 5051590Srgrimes * go for next tick. 5061590Srgrimes */ 5071590Srgrimes if (pch < svalue0) 5081590Srgrimes break; 5091590Srgrimes /* 5101590Srgrimes * if low end of tick into next routine, 5111590Srgrimes * go for next routine. 5121590Srgrimes */ 5131590Srgrimes if (pcl >= svalue1) 5141590Srgrimes continue; 5151590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5161590Srgrimes if (overlap > 0) { 5171590Srgrimes# ifdef DEBUG 5181590Srgrimes if (debug & SAMPLEDEBUG) { 5191590Srgrimes printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 5201590Srgrimes nl[j].value/sizeof(UNIT), svalue0, svalue1, 5218874Srgrimes nl[j].name, 5221590Srgrimes overlap * time / scale, overlap); 5231590Srgrimes } 5241590Srgrimes# endif DEBUG 5251590Srgrimes nl[j].time += overlap * time / scale; 5261590Srgrimes } 5271590Srgrimes } 5281590Srgrimes } 5291590Srgrimes# ifdef DEBUG 5301590Srgrimes if (debug & SAMPLEDEBUG) { 5311590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5321590Srgrimes } 5331590Srgrimes# endif DEBUG 5341590Srgrimes} 5351590Srgrimes 5361590Srgrimes 5371590Srgrimesunsigned long 5381590Srgrimesmin(a, b) 5391590Srgrimes unsigned long a,b; 5401590Srgrimes{ 5411590Srgrimes if (a<b) 5421590Srgrimes return(a); 5431590Srgrimes return(b); 5441590Srgrimes} 5451590Srgrimes 5461590Srgrimesunsigned long 5471590Srgrimesmax(a, b) 5481590Srgrimes unsigned long a,b; 5491590Srgrimes{ 5501590Srgrimes if (a>b) 5511590Srgrimes return(a); 5521590Srgrimes return(b); 5531590Srgrimes} 5541590Srgrimes 5551590Srgrimes /* 5561590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5571590Srgrimes * and possibly push the scaled entry points over the entry mask, 5581590Srgrimes * if it turns out that the entry point is in one bucket and the code 5591590Srgrimes * for a routine is in the next bucket. 5601590Srgrimes */ 5611590Srgrimesalignentries() 5621590Srgrimes{ 5631590Srgrimes register struct nl *nlp; 5641590Srgrimes unsigned long bucket_of_entry; 5651590Srgrimes unsigned long bucket_of_code; 5661590Srgrimes 5671590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 5681590Srgrimes nlp -> svalue = nlp -> value / sizeof(UNIT); 5691590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 5701590Srgrimes bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 5711590Srgrimes if (bucket_of_entry < bucket_of_code) { 5721590Srgrimes# ifdef DEBUG 5731590Srgrimes if (debug & SAMPLEDEBUG) { 5741590Srgrimes printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 5751590Srgrimes nlp->svalue, nlp->svalue + UNITS_TO_CODE); 5761590Srgrimes } 5771590Srgrimes# endif DEBUG 5781590Srgrimes nlp->svalue += UNITS_TO_CODE; 5791590Srgrimes } 5801590Srgrimes } 5811590Srgrimes} 5821590Srgrimes 5831590Srgrimesdone() 5841590Srgrimes{ 5851590Srgrimes 5861590Srgrimes exit(0); 5871590Srgrimes} 588