gprof.c revision 50477
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 50477 1999-08-28 01:08:13Z peter $"; 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 { 15847420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 15947420Sjmz strcpy(gmonname, a_outname); 16047420Sjmz strcat(gmonname, ".gmon"); 1611590Srgrimes } 1621590Srgrimes /* 16338928Sjdp * get information from the executable file. 16438928Sjdp */ 16538928Sjdp if (elf_getnfile(a_outname, &defaultEs) == -1 && 16638928Sjdp aout_getnfile(a_outname, &defaultEs) == -1) 16738928Sjdp errx(1, "%s: bad format", a_outname); 16838928Sjdp /* 16938928Sjdp * sort symbol table. 17038928Sjdp */ 17138928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17238928Sjdp /* 1731590Srgrimes * turn off default functions 1741590Srgrimes */ 17538928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1761590Srgrimes Eflag = TRUE; 1771590Srgrimes addlist( Elist , *sp ); 1781590Srgrimes eflag = TRUE; 1791590Srgrimes addlist( elist , *sp ); 1801590Srgrimes } 1811590Srgrimes /* 1821590Srgrimes * get information about mon.out file(s). 1831590Srgrimes */ 1841590Srgrimes do { 1851590Srgrimes getpfile( gmonname ); 1861590Srgrimes if ( *argv != 0 ) { 1871590Srgrimes gmonname = *argv; 1881590Srgrimes } 1891590Srgrimes } while ( *argv++ != 0 ); 1901590Srgrimes /* 1911590Srgrimes * how many ticks per second? 1921590Srgrimes * if we can't tell, report time in ticks. 1931590Srgrimes */ 1941590Srgrimes if (hz == 0) { 1951590Srgrimes hz = 1; 1961590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1971590Srgrimes } 1981590Srgrimes /* 1991590Srgrimes * dump out a gmon.sum file if requested 2001590Srgrimes */ 2011590Srgrimes if ( sflag ) { 2021590Srgrimes dumpsum( GMONSUM ); 2031590Srgrimes } 2041590Srgrimes /* 2051590Srgrimes * assign samples to procedures 2061590Srgrimes */ 2071590Srgrimes asgnsamples(); 2081590Srgrimes /* 2091590Srgrimes * assemble the dynamic profile 2101590Srgrimes */ 2111590Srgrimes timesortnlp = doarcs(); 2121590Srgrimes /* 2131590Srgrimes * print the dynamic profile 2141590Srgrimes */ 2155190Swollman if(!lflag) { 2168874Srgrimes printgprof( timesortnlp ); 2175190Swollman } 2181590Srgrimes /* 2191590Srgrimes * print the flat profile 2201590Srgrimes */ 2215190Swollman if(!Lflag) { 2225190Swollman printprof(); 2235190Swollman } 2241590Srgrimes /* 2251590Srgrimes * print the index 2261590Srgrimes */ 2278874Srgrimes printindex(); 2281590Srgrimes done(); 2291590Srgrimes} 2301590Srgrimes 2311590Srgrimes /* 2321590Srgrimes * information from a gmon.out file is in two parts: 2331590Srgrimes * an array of sampling hits within pc ranges, 2341590Srgrimes * and the arcs. 2351590Srgrimes */ 2361590Srgrimesgetpfile(filename) 2371590Srgrimes char *filename; 2381590Srgrimes{ 2391590Srgrimes FILE *pfile; 2401590Srgrimes FILE *openpfile(); 2411590Srgrimes struct rawarc arc; 2421590Srgrimes 2431590Srgrimes pfile = openpfile(filename); 2441590Srgrimes readsamples(pfile); 2451590Srgrimes /* 2461590Srgrimes * the rest of the file consists of 2471590Srgrimes * a bunch of <from,self,count> tuples. 2481590Srgrimes */ 2491590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 2501590Srgrimes# ifdef DEBUG 2511590Srgrimes if ( debug & SAMPLEDEBUG ) { 2521590Srgrimes printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 2531590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2541590Srgrimes } 2551590Srgrimes# endif DEBUG 2561590Srgrimes /* 2571590Srgrimes * add this arc 2581590Srgrimes */ 2591590Srgrimes tally( &arc ); 2601590Srgrimes } 2611590Srgrimes fclose(pfile); 2621590Srgrimes} 2631590Srgrimes 2641590SrgrimesFILE * 2651590Srgrimesopenpfile(filename) 2661590Srgrimes char *filename; 2671590Srgrimes{ 2681590Srgrimes struct gmonhdr tmp; 2691590Srgrimes FILE *pfile; 2701590Srgrimes int size; 2711590Srgrimes int rate; 2721590Srgrimes 2731590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 2741590Srgrimes perror(filename); 2751590Srgrimes done(); 2761590Srgrimes } 2771590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2781590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 2791590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 28027313Scharnier warnx("%s: incompatible with first gmon file", filename); 2811590Srgrimes done(); 2821590Srgrimes } 2831590Srgrimes gmonhdr = tmp; 2841590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2851590Srgrimes rate = gmonhdr.profrate; 2861590Srgrimes size = sizeof(struct gmonhdr); 2871590Srgrimes } else { 2881590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2891590Srgrimes size = sizeof(struct ophdr); 2901590Srgrimes gmonhdr.profrate = rate = hertz(); 2911590Srgrimes gmonhdr.version = GMONVERSION; 2921590Srgrimes } 2931590Srgrimes if (hz == 0) { 2941590Srgrimes hz = rate; 2951590Srgrimes } else if (hz != rate) { 2961590Srgrimes fprintf(stderr, 2971590Srgrimes "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 2981590Srgrimes filename, rate, "incompatible with clock rate", hz); 2991590Srgrimes done(); 3001590Srgrimes } 3011590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3021590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 3031590Srgrimes lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 3041590Srgrimes highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 3051590Srgrimes sampbytes = gmonhdr.ncnt - size; 3061590Srgrimes nsamples = sampbytes / sizeof (UNIT); 3071590Srgrimes# ifdef DEBUG 3081590Srgrimes if ( debug & SAMPLEDEBUG ) { 3091590Srgrimes printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 3101590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 3111590Srgrimes printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 3121590Srgrimes s_lowpc , s_highpc ); 3131590Srgrimes printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 3141590Srgrimes lowpc , highpc ); 3151590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3161590Srgrimes sampbytes , nsamples ); 3171590Srgrimes printf( "[openpfile] sample rate %d\n" , hz ); 3181590Srgrimes } 3191590Srgrimes# endif DEBUG 3201590Srgrimes return(pfile); 3211590Srgrimes} 3221590Srgrimes 3231590Srgrimestally( rawp ) 3241590Srgrimes struct rawarc *rawp; 3251590Srgrimes{ 3261590Srgrimes nltype *parentp; 3271590Srgrimes nltype *childp; 3281590Srgrimes 3291590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3301590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3311590Srgrimes if ( parentp == 0 || childp == 0 ) 3321590Srgrimes return; 3331590Srgrimes if ( kflag 3341590Srgrimes && onlist( kfromlist , parentp -> name ) 3351590Srgrimes && onlist( ktolist , childp -> name ) ) { 3361590Srgrimes return; 3371590Srgrimes } 3381590Srgrimes childp -> ncall += rawp -> raw_count; 3391590Srgrimes# ifdef DEBUG 3401590Srgrimes if ( debug & TALLYDEBUG ) { 3411590Srgrimes printf( "[tally] arc from %s to %s traversed %d times\n" , 3421590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3431590Srgrimes } 3441590Srgrimes# endif DEBUG 3451590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3461590Srgrimes} 3471590Srgrimes 3481590Srgrimes/* 3491590Srgrimes * dump out the gmon.sum file 3501590Srgrimes */ 3511590Srgrimesdumpsum( sumfile ) 3521590Srgrimes char *sumfile; 3531590Srgrimes{ 3541590Srgrimes register nltype *nlp; 3551590Srgrimes register arctype *arcp; 3561590Srgrimes struct rawarc arc; 3571590Srgrimes FILE *sfile; 3581590Srgrimes 3591590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 3601590Srgrimes perror( sumfile ); 3611590Srgrimes done(); 3621590Srgrimes } 3631590Srgrimes /* 3641590Srgrimes * dump the header; use the last header read in 3651590Srgrimes */ 3661590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 3671590Srgrimes perror( sumfile ); 3681590Srgrimes done(); 3691590Srgrimes } 3701590Srgrimes /* 3711590Srgrimes * dump the samples 3721590Srgrimes */ 3731590Srgrimes if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 3741590Srgrimes perror( sumfile ); 3751590Srgrimes done(); 3761590Srgrimes } 3771590Srgrimes /* 3781590Srgrimes * dump the normalized raw arc information 3791590Srgrimes */ 3801590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3811590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3821590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3831590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3841590Srgrimes arc.raw_count = arcp -> arc_count; 3851590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 3861590Srgrimes perror( sumfile ); 3871590Srgrimes done(); 3881590Srgrimes } 3891590Srgrimes# ifdef DEBUG 3901590Srgrimes if ( debug & SAMPLEDEBUG ) { 3911590Srgrimes printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 3921590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3931590Srgrimes } 3941590Srgrimes# endif DEBUG 3951590Srgrimes } 3961590Srgrimes } 3971590Srgrimes fclose( sfile ); 3981590Srgrimes} 3991590Srgrimes 40038928Sjdpstatic int 40138928Sjdpvalcmp(v1, v2) 40238928Sjdp const void *v1; 40338928Sjdp const void *v2; 4041590Srgrimes{ 40538928Sjdp const nltype *p1 = (const nltype *)v1; 40638928Sjdp const nltype *p2 = (const nltype *)v2; 40738928Sjdp 4081590Srgrimes if ( p1 -> value < p2 -> value ) { 4091590Srgrimes return LESSTHAN; 4101590Srgrimes } 4111590Srgrimes if ( p1 -> value > p2 -> value ) { 4121590Srgrimes return GREATERTHAN; 4131590Srgrimes } 4141590Srgrimes return EQUALTO; 4151590Srgrimes} 4161590Srgrimes 4171590Srgrimesreadsamples(pfile) 4181590Srgrimes FILE *pfile; 4191590Srgrimes{ 4201590Srgrimes register i; 4211590Srgrimes UNIT sample; 4228874Srgrimes 4231590Srgrimes if (samples == 0) { 4241590Srgrimes samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 4251590Srgrimes if (samples == 0) { 42627313Scharnier warnx("no room for %d sample pc's", sampbytes / sizeof (UNIT)); 4271590Srgrimes done(); 4281590Srgrimes } 4291590Srgrimes } 4301590Srgrimes for (i = 0; i < nsamples; i++) { 4311590Srgrimes fread(&sample, sizeof (UNIT), 1, pfile); 4321590Srgrimes if (feof(pfile)) 4331590Srgrimes break; 4341590Srgrimes samples[i] += sample; 4351590Srgrimes } 4361590Srgrimes if (i != nsamples) { 43727313Scharnier warnx("unexpected EOF after reading %d/%d samples", --i , nsamples ); 4381590Srgrimes done(); 4391590Srgrimes } 4401590Srgrimes} 4411590Srgrimes 4421590Srgrimes/* 4431590Srgrimes * Assign samples to the procedures to which they belong. 4441590Srgrimes * 4451590Srgrimes * There are three cases as to where pcl and pch can be 4461590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4471590Srgrimes * as shown in the following diagram. overlap computes the 4481590Srgrimes * distance between the arrows, the fraction of the sample 4491590Srgrimes * that is to be credited to the routine which starts at svalue0. 4501590Srgrimes * 4511590Srgrimes * svalue0 svalue1 4521590Srgrimes * | | 4531590Srgrimes * v v 4541590Srgrimes * 4551590Srgrimes * +-----------------------------------------------+ 4561590Srgrimes * | | 4571590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4581590Srgrimes * | | | | | | 4591590Srgrimes * +---------+ +---------+ +---------+ 4601590Srgrimes * 4611590Srgrimes * ^ ^ ^ ^ ^ ^ 4621590Srgrimes * | | | | | | 4631590Srgrimes * pcl pch pcl pch pcl pch 4641590Srgrimes * 4651590Srgrimes * For the vax we assert that samples will never fall in the first 4661590Srgrimes * two bytes of any routine, since that is the entry mask, 4671590Srgrimes * thus we give call alignentries() to adjust the entry points if 4681590Srgrimes * the entry mask falls in one bucket but the code for the routine 4691590Srgrimes * doesn't start until the next bucket. In conjunction with the 4701590Srgrimes * alignment of routine addresses, this should allow us to have 4711590Srgrimes * only one sample for every four bytes of text space and never 4721590Srgrimes * have any overlap (the two end cases, above). 4731590Srgrimes */ 4741590Srgrimesasgnsamples() 4751590Srgrimes{ 4761590Srgrimes register int j; 4771590Srgrimes UNIT ccnt; 4781590Srgrimes double time; 4791590Srgrimes unsigned long pcl, pch; 4801590Srgrimes register int i; 4811590Srgrimes unsigned long overlap; 4821590Srgrimes unsigned long svalue0, svalue1; 4831590Srgrimes 4841590Srgrimes /* read samples and assign to namelist symbols */ 4851590Srgrimes scale = highpc - lowpc; 4861590Srgrimes scale /= nsamples; 4871590Srgrimes alignentries(); 4881590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 4891590Srgrimes ccnt = samples[i]; 4901590Srgrimes if (ccnt == 0) 4911590Srgrimes continue; 49248839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 49348839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 4941590Srgrimes time = ccnt; 4951590Srgrimes# ifdef DEBUG 4961590Srgrimes if ( debug & SAMPLEDEBUG ) { 4971590Srgrimes printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 4981590Srgrimes pcl , pch , ccnt ); 4991590Srgrimes } 5001590Srgrimes# endif DEBUG 5011590Srgrimes totime += time; 5021590Srgrimes for (j = j - 1; j < nname; j++) { 5031590Srgrimes svalue0 = nl[j].svalue; 5041590Srgrimes svalue1 = nl[j+1].svalue; 5051590Srgrimes /* 5068874Srgrimes * if high end of tick is below entry address, 5071590Srgrimes * go for next tick. 5081590Srgrimes */ 5091590Srgrimes if (pch < svalue0) 5101590Srgrimes break; 5111590Srgrimes /* 5121590Srgrimes * if low end of tick into next routine, 5131590Srgrimes * go for next routine. 5141590Srgrimes */ 5151590Srgrimes if (pcl >= svalue1) 5161590Srgrimes continue; 5171590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5181590Srgrimes if (overlap > 0) { 5191590Srgrimes# ifdef DEBUG 5201590Srgrimes if (debug & SAMPLEDEBUG) { 5211590Srgrimes printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 5221590Srgrimes nl[j].value/sizeof(UNIT), svalue0, svalue1, 5238874Srgrimes nl[j].name, 5241590Srgrimes overlap * time / scale, overlap); 5251590Srgrimes } 5261590Srgrimes# endif DEBUG 5271590Srgrimes nl[j].time += overlap * time / scale; 5281590Srgrimes } 5291590Srgrimes } 5301590Srgrimes } 5311590Srgrimes# ifdef DEBUG 5321590Srgrimes if (debug & SAMPLEDEBUG) { 5331590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5341590Srgrimes } 5351590Srgrimes# endif DEBUG 5361590Srgrimes} 5371590Srgrimes 5381590Srgrimes 5391590Srgrimesunsigned long 5401590Srgrimesmin(a, b) 5411590Srgrimes unsigned long a,b; 5421590Srgrimes{ 5431590Srgrimes if (a<b) 5441590Srgrimes return(a); 5451590Srgrimes return(b); 5461590Srgrimes} 5471590Srgrimes 5481590Srgrimesunsigned long 5491590Srgrimesmax(a, b) 5501590Srgrimes unsigned long a,b; 5511590Srgrimes{ 5521590Srgrimes if (a>b) 5531590Srgrimes return(a); 5541590Srgrimes return(b); 5551590Srgrimes} 5561590Srgrimes 5571590Srgrimes /* 5581590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5591590Srgrimes * and possibly push the scaled entry points over the entry mask, 5601590Srgrimes * if it turns out that the entry point is in one bucket and the code 5611590Srgrimes * for a routine is in the next bucket. 5621590Srgrimes */ 5631590Srgrimesalignentries() 5641590Srgrimes{ 5651590Srgrimes register struct nl *nlp; 5661590Srgrimes unsigned long bucket_of_entry; 5671590Srgrimes unsigned long bucket_of_code; 5681590Srgrimes 5691590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 5701590Srgrimes nlp -> svalue = nlp -> value / sizeof(UNIT); 5711590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 5721590Srgrimes bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 5731590Srgrimes if (bucket_of_entry < bucket_of_code) { 5741590Srgrimes# ifdef DEBUG 5751590Srgrimes if (debug & SAMPLEDEBUG) { 5761590Srgrimes printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 5771590Srgrimes nlp->svalue, nlp->svalue + UNITS_TO_CODE); 5781590Srgrimes } 5791590Srgrimes# endif DEBUG 5801590Srgrimes nlp->svalue += UNITS_TO_CODE; 5811590Srgrimes } 5821590Srgrimes } 5831590Srgrimes} 5841590Srgrimes 5851590Srgrimesdone() 5861590Srgrimes{ 5871590Srgrimes 5881590Srgrimes exit(0); 5891590Srgrimes} 590