gprof.c revision 187116
1191783Srmacklem/*
2191783Srmacklem * Copyright (c) 1983, 1993
3191783Srmacklem *	The Regents of the University of California.  All rights reserved.
4191783Srmacklem *
5191783Srmacklem * Redistribution and use in source and binary forms, with or without
6191783Srmacklem * modification, are permitted provided that the following conditions
7191783Srmacklem * are met:
8191783Srmacklem * 1. Redistributions of source code must retain the above copyright
9191783Srmacklem *    notice, this list of conditions and the following disclaimer.
10191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
11191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
12191783Srmacklem *    documentation and/or other materials provided with the distribution.
13191783Srmacklem * 3. All advertising materials mentioning features or use of this software
14191783Srmacklem *    must display the following acknowledgement:
15191783Srmacklem *	This product includes software developed by the University of
16191783Srmacklem *	California, Berkeley and its contributors.
17191783Srmacklem * 4. Neither the name of the University nor the names of its contributors
18191783Srmacklem *    may be used to endorse or promote products derived from this software
19191783Srmacklem *    without specific prior written permission.
20191783Srmacklem *
21191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24191783Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31191783Srmacklem * SUCH DAMAGE.
32191783Srmacklem */
33191783Srmacklem
34191783Srmacklem#ifndef lint
35191783Srmacklemstatic const char copyright[] =
36191783Srmacklem"@(#) Copyright (c) 1983, 1993\n\
37191783Srmacklem	The Regents of the University of California.  All rights reserved.\n";
38191783Srmacklem#endif /* not lint */
39191783Srmacklem
40191783Srmacklem#if 0
41191783Srmacklem#ifndef lint
42191783Srmacklemstatic char sccsid[] = "@(#)gprof.c	8.1 (Berkeley) 6/6/93";
43191783Srmacklem#endif /* not lint */
44191783Srmacklem#endif
45269398Srmacklem
46269398Srmacklem#include <sys/cdefs.h>
47191783Srmacklem__FBSDID("$FreeBSD: head/usr.bin/gprof/gprof.c 187116 2009-01-12 21:49:42Z obrien $");
48191783Srmacklem
49191783Srmacklem#include <err.h>
50191783Srmacklem#include <limits.h>
51191783Srmacklem#include <stdint.h>
52191783Srmacklem#include <string.h>
53191783Srmacklem
54191783Srmacklem#include "gprof.h"
55191783Srmacklem
56191783Srmacklemstatic int valcmp(const void *, const void *);
57191783Srmacklem
58191783Srmacklem
59191783Srmacklemstatic struct gmonhdr	gmonhdr;
60191783Srmacklemstatic int lflag;
61191783Srmacklemstatic int Lflag;
62191783Srmacklem
63191783Srmacklemint
64191783Srmacklemmain(argc, argv)
65191783Srmacklem    int argc;
66191783Srmacklem    char **argv;
67191783Srmacklem{
68191783Srmacklem    char	**sp;
69269398Srmacklem    nltype	**timesortnlp;
70269398Srmacklem    char	**defaultEs;
71269398Srmacklem
72269398Srmacklem    --argc;
73269398Srmacklem    argv++;
74269398Srmacklem    debug = 0;
75269398Srmacklem    bflag = TRUE;
76191783Srmacklem    while ( *argv != 0 && **argv == '-' ) {
77191783Srmacklem	(*argv)++;
78191783Srmacklem	switch ( **argv ) {
79191783Srmacklem	case 'a':
80191783Srmacklem	    aflag = TRUE;
81191783Srmacklem	    break;
82191783Srmacklem	case 'b':
83191783Srmacklem	    bflag = FALSE;
84191783Srmacklem	    break;
85191783Srmacklem	case 'C':
86191783Srmacklem	    Cflag = TRUE;
87191783Srmacklem	    cyclethreshold = atoi( *++argv );
88269398Srmacklem	    break;
89191783Srmacklem	case 'd':
90191783Srmacklem	    dflag = TRUE;
91191783Srmacklem	    setlinebuf(stdout);
92191783Srmacklem	    debug |= atoi( *++argv );
93191783Srmacklem	    debug |= ANYDEBUG;
94191783Srmacklem#	    ifdef DEBUG
95191783Srmacklem		printf("[main] debug = %d\n", debug);
96191783Srmacklem#	    else /* not DEBUG */
97191783Srmacklem		printf("gprof: -d ignored\n");
98191783Srmacklem#	    endif /* DEBUG */
99191783Srmacklem	    break;
100191783Srmacklem	case 'E':
101191783Srmacklem	    ++argv;
102191783Srmacklem	    addlist( Elist , *argv );
103191783Srmacklem	    Eflag = TRUE;
104191783Srmacklem	    addlist( elist , *argv );
105191783Srmacklem	    eflag = TRUE;
106191783Srmacklem	    break;
107191783Srmacklem	case 'e':
108191783Srmacklem	    addlist( elist , *++argv );
109191783Srmacklem	    eflag = TRUE;
110191783Srmacklem	    break;
111191783Srmacklem	case 'F':
112191783Srmacklem	    ++argv;
113191783Srmacklem	    addlist( Flist , *argv );
114269398Srmacklem	    Fflag = TRUE;
115269398Srmacklem	    addlist( flist , *argv );
116269398Srmacklem	    fflag = TRUE;
117269398Srmacklem	    break;
118269398Srmacklem	case 'f':
119269398Srmacklem	    addlist( flist , *++argv );
120269398Srmacklem	    fflag = TRUE;
121269398Srmacklem	    break;
122269398Srmacklem	case 'k':
123269398Srmacklem	    addlist( kfromlist , *++argv );
124269398Srmacklem	    addlist( ktolist , *++argv );
125269398Srmacklem	    kflag = TRUE;
126269398Srmacklem	    break;
127269398Srmacklem	case 'K':
128269398Srmacklem	    Kflag = TRUE;
129269398Srmacklem	    break;
130269398Srmacklem	case 'l':
131269398Srmacklem	    lflag = 1;
132269398Srmacklem	    Lflag = 0;
133269398Srmacklem	    break;
134269398Srmacklem	case 'L':
135269398Srmacklem	    Lflag = 1;
136269398Srmacklem	    lflag = 0;
137269398Srmacklem	    break;
138269398Srmacklem	case 's':
139269398Srmacklem	    sflag = TRUE;
140269398Srmacklem	    break;
141269398Srmacklem	case 'u':
142269398Srmacklem	    uflag = TRUE;
143269398Srmacklem	    break;
144269398Srmacklem	case 'z':
145269398Srmacklem	    zflag = TRUE;
146269398Srmacklem	    break;
147269398Srmacklem	}
148269398Srmacklem	argv++;
149269398Srmacklem    }
150269398Srmacklem    if ( *argv != 0 ) {
151191783Srmacklem	a_outname  = *argv;
152191783Srmacklem	argv++;
153191783Srmacklem    } else {
154191783Srmacklem	a_outname  = A_OUTNAME;
155191783Srmacklem    }
156191783Srmacklem    if ( *argv != 0 ) {
157191783Srmacklem	gmonname = *argv;
158191783Srmacklem	argv++;
159191783Srmacklem    } else {
160191783Srmacklem	gmonname = (char *) malloc(strlen(a_outname)+6);
161191783Srmacklem	strcpy(gmonname, a_outname);
162191783Srmacklem	strcat(gmonname, ".gmon");
163191783Srmacklem    }
164191783Srmacklem	/*
165191783Srmacklem	 *	get information from the executable file.
166191783Srmacklem	 */
167191783Srmacklem    if ((Kflag && kernel_getnfile(a_outname, &defaultEs) == -1) ||
168191783Srmacklem      (!Kflag && elf_getnfile(a_outname, &defaultEs) == -1 &&
169191783Srmacklem      aout_getnfile(a_outname, &defaultEs) == -1))
170191783Srmacklem	errx(1, "%s: bad format", a_outname);
171191783Srmacklem	/*
172191783Srmacklem	 *	sort symbol table.
173191783Srmacklem	 */
174191783Srmacklem    qsort(nl, nname, sizeof(nltype), valcmp);
175191783Srmacklem	/*
176191783Srmacklem	 *	turn off default functions
177191783Srmacklem	 */
178191783Srmacklem    for ( sp = defaultEs ; *sp ; sp++ ) {
179191783Srmacklem	Eflag = TRUE;
180191783Srmacklem	addlist( Elist , *sp );
181191783Srmacklem	eflag = TRUE;
182191783Srmacklem	addlist( elist , *sp );
183191783Srmacklem    }
184191783Srmacklem	/*
185191783Srmacklem	 *	get information about mon.out file(s).
186191783Srmacklem	 */
187191783Srmacklem    do	{
188191783Srmacklem	getpfile( gmonname );
189191783Srmacklem	if ( *argv != 0 ) {
190191783Srmacklem	    gmonname = *argv;
191191783Srmacklem	}
192191783Srmacklem    } while ( *argv++ != 0 );
193191783Srmacklem	/*
194191783Srmacklem	 *	how many ticks per second?
195191783Srmacklem	 *	if we can't tell, report time in ticks.
196191783Srmacklem	 */
197191783Srmacklem    if (hz == 0) {
198191783Srmacklem	hz = 1;
199191783Srmacklem	fprintf(stderr, "time is in ticks, not seconds\n");
200191783Srmacklem    }
201191783Srmacklem	/*
202191783Srmacklem	 *	dump out a gmon.sum file if requested
203191783Srmacklem	 */
204191783Srmacklem    if ( sflag ) {
205191783Srmacklem	dumpsum( GMONSUM );
206191783Srmacklem    }
207191783Srmacklem	/*
208191783Srmacklem	 *	assign samples to procedures
209191783Srmacklem	 */
210191783Srmacklem    asgnsamples();
211191783Srmacklem	/*
212191783Srmacklem	 *	assemble the dynamic profile
213191783Srmacklem	 */
214191783Srmacklem    timesortnlp = doarcs();
215191783Srmacklem	/*
216191783Srmacklem	 *	print the dynamic profile
217191783Srmacklem	 */
218191783Srmacklem    if(!lflag) {
219191783Srmacklem	    printgprof( timesortnlp );
220191783Srmacklem    }
221191783Srmacklem	/*
222191783Srmacklem	 *	print the flat profile
223191783Srmacklem	 */
224191783Srmacklem    if(!Lflag) {
225191783Srmacklem	    printprof();
226191783Srmacklem    }
227191783Srmacklem	/*
228191783Srmacklem	 *	print the index
229191783Srmacklem	 */
230191783Srmacklem    printindex();
231191783Srmacklem    exit(0);
232191783Srmacklem}
233191783Srmacklem
234191783Srmacklem    /*
235205941Srmacklem     *	information from a gmon.out file is in two parts:
236205941Srmacklem     *	an array of sampling hits within pc ranges,
237205941Srmacklem     *	and the arcs.
238205941Srmacklem     */
239205941Srmacklemvoid
240205941Srmacklemgetpfile(filename)
241205941Srmacklem    char *filename;
242205941Srmacklem{
243205941Srmacklem    FILE		*pfile;
244205941Srmacklem    FILE		*openpfile();
245205941Srmacklem    struct rawarc	arc;
246191783Srmacklem
247191783Srmacklem    pfile = openpfile(filename);
248191783Srmacklem    readsamples(pfile);
249191783Srmacklem	/*
250191783Srmacklem	 *	the rest of the file consists of
251191783Srmacklem	 *	a bunch of <from,self,count> tuples.
252191783Srmacklem	 */
253191783Srmacklem    while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
254205941Srmacklem#	ifdef DEBUG
255205941Srmacklem	    if ( debug & SAMPLEDEBUG ) {
256191783Srmacklem		printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" ,
257191783Srmacklem			arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
258205941Srmacklem	    }
259205941Srmacklem#	endif /* DEBUG */
260191783Srmacklem	    /*
261191783Srmacklem	     *	add this arc
262191783Srmacklem	     */
263191783Srmacklem	tally( &arc );
264191783Srmacklem    }
265191783Srmacklem    fclose(pfile);
266191783Srmacklem}
267191783Srmacklem
268191783SrmacklemFILE *
269191783Srmacklemopenpfile(filename)
270191783Srmacklem    char *filename;
271191783Srmacklem{
272191783Srmacklem    struct gmonhdr	tmp;
273191783Srmacklem    FILE		*pfile;
274191783Srmacklem    int			size;
275191783Srmacklem    int			rate;
276191783Srmacklem
277191783Srmacklem    if((pfile = fopen(filename, "r")) == NULL)
278191783Srmacklem	err(1, "%s", filename);
279191783Srmacklem    fread(&tmp, sizeof(struct gmonhdr), 1, pfile);
280191783Srmacklem    if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc ||
281191783Srmacklem	 tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) )
282191783Srmacklem	errx(1, "%s: incompatible with first gmon file", filename);
283191783Srmacklem    gmonhdr = tmp;
284191783Srmacklem    if ( gmonhdr.version == GMONVERSION ) {
285191783Srmacklem	rate = gmonhdr.profrate;
286191783Srmacklem	size = sizeof(struct gmonhdr);
287191783Srmacklem    } else {
288191783Srmacklem	fseek(pfile, sizeof(struct ophdr), SEEK_SET);
289191783Srmacklem	size = sizeof(struct ophdr);
290191783Srmacklem	gmonhdr.profrate = rate = hertz();
291191783Srmacklem	gmonhdr.version = GMONVERSION;
292191783Srmacklem    }
293191783Srmacklem    if (hz == 0) {
294191783Srmacklem	hz = rate;
295191783Srmacklem    } else if (hz != rate)
296191783Srmacklem	errx(0, "%s: profile clock rate (%d) %s (%ld) in first gmon file",
297191783Srmacklem	    filename, rate, "incompatible with clock rate", hz);
298    if ( gmonhdr.histcounter_type == 0 ) {
299	/* Historical case.  The type was u_short (2 bytes in practice). */
300	histcounter_type = 16;
301	histcounter_size = 2;
302    } else {
303	histcounter_type = gmonhdr.histcounter_type;
304	histcounter_size = abs(histcounter_type) / CHAR_BIT;
305    }
306    s_lowpc = (unsigned long) gmonhdr.lpc;
307    s_highpc = (unsigned long) gmonhdr.hpc;
308    lowpc = (unsigned long)gmonhdr.lpc / HISTORICAL_SCALE_2;
309    highpc = (unsigned long)gmonhdr.hpc / HISTORICAL_SCALE_2;
310    sampbytes = gmonhdr.ncnt - size;
311    nsamples = sampbytes / histcounter_size;
312#   ifdef DEBUG
313	if ( debug & SAMPLEDEBUG ) {
314	    printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n",
315		gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt );
316	    printf( "[openpfile]   s_lowpc 0x%lx   s_highpc 0x%lx\n" ,
317		s_lowpc , s_highpc );
318	    printf( "[openpfile]     lowpc 0x%lx     highpc 0x%lx\n" ,
319		lowpc , highpc );
320	    printf( "[openpfile] sampbytes %d nsamples %d\n" ,
321		sampbytes , nsamples );
322	    printf( "[openpfile] sample rate %ld\n" , hz );
323	}
324#   endif /* DEBUG */
325    return(pfile);
326}
327
328void
329tally( rawp )
330    struct rawarc	*rawp;
331{
332    nltype		*parentp;
333    nltype		*childp;
334
335    parentp = nllookup( rawp -> raw_frompc );
336    childp = nllookup( rawp -> raw_selfpc );
337    if ( parentp == 0 || childp == 0 )
338	return;
339    if ( kflag
340	 && onlist( kfromlist , parentp -> name )
341	 && onlist( ktolist , childp -> name ) ) {
342	return;
343    }
344    childp -> ncall += rawp -> raw_count;
345#   ifdef DEBUG
346	if ( debug & TALLYDEBUG ) {
347	    printf( "[tally] arc from %s to %s traversed %ld times\n" ,
348		    parentp -> name , childp -> name , rawp -> raw_count );
349	}
350#   endif /* DEBUG */
351    addarc( parentp , childp , rawp -> raw_count );
352}
353
354/*
355 * dump out the gmon.sum file
356 */
357void
358dumpsum( sumfile )
359    char *sumfile;
360{
361    register nltype *nlp;
362    register arctype *arcp;
363    struct rawarc arc;
364    FILE *sfile;
365
366    if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL )
367	err( 1 , "%s" , sumfile );
368    /*
369     * dump the header; use the last header read in
370     */
371    if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 )
372	err( 1 , "%s" , sumfile );
373    /*
374     * dump the samples
375     */
376    if (fwrite(samples, histcounter_size, nsamples, sfile) != nsamples)
377	err( 1 , "%s" , sumfile );
378    /*
379     * dump the normalized raw arc information
380     */
381    for ( nlp = nl ; nlp < npe ; nlp++ ) {
382	for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
383	    arc.raw_frompc = arcp -> arc_parentp -> value;
384	    arc.raw_selfpc = arcp -> arc_childp -> value;
385	    arc.raw_count = arcp -> arc_count;
386	    if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 )
387		err( 1 , "%s" , sumfile );
388#	    ifdef DEBUG
389		if ( debug & SAMPLEDEBUG ) {
390		    printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" ,
391			    arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
392		}
393#	    endif /* DEBUG */
394	}
395    }
396    fclose( sfile );
397}
398
399static int
400valcmp(v1, v2)
401    const void *v1;
402    const void *v2;
403{
404    const nltype *p1 = (const nltype *)v1;
405    const nltype *p2 = (const nltype *)v2;
406
407    if ( p1 -> value < p2 -> value ) {
408	return LESSTHAN;
409    }
410    if ( p1 -> value > p2 -> value ) {
411	return GREATERTHAN;
412    }
413    return EQUALTO;
414}
415
416void
417readsamples(pfile)
418    FILE	*pfile;
419{
420    int		i;
421    intmax_t	sample;
422
423    if (samples == 0) {
424	samples = (double *) calloc(nsamples, sizeof(double));
425	if (samples == 0)
426	    errx(0, "no room for %d sample pc's", nsamples);
427    }
428    for (i = 0; i < nsamples; i++) {
429	fread(&sample, histcounter_size, 1, pfile);
430	if (feof(pfile))
431		break;
432	switch ( histcounter_type ) {
433	case -8:
434	    samples[i] += *(int8_t *)&sample;
435	    break;
436	case 8:
437	    samples[i] += *(u_int8_t *)&sample;
438	    break;
439	case -16:
440	    samples[i] += *(int16_t *)&sample;
441	    break;
442	case 16:
443	    samples[i] += *(u_int16_t *)&sample;
444	    break;
445	case -32:
446	    samples[i] += *(int32_t *)&sample;
447	    break;
448	case 32:
449	    samples[i] += *(u_int32_t *)&sample;
450	    break;
451	case -64:
452	    samples[i] += *(int64_t *)&sample;
453	    break;
454	case 64:
455	    samples[i] += *(u_int64_t *)&sample;
456	    break;
457	default:
458	    err(1, "unsupported histogram counter type %d", histcounter_type);
459	}
460    }
461    if (i != nsamples)
462	errx(1, "unexpected EOF after reading %d/%d samples", --i , nsamples );
463}
464
465/*
466 *	Assign samples to the procedures to which they belong.
467 *
468 *	There are three cases as to where pcl and pch can be
469 *	with respect to the routine entry addresses svalue0 and svalue1
470 *	as shown in the following diagram.  overlap computes the
471 *	distance between the arrows, the fraction of the sample
472 *	that is to be credited to the routine which starts at svalue0.
473 *
474 *	    svalue0                                         svalue1
475 *	       |                                               |
476 *	       v                                               v
477 *
478 *	       +-----------------------------------------------+
479 *	       |					       |
480 *	  |  ->|    |<-		->|         |<-		->|    |<-  |
481 *	  |         |		  |         |		  |         |
482 *	  +---------+		  +---------+		  +---------+
483 *
484 *	  ^         ^		  ^         ^		  ^         ^
485 *	  |         |		  |         |		  |         |
486 *	 pcl       pch		 pcl       pch		 pcl       pch
487 *
488 *	For the vax we assert that samples will never fall in the first
489 *	two bytes of any routine, since that is the entry mask,
490 *	thus we give call alignentries() to adjust the entry points if
491 *	the entry mask falls in one bucket but the code for the routine
492 *	doesn't start until the next bucket.  In conjunction with the
493 *	alignment of routine addresses, this should allow us to have
494 *	only one sample for every four bytes of text space and never
495 *	have any overlap (the two end cases, above).
496 */
497void
498asgnsamples()
499{
500    register int	j;
501    double		ccnt;
502    double		time;
503    unsigned long	pcl, pch;
504    register int	i;
505    unsigned long	overlap;
506    unsigned long	svalue0, svalue1;
507
508    /* read samples and assign to namelist symbols */
509    scale = highpc - lowpc;
510    scale /= nsamples;
511    alignentries();
512    for (i = 0, j = 1; i < nsamples; i++) {
513	ccnt = samples[i];
514	if (ccnt == 0)
515		continue;
516	pcl = lowpc + (unsigned long)(scale * i);
517	pch = lowpc + (unsigned long)(scale * (i + 1));
518	time = ccnt;
519#	ifdef DEBUG
520	    if ( debug & SAMPLEDEBUG ) {
521		printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %.0f\n" ,
522			pcl , pch , ccnt );
523	    }
524#	endif /* DEBUG */
525	totime += time;
526	for (j = j - 1; j < nname; j++) {
527	    svalue0 = nl[j].svalue;
528	    svalue1 = nl[j+1].svalue;
529		/*
530		 *	if high end of tick is below entry address,
531		 *	go for next tick.
532		 */
533	    if (pch < svalue0)
534		    break;
535		/*
536		 *	if low end of tick into next routine,
537		 *	go for next routine.
538		 */
539	    if (pcl >= svalue1)
540		    continue;
541	    overlap = min(pch, svalue1) - max(pcl, svalue0);
542	    if (overlap > 0) {
543#		ifdef DEBUG
544		    if (debug & SAMPLEDEBUG) {
545			printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %lu overlap\n",
546				nl[j].value / HISTORICAL_SCALE_2,
547				svalue0, svalue1, nl[j].name,
548				overlap * time / scale, overlap);
549		    }
550#		endif /* DEBUG */
551		nl[j].time += overlap * time / scale;
552	    }
553	}
554    }
555#   ifdef DEBUG
556	if (debug & SAMPLEDEBUG) {
557	    printf("[asgnsamples] totime %f\n", totime);
558	}
559#   endif /* DEBUG */
560}
561
562
563unsigned long
564min(a, b)
565    unsigned long a,b;
566{
567    if (a<b)
568	return(a);
569    return(b);
570}
571
572unsigned long
573max(a, b)
574    unsigned long a,b;
575{
576    if (a>b)
577	return(a);
578    return(b);
579}
580
581    /*
582     *	calculate scaled entry point addresses (to save time in asgnsamples),
583     *	and possibly push the scaled entry points over the entry mask,
584     *	if it turns out that the entry point is in one bucket and the code
585     *	for a routine is in the next bucket.
586     */
587void
588alignentries()
589{
590    register struct nl	*nlp;
591    unsigned long	bucket_of_entry;
592    unsigned long	bucket_of_code;
593
594    for (nlp = nl; nlp < npe; nlp++) {
595	nlp -> svalue = nlp -> value / HISTORICAL_SCALE_2;
596	bucket_of_entry = (nlp->svalue - lowpc) / scale;
597	bucket_of_code = (nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2 -
598	  lowpc) / scale;
599	if (bucket_of_entry < bucket_of_code) {
600#	    ifdef DEBUG
601		if (debug & SAMPLEDEBUG) {
602		    printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n",
603			    nlp->svalue,
604			    nlp->svalue + OFFSET_OF_CODE / HISTORICAL_SCALE_2);
605		}
606#	    endif /* DEBUG */
607	    nlp->svalue += OFFSET_OF_CODE / HISTORICAL_SCALE_2;
608	}
609    }
610}
611