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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127313Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 36105243Scharnier#if 0 371590Srgrimes#ifndef lint 381590Srgrimesstatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 39105243Scharnier#endif /* not lint */ 4027313Scharnier#endif 41105243Scharnier 4299112Sobrien#include <sys/cdefs.h> 4399112Sobrien__FBSDID("$FreeBSD$"); 441590Srgrimes 4527313Scharnier#include <err.h> 4691738Sbde#include <limits.h> 4793123Smike#include <stdint.h> 48129657Sstefanf#include <string.h> 49129657Sstefanf 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 59105243Scharnierint 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 'd': 861590Srgrimes dflag = TRUE; 871590Srgrimes setlinebuf(stdout); 881590Srgrimes debug |= atoi( *++argv ); 891590Srgrimes debug |= ANYDEBUG; 901590Srgrimes# ifdef DEBUG 911590Srgrimes printf("[main] debug = %d\n", debug); 9297631Swollman# else /* not DEBUG */ 9327313Scharnier printf("gprof: -d ignored\n"); 9497631Swollman# endif /* DEBUG */ 951590Srgrimes break; 961590Srgrimes case 'E': 971590Srgrimes ++argv; 981590Srgrimes addlist( Elist , *argv ); 991590Srgrimes Eflag = TRUE; 1001590Srgrimes addlist( elist , *argv ); 1011590Srgrimes eflag = TRUE; 1021590Srgrimes break; 1031590Srgrimes case 'e': 1041590Srgrimes addlist( elist , *++argv ); 1051590Srgrimes eflag = TRUE; 1061590Srgrimes break; 1071590Srgrimes case 'F': 1081590Srgrimes ++argv; 1091590Srgrimes addlist( Flist , *argv ); 1101590Srgrimes Fflag = TRUE; 1111590Srgrimes addlist( flist , *argv ); 1121590Srgrimes fflag = TRUE; 1131590Srgrimes break; 1141590Srgrimes case 'f': 1151590Srgrimes addlist( flist , *++argv ); 1161590Srgrimes fflag = TRUE; 1171590Srgrimes break; 1181590Srgrimes case 'k': 1191590Srgrimes addlist( kfromlist , *++argv ); 1201590Srgrimes addlist( ktolist , *++argv ); 1211590Srgrimes kflag = TRUE; 1221590Srgrimes break; 12385739Sgreen case 'K': 12485739Sgreen Kflag = TRUE; 12585739Sgreen break; 126105243Scharnier case 'l': 1275190Swollman lflag = 1; 1285190Swollman Lflag = 0; 1295190Swollman break; 130105243Scharnier case 'L': 1315190Swollman Lflag = 1; 1325190Swollman lflag = 0; 1335190Swollman break; 134105243Scharnier case 's': 1351590Srgrimes sflag = TRUE; 1361590Srgrimes break; 1372513Sbde case 'u': 1382513Sbde uflag = TRUE; 1392513Sbde break; 1401590Srgrimes case 'z': 1411590Srgrimes zflag = TRUE; 1421590Srgrimes break; 1431590Srgrimes } 1441590Srgrimes argv++; 1451590Srgrimes } 1461590Srgrimes if ( *argv != 0 ) { 1471590Srgrimes a_outname = *argv; 1481590Srgrimes argv++; 1491590Srgrimes } else { 1501590Srgrimes a_outname = A_OUTNAME; 1511590Srgrimes } 1521590Srgrimes if ( *argv != 0 ) { 1531590Srgrimes gmonname = *argv; 1541590Srgrimes argv++; 1551590Srgrimes } else { 15647420Sjmz gmonname = (char *) malloc(strlen(a_outname)+6); 15747420Sjmz strcpy(gmonname, a_outname); 15847420Sjmz strcat(gmonname, ".gmon"); 1591590Srgrimes } 1601590Srgrimes /* 16138928Sjdp * get information from the executable file. 16238928Sjdp */ 16385739Sgreen if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) || 164187116Sobrien (!Kflag && elf_getnfile(a_outname, &defaultEs) == -1 && 16585739Sgreen aout_getnfile(a_outname, &defaultEs) == -1)) 16638928Sjdp errx(1, "%s: bad format", a_outname); 16738928Sjdp /* 16838928Sjdp * sort symbol table. 16938928Sjdp */ 17038928Sjdp qsort(nl, nname, sizeof(nltype), valcmp); 17138928Sjdp /* 1721590Srgrimes * turn off default functions 1731590Srgrimes */ 17438928Sjdp for ( sp = defaultEs ; *sp ; sp++ ) { 1751590Srgrimes Eflag = TRUE; 1761590Srgrimes addlist( Elist , *sp ); 1771590Srgrimes eflag = TRUE; 1781590Srgrimes addlist( elist , *sp ); 1791590Srgrimes } 1801590Srgrimes /* 1811590Srgrimes * get information about mon.out file(s). 1821590Srgrimes */ 1831590Srgrimes do { 1841590Srgrimes getpfile( gmonname ); 1851590Srgrimes if ( *argv != 0 ) { 1861590Srgrimes gmonname = *argv; 1871590Srgrimes } 1881590Srgrimes } while ( *argv++ != 0 ); 1891590Srgrimes /* 1901590Srgrimes * how many ticks per second? 1911590Srgrimes * if we can't tell, report time in ticks. 1921590Srgrimes */ 1931590Srgrimes if (hz == 0) { 1941590Srgrimes hz = 1; 1951590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1961590Srgrimes } 1971590Srgrimes /* 1981590Srgrimes * dump out a gmon.sum file if requested 1991590Srgrimes */ 2001590Srgrimes if ( sflag ) { 2011590Srgrimes dumpsum( GMONSUM ); 2021590Srgrimes } 2031590Srgrimes /* 2041590Srgrimes * assign samples to procedures 2051590Srgrimes */ 2061590Srgrimes asgnsamples(); 2071590Srgrimes /* 2081590Srgrimes * assemble the dynamic profile 2091590Srgrimes */ 2101590Srgrimes timesortnlp = doarcs(); 2111590Srgrimes /* 2121590Srgrimes * print the dynamic profile 2131590Srgrimes */ 2145190Swollman if(!lflag) { 2158874Srgrimes printgprof( timesortnlp ); 2165190Swollman } 2171590Srgrimes /* 2181590Srgrimes * print the flat profile 2191590Srgrimes */ 2205190Swollman if(!Lflag) { 2215190Swollman printprof(); 2225190Swollman } 2231590Srgrimes /* 2241590Srgrimes * print the index 2251590Srgrimes */ 2268874Srgrimes printindex(); 227105243Scharnier exit(0); 2281590Srgrimes} 2291590Srgrimes 2301590Srgrimes /* 2311590Srgrimes * information from a gmon.out file is in two parts: 2321590Srgrimes * an array of sampling hits within pc ranges, 2331590Srgrimes * and the arcs. 2341590Srgrimes */ 235105243Scharniervoid 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 ) { 25291018Sbde printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" , 2531590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 2541590Srgrimes } 25597631Swollman# 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 273105243Scharnier if((pfile = fopen(filename, "r")) == NULL) 274105243Scharnier err(1, "%s", filename); 2751590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 2761590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 277105243Scharnier tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) 278105243Scharnier errx(1, "%s: incompatible with first gmon file", filename); 2791590Srgrimes gmonhdr = tmp; 2801590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 2811590Srgrimes rate = gmonhdr.profrate; 2821590Srgrimes size = sizeof(struct gmonhdr); 2831590Srgrimes } else { 2841590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 2851590Srgrimes size = sizeof(struct ophdr); 2861590Srgrimes gmonhdr.profrate = rate = hertz(); 2871590Srgrimes gmonhdr.version = GMONVERSION; 2881590Srgrimes } 2891590Srgrimes if (hz == 0) { 2901590Srgrimes hz = rate; 291105243Scharnier } else if (hz != rate) 292105243Scharnier errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file", 2931590Srgrimes filename, rate, "incompatible with clock rate", hz); 29491738Sbde if ( gmonhdr.histcounter_type == 0 ) { 29591738Sbde /* Historical case. The type was u_short (2 bytes in practice). */ 29691738Sbde histcounter_type = 16; 29791738Sbde histcounter_size = 2; 29891738Sbde } else { 29991738Sbde histcounter_type = gmonhdr.histcounter_type; 30091738Sbde histcounter_size = abs(histcounter_type) / CHAR_BIT; 30191738Sbde } 3021590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 3031590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 30491735Sbde lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2; 30591735Sbde highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2; 3061590Srgrimes sampbytes = gmonhdr.ncnt - size; 30791738Sbde nsamples = sampbytes / histcounter_size; 3081590Srgrimes# ifdef DEBUG 3091590Srgrimes if ( debug & SAMPLEDEBUG ) { 31091018Sbde printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n", 3111590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 31291018Sbde printf( "[openpfile] s_lowpc 0x%lx s_highpc 0x%lx\n" , 3131590Srgrimes s_lowpc , s_highpc ); 31491018Sbde printf( "[openpfile] lowpc 0x%lx highpc 0x%lx\n" , 3151590Srgrimes lowpc , highpc ); 3161590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 3171590Srgrimes sampbytes , nsamples ); 31891018Sbde printf( "[openpfile] sample rate %ld\n" , hz ); 3191590Srgrimes } 32097631Swollman# endif /* DEBUG */ 3211590Srgrimes return(pfile); 3221590Srgrimes} 3231590Srgrimes 324105243Scharniervoid 3251590Srgrimestally( rawp ) 3261590Srgrimes struct rawarc *rawp; 3271590Srgrimes{ 3281590Srgrimes nltype *parentp; 3291590Srgrimes nltype *childp; 3301590Srgrimes 3311590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 3321590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 3331590Srgrimes if ( parentp == 0 || childp == 0 ) 3341590Srgrimes return; 3351590Srgrimes if ( kflag 3361590Srgrimes && onlist( kfromlist , parentp -> name ) 3371590Srgrimes && onlist( ktolist , childp -> name ) ) { 3381590Srgrimes return; 3391590Srgrimes } 3401590Srgrimes childp -> ncall += rawp -> raw_count; 3411590Srgrimes# ifdef DEBUG 3421590Srgrimes if ( debug & TALLYDEBUG ) { 34391018Sbde printf( "[tally] arc from %s to %s traversed %ld times\n" , 3441590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 3451590Srgrimes } 34697631Swollman# endif /* DEBUG */ 3471590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 3481590Srgrimes} 3491590Srgrimes 3501590Srgrimes/* 3511590Srgrimes * dump out the gmon.sum file 3521590Srgrimes */ 353105243Scharniervoid 3541590Srgrimesdumpsum( sumfile ) 3551590Srgrimes char *sumfile; 3561590Srgrimes{ 3571590Srgrimes register nltype *nlp; 3581590Srgrimes register arctype *arcp; 3591590Srgrimes struct rawarc arc; 3601590Srgrimes FILE *sfile; 3611590Srgrimes 362105243Scharnier if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) 363105243Scharnier err( 1 , "%s" , sumfile ); 3641590Srgrimes /* 3651590Srgrimes * dump the header; use the last header read in 3661590Srgrimes */ 367105243Scharnier if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) 368105243Scharnier err( 1 , "%s" , sumfile ); 3691590Srgrimes /* 3701590Srgrimes * dump the samples 3711590Srgrimes */ 372105243Scharnier if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples) 373105243Scharnier err( 1 , "%s" , sumfile ); 3741590Srgrimes /* 3751590Srgrimes * dump the normalized raw arc information 3761590Srgrimes */ 3771590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 3781590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 3791590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 3801590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 3811590Srgrimes arc.raw_count = arcp -> arc_count; 382105243Scharnier if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) 383105243Scharnier err( 1 , "%s" , sumfile ); 3841590Srgrimes# ifdef DEBUG 3851590Srgrimes if ( debug & SAMPLEDEBUG ) { 38691018Sbde printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" , 3871590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3881590Srgrimes } 38997631Swollman# endif /* DEBUG */ 3901590Srgrimes } 3911590Srgrimes } 3921590Srgrimes fclose( sfile ); 3931590Srgrimes} 3941590Srgrimes 39538928Sjdpstatic int 39638928Sjdpvalcmp(v1, v2) 39738928Sjdp const void *v1; 39838928Sjdp const void *v2; 3991590Srgrimes{ 40038928Sjdp const nltype *p1 = (const nltype *)v1; 40138928Sjdp const nltype *p2 = (const nltype *)v2; 40238928Sjdp 4031590Srgrimes if ( p1 -> value < p2 -> value ) { 4041590Srgrimes return LESSTHAN; 4051590Srgrimes } 4061590Srgrimes if ( p1 -> value > p2 -> value ) { 4071590Srgrimes return GREATERTHAN; 4081590Srgrimes } 4091590Srgrimes return EQUALTO; 4101590Srgrimes} 4111590Srgrimes 412105243Scharniervoid 4131590Srgrimesreadsamples(pfile) 4141590Srgrimes FILE *pfile; 4151590Srgrimes{ 416131990Sstefanf int i; 41791738Sbde intmax_t sample; 4188874Srgrimes 4191590Srgrimes if (samples == 0) { 42091738Sbde samples = (double *) calloc(nsamples, sizeof(double)); 421105243Scharnier if (samples == 0) 422105243Scharnier errx(0, "no room for %d sample pc's", nsamples); 4231590Srgrimes } 4241590Srgrimes for (i = 0; i < nsamples; i++) { 42591738Sbde fread(&sample, histcounter_size, 1, pfile); 4261590Srgrimes if (feof(pfile)) 4271590Srgrimes break; 42891738Sbde switch ( histcounter_type ) { 42991738Sbde case -8: 43091738Sbde samples[i] += *(int8_t *)&sample; 43191738Sbde break; 43291738Sbde case 8: 43391738Sbde samples[i] += *(u_int8_t *)&sample; 43491738Sbde break; 43591738Sbde case -16: 43691738Sbde samples[i] += *(int16_t *)&sample; 43791738Sbde break; 43891738Sbde case 16: 43991738Sbde samples[i] += *(u_int16_t *)&sample; 44091738Sbde break; 44191738Sbde case -32: 44291738Sbde samples[i] += *(int32_t *)&sample; 44391738Sbde break; 44491738Sbde case 32: 44591738Sbde samples[i] += *(u_int32_t *)&sample; 44691738Sbde break; 44791738Sbde case -64: 44891738Sbde samples[i] += *(int64_t *)&sample; 44991738Sbde break; 45091738Sbde case 64: 45191738Sbde samples[i] += *(u_int64_t *)&sample; 45291738Sbde break; 45391738Sbde default: 45491738Sbde err(1, "unsupported histogram counter type %d", histcounter_type); 45591738Sbde } 4561590Srgrimes } 457105243Scharnier if (i != nsamples) 458105243Scharnier errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples ); 4591590Srgrimes} 4601590Srgrimes 4611590Srgrimes/* 4621590Srgrimes * Assign samples to the procedures to which they belong. 4631590Srgrimes * 4641590Srgrimes * There are three cases as to where pcl and pch can be 4651590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 4661590Srgrimes * as shown in the following diagram. overlap computes the 4671590Srgrimes * distance between the arrows, the fraction of the sample 4681590Srgrimes * that is to be credited to the routine which starts at svalue0. 4691590Srgrimes * 4701590Srgrimes * svalue0 svalue1 4711590Srgrimes * | | 4721590Srgrimes * v v 4731590Srgrimes * 4741590Srgrimes * +-----------------------------------------------+ 4751590Srgrimes * | | 4761590Srgrimes * | ->| |<- ->| |<- ->| |<- | 4771590Srgrimes * | | | | | | 4781590Srgrimes * +---------+ +---------+ +---------+ 4791590Srgrimes * 4801590Srgrimes * ^ ^ ^ ^ ^ ^ 4811590Srgrimes * | | | | | | 4821590Srgrimes * pcl pch pcl pch pcl pch 4831590Srgrimes * 4841590Srgrimes * For the vax we assert that samples will never fall in the first 4851590Srgrimes * two bytes of any routine, since that is the entry mask, 4861590Srgrimes * thus we give call alignentries() to adjust the entry points if 4871590Srgrimes * the entry mask falls in one bucket but the code for the routine 4881590Srgrimes * doesn't start until the next bucket. In conjunction with the 4891590Srgrimes * alignment of routine addresses, this should allow us to have 4901590Srgrimes * only one sample for every four bytes of text space and never 4911590Srgrimes * have any overlap (the two end cases, above). 4921590Srgrimes */ 493105243Scharniervoid 4941590Srgrimesasgnsamples() 4951590Srgrimes{ 4961590Srgrimes register int j; 49791738Sbde double ccnt; 4981590Srgrimes double time; 4991590Srgrimes unsigned long pcl, pch; 5001590Srgrimes register int i; 5011590Srgrimes unsigned long overlap; 5021590Srgrimes unsigned long svalue0, svalue1; 5031590Srgrimes 5041590Srgrimes /* read samples and assign to namelist symbols */ 5051590Srgrimes scale = highpc - lowpc; 5061590Srgrimes scale /= nsamples; 5071590Srgrimes alignentries(); 5081590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 5091590Srgrimes ccnt = samples[i]; 5101590Srgrimes if (ccnt == 0) 5111590Srgrimes continue; 51248839Ssimokawa pcl = lowpc + (unsigned long)(scale * i); 51348839Ssimokawa pch = lowpc + (unsigned long)(scale * (i + 1)); 5141590Srgrimes time = ccnt; 5151590Srgrimes# ifdef DEBUG 5161590Srgrimes if ( debug & SAMPLEDEBUG ) { 51791738Sbde printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" , 5181590Srgrimes pcl , pch , ccnt ); 5191590Srgrimes } 52097631Swollman# endif /* DEBUG */ 5211590Srgrimes totime += time; 5221590Srgrimes for (j = j - 1; j < nname; j++) { 5231590Srgrimes svalue0 = nl[j].svalue; 5241590Srgrimes svalue1 = nl[j+1].svalue; 5251590Srgrimes /* 5268874Srgrimes * if high end of tick is below entry address, 5271590Srgrimes * go for next tick. 5281590Srgrimes */ 5291590Srgrimes if (pch < svalue0) 5301590Srgrimes break; 5311590Srgrimes /* 5321590Srgrimes * if low end of tick into next routine, 5331590Srgrimes * go for next routine. 5341590Srgrimes */ 5351590Srgrimes if (pcl >= svalue1) 5361590Srgrimes continue; 5371590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 5381590Srgrimes if (overlap > 0) { 5391590Srgrimes# ifdef DEBUG 5401590Srgrimes if (debug & SAMPLEDEBUG) { 54191018Sbde printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n", 54291735Sbde nl[j].value / HISTORICAL_SCALE_2, 54391735Sbde svalue0, svalue1, nl[j].name, 5441590Srgrimes overlap * time / scale, overlap); 5451590Srgrimes } 54697631Swollman# endif /* DEBUG */ 5471590Srgrimes nl[j].time += overlap * time / scale; 5481590Srgrimes } 5491590Srgrimes } 5501590Srgrimes } 5511590Srgrimes# ifdef DEBUG 5521590Srgrimes if (debug & SAMPLEDEBUG) { 5531590Srgrimes printf("[asgnsamples] totime %f\n", totime); 5541590Srgrimes } 55597631Swollman# endif /* DEBUG */ 5561590Srgrimes} 5571590Srgrimes 5581590Srgrimes 5591590Srgrimesunsigned long 5601590Srgrimesmin(a, b) 5611590Srgrimes unsigned long a,b; 5621590Srgrimes{ 5631590Srgrimes if (a<b) 5641590Srgrimes return(a); 5651590Srgrimes return(b); 5661590Srgrimes} 5671590Srgrimes 5681590Srgrimesunsigned long 5691590Srgrimesmax(a, b) 5701590Srgrimes unsigned long a,b; 5711590Srgrimes{ 5721590Srgrimes if (a>b) 5731590Srgrimes return(a); 5741590Srgrimes return(b); 5751590Srgrimes} 5761590Srgrimes 5771590Srgrimes /* 5781590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 5791590Srgrimes * and possibly push the scaled entry points over the entry mask, 5801590Srgrimes * if it turns out that the entry point is in one bucket and the code 5811590Srgrimes * for a routine is in the next bucket. 5821590Srgrimes */ 583105243Scharniervoid 5841590Srgrimesalignentries() 5851590Srgrimes{ 5861590Srgrimes register struct nl *nlp; 5871590Srgrimes unsigned long bucket_of_entry; 5881590Srgrimes unsigned long bucket_of_code; 5891590Srgrimes 5901590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 59191735Sbde nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2; 5921590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 59391735Sbde bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 - 59491735Sbde lowpc) / scale; 5951590Srgrimes if (bucket_of_entry < bucket_of_code) { 5961590Srgrimes# ifdef DEBUG 5971590Srgrimes if (debug & SAMPLEDEBUG) { 59891018Sbde printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n", 59991735Sbde nlp->svalue, 60091735Sbde nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2); 6011590Srgrimes } 60297631Swollman# endif /* DEBUG */ 60391735Sbde nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2; 6041590Srgrimes } 6051590Srgrimes } 6061590Srgrimes} 607