xref: /csrg-svn/usr.bin/gprof/gprof.c (revision 21960)
1*21960Sdist /*
2*21960Sdist  * Copyright (c) 1983 Regents of the University of California.
3*21960Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21960Sdist  * specifies the terms and conditions for redistribution.
5*21960Sdist  */
6*21960Sdist 
74510Speter #ifndef lint
8*21960Sdist char copyright[] =
9*21960Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10*21960Sdist  All rights reserved.\n";
11*21960Sdist #endif not lint
124510Speter 
13*21960Sdist #ifndef lint
14*21960Sdist static char sccsid[] = "@(#)gprof.c	5.1 (Berkeley) 06/04/85";
15*21960Sdist #endif not lint
16*21960Sdist 
174563Speter #include "gprof.h"
184510Speter 
197128Speter char	*whoami = "gprof";
207128Speter 
217223Speter     /*
227223Speter      *	things which get -E excluded by default.
237223Speter      */
247223Speter char	*defaultEs[] = { "mcount" , "__mcleanup" , 0 };
257173Speter 
264510Speter main(argc, argv)
277173Speter     int argc;
287173Speter     char **argv;
294510Speter {
307173Speter     char	**sp;
3116852Smckusick     nltype	**timesortnlp;
324510Speter 
334510Speter     --argc;
344510Speter     argv++;
354510Speter     debug = 0;
3612385Smckusick     bflag = TRUE;
374510Speter     while ( *argv != 0 && **argv == '-' ) {
384510Speter 	(*argv)++;
394866Smckusic 	switch ( **argv ) {
407173Speter 	case 'a':
417173Speter 	    aflag = TRUE;
427173Speter 	    break;
437173Speter 	case 'b':
4412385Smckusick 	    bflag = FALSE;
457173Speter 	    break;
467173Speter 	case 'c':
477173Speter 	    cflag = TRUE;
487173Speter 	    break;
494866Smckusic 	case 'd':
507173Speter 	    dflag = TRUE;
514510Speter 	    (*argv)++;
524510Speter 	    debug |= atoi( *argv );
534510Speter 	    debug |= ANYDEBUG;
544510Speter #	    ifdef DEBUG
5511807Smckusick 		printf("[main] debug = %d\n", debug);
5611807Smckusick #	    else not DEBUG
5711807Smckusick 		printf("%s: -d ignored\n", whoami);
584510Speter #	    endif DEBUG
594866Smckusic 	    break;
607223Speter 	case 'E':
617223Speter 	    ++argv;
627223Speter 	    addlist( Elist , *argv );
637223Speter 	    Eflag = TRUE;
647223Speter 	    addlist( elist , *argv );
657223Speter 	    eflag = TRUE;
667223Speter 	    break;
677173Speter 	case 'e':
687223Speter 	    addlist( elist , *++argv );
697173Speter 	    eflag = TRUE;
704866Smckusic 	    break;
717223Speter 	case 'F':
727223Speter 	    ++argv;
737223Speter 	    addlist( Flist , *argv );
747223Speter 	    Fflag = TRUE;
757223Speter 	    addlist( flist , *argv );
767223Speter 	    fflag = TRUE;
777223Speter 	    break;
787173Speter 	case 'f':
797223Speter 	    addlist( flist , *++argv );
807173Speter 	    fflag = TRUE;
814866Smckusic 	    break;
824866Smckusic 	case 's':
837173Speter 	    sflag = TRUE;
844866Smckusic 	    break;
854866Smckusic 	case 'z':
867173Speter 	    zflag = TRUE;
874866Smckusic 	    break;
884510Speter 	}
894510Speter 	argv++;
904510Speter     }
914510Speter     if ( *argv != 0 ) {
924510Speter 	a_outname  = *argv;
934510Speter 	argv++;
944510Speter     } else {
954510Speter 	a_outname  = A_OUTNAME;
964510Speter     }
974510Speter     if ( *argv != 0 ) {
984563Speter 	gmonname = *argv;
994510Speter 	argv++;
1004510Speter     } else {
1014563Speter 	gmonname = GMONNAME;
1024510Speter     }
1034510Speter 	/*
1047173Speter 	 *	turn off default functions
1057173Speter 	 */
1067223Speter     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
1077223Speter 	Eflag = TRUE;
1087223Speter 	addlist( Elist , *sp );
1097173Speter 	eflag = TRUE;
1107223Speter 	addlist( elist , *sp );
1117173Speter     }
1127173Speter 	/*
11315910Speter 	 *	how many ticks per second?
11415910Speter 	 *	if we can't tell, report time in ticks.
11510249Speter 	 */
11610249Speter     hz = hertz();
11715910Speter     if (hz == 0) {
11815910Speter 	hz = 1;
11915910Speter 	fprintf(stderr, "time is in ticks, not seconds\n");
12015910Speter     }
12110249Speter 	/*
1224510Speter 	 *	get information about a.out file.
1234510Speter 	 */
1244510Speter     getnfile();
1254510Speter 	/*
1264510Speter 	 *	get information about mon.out file(s).
1274510Speter 	 */
1284866Smckusic     do	{
1294866Smckusic 	getpfile( gmonname );
1304866Smckusic 	if ( *argv != 0 ) {
1314866Smckusic 	    gmonname = *argv;
1324866Smckusic 	}
1337128Speter     } while ( *argv++ != 0 );
1344510Speter 	/*
1354866Smckusic 	 *	dump out a gmon.sum file if requested
1364866Smckusic 	 */
1377128Speter     if ( sflag ) {
1387128Speter 	dumpsum( GMONSUM );
1397128Speter     }
1404866Smckusic 	/*
1414510Speter 	 *	assign samples to procedures
1424510Speter 	 */
1434510Speter     asgnsamples();
1444510Speter 	/*
14516852Smckusick 	 *	assemble the dynamic profile
1464510Speter 	 */
14716852Smckusick     timesortnlp = doarcs();
14816852Smckusick 	/*
14916852Smckusick 	 *	print the dynamic profile
15016852Smckusick 	 */
15116852Smckusick     printgprof( timesortnlp );
15216852Smckusick 	/*
15316852Smckusick 	 *	print the flat profile
15416852Smckusick 	 */
1554510Speter     printprof();
1564510Speter 	/*
15716852Smckusick 	 *	print the index
1584510Speter 	 */
15916852Smckusick     printindex();
1604510Speter     done();
1614510Speter }
1624510Speter 
1637128Speter     /*
1647128Speter      * Set up string and symbol tables from a.out.
1657128Speter      *	and optionally the text space.
1667128Speter      * On return symbol table is sorted by value.
1677128Speter      */
1684510Speter getnfile()
1694510Speter {
1704510Speter     FILE	*nfile;
1714510Speter 
1724510Speter     nfile = fopen( a_outname ,"r");
1734510Speter     if (nfile == NULL) {
1744510Speter 	perror( a_outname );
1754510Speter 	done();
1764510Speter     }
1774510Speter     fread(&xbuf, 1, sizeof(xbuf), nfile);
1784510Speter     if (N_BADMAG(xbuf)) {
1797128Speter 	fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
1804510Speter 	done();
1814510Speter     }
1824510Speter     getstrtab(nfile);
1834510Speter     getsymtab(nfile);
1844720Speter     gettextspace( nfile );
1854510Speter     qsort(nl, nname, sizeof(nltype), valcmp);
1864510Speter     fclose(nfile);
1874510Speter #   ifdef DEBUG
1884510Speter 	if ( debug & AOUTDEBUG ) {
1894510Speter 	    register int j;
1904510Speter 
1914510Speter 	    for (j = 0; j < nname; j++){
1924510Speter 		printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
1934510Speter 	    }
1944510Speter 	}
1954510Speter #   endif DEBUG
1964510Speter }
1974510Speter 
1984510Speter getstrtab(nfile)
1994510Speter     FILE	*nfile;
2004510Speter {
2014510Speter 
2024510Speter     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
2034510Speter     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
2047128Speter 	fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
2057128Speter 		whoami , a_outname );
2064510Speter 	done();
2074510Speter     }
2084510Speter     strtab = (char *)calloc(ssiz, 1);
2094510Speter     if (strtab == NULL) {
2107128Speter 	fprintf(stderr, "%s: %s: no room for %d bytes of string table",
2117128Speter 		whoami , a_outname , ssiz);
2124510Speter 	done();
2134510Speter     }
2144510Speter     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
2157128Speter 	fprintf(stderr, "%s: %s: error reading string table\n",
2167128Speter 		whoami , a_outname );
2174510Speter 	done();
2184510Speter     }
2194510Speter }
2204510Speter 
2214510Speter     /*
2224510Speter      * Read in symbol table
2234510Speter      */
2244510Speter getsymtab(nfile)
2254510Speter     FILE	*nfile;
2264510Speter {
2274510Speter     register long	i;
2284510Speter     int			askfor;
2294510Speter     struct nlist	nbuf;
2304510Speter 
2314510Speter     /* pass1 - count symbols */
2324510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
2334510Speter     nname = 0;
2344510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2354510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
2364845Speter 	if ( ! funcsymbol( &nbuf ) ) {
2374510Speter 	    continue;
2384510Speter 	}
2394510Speter 	nname++;
2404510Speter     }
2414510Speter     if (nname == 0) {
2427128Speter 	fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
2434510Speter 	done();
2444510Speter     }
2457128Speter     askfor = nname + 1;
2464510Speter     nl = (nltype *) calloc( askfor , sizeof(nltype) );
2474510Speter     if (nl == 0) {
2487128Speter 	fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
2497128Speter 		whoami, askfor * sizeof(nltype) );
2504510Speter 	done();
2514510Speter     }
2524510Speter 
2534510Speter     /* pass2 - read symbols */
2544510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
2554510Speter     npe = nl;
2564510Speter     nname = 0;
2574510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2584510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
2594845Speter 	if ( ! funcsymbol( &nbuf ) ) {
2604845Speter #	    ifdef DEBUG
2614845Speter 		if ( debug & AOUTDEBUG ) {
2624845Speter 		    printf( "[getsymtab] rejecting: 0x%x %s\n" ,
2634845Speter 			    nbuf.n_type , strtab + nbuf.n_un.n_strx );
2644845Speter 		}
2654845Speter #	    endif DEBUG
2664510Speter 	    continue;
2674510Speter 	}
2684510Speter 	npe->value = nbuf.n_value;
2694510Speter 	npe->name = strtab+nbuf.n_un.n_strx;
2704510Speter #	ifdef DEBUG
2714510Speter 	    if ( debug & AOUTDEBUG ) {
2724510Speter 		printf( "[getsymtab] %d %s 0x%08x\n" ,
2734510Speter 			nname , npe -> name , npe -> value );
2744510Speter 	    }
2754510Speter #	endif DEBUG
2764510Speter 	npe++;
2774510Speter 	nname++;
2784510Speter     }
2794510Speter     npe->value = -1;
2804510Speter }
2814510Speter 
2824510Speter     /*
2834720Speter      *	read in the text space of an a.out file
2844720Speter      */
2854720Speter gettextspace( nfile )
2864720Speter     FILE	*nfile;
2874720Speter {
2884720Speter     unsigned char	*malloc();
2894720Speter 
2904720Speter     if ( cflag == 0 ) {
2914720Speter 	return;
2924720Speter     }
2934720Speter     textspace = malloc( xbuf.a_text );
2944720Speter     if ( textspace == 0 ) {
2957128Speter 	fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
2967128Speter 			whoami , xbuf.a_text );
2977128Speter 	fprintf( stderr , "can't do -c\n" );
2984720Speter 	return;
2994720Speter     }
3004720Speter     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
3014720Speter     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
3027128Speter 	fprintf( stderr , "%s: couldn't read text space:  " , whoami );
3037128Speter 	fprintf( stderr , "can't do -c\n" );
3044720Speter 	free( textspace );
3054720Speter 	textspace = 0;
3064720Speter 	return;
3074720Speter     }
3084720Speter }
3094720Speter     /*
3104563Speter      *	information from a gmon.out file is in two parts:
3114510Speter      *	an array of sampling hits within pc ranges,
3124510Speter      *	and the arcs.
3134510Speter      */
3144510Speter getpfile(filename)
3154510Speter     char *filename;
3164510Speter {
3174510Speter     FILE		*pfile;
3184510Speter     FILE		*openpfile();
3194510Speter     struct rawarc	arc;
3204510Speter 
3214510Speter     pfile = openpfile(filename);
3224510Speter     readsamples(pfile);
3234510Speter 	/*
3244510Speter 	 *	the rest of the file consists of
3254510Speter 	 *	a bunch of <from,self,count> tuples.
3264510Speter 	 */
3274510Speter     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
3284510Speter #	ifdef DEBUG
3294510Speter 	    if ( debug & SAMPLEDEBUG ) {
3304752Speter 		printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
3314510Speter 			arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
3324510Speter 	    }
3334510Speter #	endif DEBUG
3344510Speter 	    /*
3354510Speter 	     *	add this arc
3364510Speter 	     */
3374510Speter 	tally( &arc );
3384510Speter     }
3394510Speter     fclose(pfile);
3404510Speter }
3414510Speter 
3424841Speter FILE *
3434841Speter openpfile(filename)
3444510Speter     char *filename;
3454510Speter {
3464866Smckusic     struct hdr	tmp;
3474510Speter     FILE	*pfile;
3484510Speter 
3494510Speter     if((pfile = fopen(filename, "r")) == NULL) {
3504510Speter 	perror(filename);
3514510Speter 	done();
3524510Speter     }
3534866Smckusic     fread(&tmp, sizeof(struct hdr), 1, pfile);
3544866Smckusic     if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
3554866Smckusic 	 tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
3564866Smckusic 	fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
3574866Smckusic 	done();
3584866Smckusic     }
3594866Smckusic     h = tmp;
3604752Speter     s_lowpc = (unsigned long) h.lowpc;
3614752Speter     s_highpc = (unsigned long) h.highpc;
3627227Smckusick     lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
3637227Smckusick     highpc = (unsigned long)h.highpc / sizeof(UNIT);
3644510Speter     sampbytes = h.ncnt - sizeof(struct hdr);
3654510Speter     nsamples = sampbytes / sizeof (unsigned UNIT);
3667226Speter #   ifdef DEBUG
3677226Speter 	if ( debug & SAMPLEDEBUG ) {
3687226Speter 	    printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
3697226Speter 		h.lowpc , h.highpc , h.ncnt );
3707226Speter 	    printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
3717226Speter 		s_lowpc , s_highpc );
3727226Speter 	    printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
3737226Speter 		lowpc , highpc );
3747226Speter 	    printf( "[openpfile] sampbytes %d nsamples %d\n" ,
3757226Speter 		sampbytes , nsamples );
3767226Speter 	}
3777226Speter #   endif DEBUG
3784510Speter     return(pfile);
3794510Speter }
3804510Speter 
3814510Speter tally( rawp )
3824510Speter     struct rawarc	*rawp;
3834510Speter {
3844510Speter     nltype		*parentp;
3854510Speter     nltype		*childp;
3864510Speter 
3874510Speter     parentp = nllookup( rawp -> raw_frompc );
3884510Speter     childp = nllookup( rawp -> raw_selfpc );
3894510Speter     childp -> ncall += rawp -> raw_count;
3904510Speter #   ifdef DEBUG
3914510Speter 	if ( debug & TALLYDEBUG ) {
3924510Speter 	    printf( "[tally] arc from %s to %s traversed %d times\n" ,
3934510Speter 		    parentp -> name , childp -> name , rawp -> raw_count );
3944510Speter 	}
3954510Speter #   endif DEBUG
3964720Speter     addarc( parentp , childp , rawp -> raw_count );
3974510Speter }
3984510Speter 
3994866Smckusic /*
4004866Smckusic  * dump out the gmon.sum file
4014866Smckusic  */
4024866Smckusic dumpsum( sumfile )
4034866Smckusic     char *sumfile;
4044866Smckusic {
4054866Smckusic     register nltype *nlp;
4064866Smckusic     register arctype *arcp;
4074866Smckusic     struct rawarc arc;
4084866Smckusic     FILE *sfile;
4094866Smckusic 
4104866Smckusic     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
4114866Smckusic 	perror( sumfile );
4124866Smckusic 	done();
4134866Smckusic     }
4144866Smckusic     /*
4154866Smckusic      * dump the header; use the last header read in
4164866Smckusic      */
4174866Smckusic     if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
4184866Smckusic 	perror( sumfile );
4194866Smckusic 	done();
4204866Smckusic     }
4214866Smckusic     /*
4224866Smckusic      * dump the samples
4234866Smckusic      */
4244866Smckusic     if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
4254866Smckusic 	perror( sumfile );
4264866Smckusic 	done();
4274866Smckusic     }
4284866Smckusic     /*
4294866Smckusic      * dump the normalized raw arc information
4304866Smckusic      */
43111807Smckusick     for ( nlp = nl ; nlp < npe ; nlp++ ) {
4324866Smckusic 	for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
4334866Smckusic 	    arc.raw_frompc = arcp -> arc_parentp -> value;
4344866Smckusic 	    arc.raw_selfpc = arcp -> arc_childp -> value;
4354866Smckusic 	    arc.raw_count = arcp -> arc_count;
4364866Smckusic 	    if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
4374866Smckusic 		perror( sumfile );
4384866Smckusic 		done();
4394866Smckusic 	    }
4404866Smckusic #	    ifdef DEBUG
4414866Smckusic 		if ( debug & SAMPLEDEBUG ) {
4424866Smckusic 		    printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
4434866Smckusic 			    arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
4444866Smckusic 		}
4454866Smckusic #	    endif DEBUG
4464866Smckusic 	}
4474866Smckusic     }
4484866Smckusic     fclose( sfile );
4494866Smckusic }
4504866Smckusic 
4514510Speter valcmp(p1, p2)
4524510Speter     nltype *p1, *p2;
4534510Speter {
4544510Speter     if ( p1 -> value < p2 -> value ) {
4554510Speter 	return LESSTHAN;
4564510Speter     }
4574510Speter     if ( p1 -> value > p2 -> value ) {
4584510Speter 	return GREATERTHAN;
4594510Speter     }
4604510Speter     return EQUALTO;
4614510Speter }
4624510Speter 
4634510Speter readsamples(pfile)
4644510Speter     FILE	*pfile;
4654510Speter {
4664510Speter     register i;
4674510Speter     unsigned UNIT	sample;
4684510Speter 
4694510Speter     if (samples == 0) {
4704510Speter 	samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
4714510Speter 	if (samples == 0) {
4727128Speter 	    fprintf( stderr , "%s: No room for %d sample pc's\n",
4737128Speter 		whoami , sampbytes / sizeof (unsigned UNIT));
4744510Speter 	    done();
4754510Speter 	}
4764510Speter     }
4774510Speter     for (i = 0; i < nsamples; i++) {
4784510Speter 	fread(&sample, sizeof (unsigned UNIT), 1, pfile);
4794510Speter 	if (feof(pfile))
4804510Speter 		break;
4814510Speter 	samples[i] += sample;
4824510Speter     }
4834510Speter     if (i != nsamples) {
4844510Speter 	fprintf(stderr,
4857128Speter 	    "%s: unexpected EOF after reading %d/%d samples\n",
4867128Speter 		whoami , --i , nsamples );
4874510Speter 	done();
4884510Speter     }
4894510Speter }
4904510Speter 
4914510Speter /*
49211523Smckusick  *	Assign samples to the procedures to which they belong.
49311523Smckusick  *
49411523Smckusick  *	There are three cases as to where pcl and pch can be
49511523Smckusick  *	with respect to the routine entry addresses svalue0 and svalue1
49611523Smckusick  *	as shown in the following diagram.  overlap computes the
49711523Smckusick  *	distance between the arrows, the fraction of the sample
49811523Smckusick  *	that is to be credited to the routine which starts at svalue0.
49911523Smckusick  *
50011523Smckusick  *	    svalue0                                         svalue1
50111523Smckusick  *	       |                                               |
50211523Smckusick  *	       v                                               v
50311523Smckusick  *
50411523Smckusick  *	       +-----------------------------------------------+
50511523Smckusick  *	       |					       |
50611523Smckusick  *	  |  ->|    |<-		->|         |<-		->|    |<-  |
50711523Smckusick  *	  |         |		  |         |		  |         |
50811523Smckusick  *	  +---------+		  +---------+		  +---------+
50911523Smckusick  *
51011523Smckusick  *	  ^         ^		  ^         ^		  ^         ^
51111523Smckusick  *	  |         |		  |         |		  |         |
51211523Smckusick  *	 pcl       pch		 pcl       pch		 pcl       pch
51311523Smckusick  *
51411523Smckusick  *	For the vax we assert that samples will never fall in the first
51511807Smckusick  *	two bytes of any routine, since that is the entry mask,
51611807Smckusick  *	thus we give call alignentries() to adjust the entry points if
51711807Smckusick  *	the entry mask falls in one bucket but the code for the routine
51811807Smckusick  *	doesn't start until the next bucket.  In conjunction with the
51911807Smckusick  *	alignment of routine addresses, this should allow us to have
52011807Smckusick  *	only one sample for every four bytes of text space and never
52111807Smckusick  *	have any overlap (the two end cases, above).
5224510Speter  */
5234510Speter asgnsamples()
5244510Speter {
5254510Speter     register int	j;
5264510Speter     unsigned UNIT	ccnt;
5274510Speter     double		time;
5284510Speter     unsigned long	pcl, pch;
5294510Speter     register int	i;
5304841Speter     unsigned long	overlap;
5314510Speter     unsigned long	svalue0, svalue1;
5324510Speter 
5334510Speter     /* read samples and assign to namelist symbols */
5344510Speter     scale = highpc - lowpc;
5354510Speter     scale /= nsamples;
53611807Smckusick     alignentries();
5377257Smckusick     for (i = 0, j = 1; i < nsamples; i++) {
5384510Speter 	ccnt = samples[i];
5394510Speter 	if (ccnt == 0)
5404510Speter 		continue;
54111523Smckusick 	pcl = lowpc + scale * i;
54211523Smckusick 	pch = lowpc + scale * (i + 1);
5434510Speter 	time = ccnt;
5444510Speter #	ifdef DEBUG
5454510Speter 	    if ( debug & SAMPLEDEBUG ) {
5465072Smckusic 		printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
5475072Smckusic 			pcl , pch , ccnt );
5484510Speter 	    }
5494510Speter #	endif DEBUG
5504510Speter 	totime += time;
5517252Smckusick 	for (j = j - 1; j < nname; j++) {
55211807Smckusick 	    svalue0 = nl[j].svalue;
55311807Smckusick 	    svalue1 = nl[j+1].svalue;
55411807Smckusick 		/*
55511807Smckusick 		 *	if high end of tick is below entry address,
55611807Smckusick 		 *	go for next tick.
55711807Smckusick 		 */
5584510Speter 	    if (pch < svalue0)
5594510Speter 		    break;
56011807Smckusick 		/*
56111807Smckusick 		 *	if low end of tick into next routine,
56211807Smckusick 		 *	go for next routine.
56311807Smckusick 		 */
5644510Speter 	    if (pcl >= svalue1)
5654510Speter 		    continue;
56611807Smckusick 	    overlap = min(pch, svalue1) - max(pcl, svalue0);
56711523Smckusick 	    if (overlap > 0) {
5684510Speter #		ifdef DEBUG
56911523Smckusick 		    if (debug & SAMPLEDEBUG) {
57011807Smckusick 			printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
57111807Smckusick 				nl[j].value/sizeof(UNIT), svalue0, svalue1,
57211807Smckusick 				nl[j].name,
57311807Smckusick 				overlap * time / scale, overlap);
5744510Speter 		    }
5754510Speter #		endif DEBUG
57611523Smckusick 		nl[j].time += overlap * time / scale;
5774510Speter 	    }
5784510Speter 	}
5794510Speter     }
5804510Speter #   ifdef DEBUG
58111523Smckusick 	if (debug & SAMPLEDEBUG) {
58211523Smckusick 	    printf("[asgnsamples] totime %f\n", totime);
5834510Speter 	}
5844510Speter #   endif DEBUG
5854510Speter }
5864510Speter 
5874510Speter 
5884841Speter unsigned long
5894510Speter min(a, b)
5904841Speter     unsigned long a,b;
5914510Speter {
5924510Speter     if (a<b)
5934510Speter 	return(a);
5944510Speter     return(b);
5954510Speter }
5964510Speter 
5974841Speter unsigned long
5984510Speter max(a, b)
5994841Speter     unsigned long a,b;
6004510Speter {
6014510Speter     if (a>b)
6024510Speter 	return(a);
6034510Speter     return(b);
6044510Speter }
6054510Speter 
60611807Smckusick     /*
60711807Smckusick      *	calculate scaled entry point addresses (to save time in asgnsamples),
60811807Smckusick      *	and possibly push the scaled entry points over the entry mask,
60911807Smckusick      *	if it turns out that the entry point is in one bucket and the code
61011807Smckusick      *	for a routine is in the next bucket.
61111807Smckusick      */
61211807Smckusick alignentries()
61311807Smckusick {
61411807Smckusick     register struct nl	*nlp;
61511807Smckusick     unsigned long	bucket_of_entry;
61611807Smckusick     unsigned long	bucket_of_code;
61711807Smckusick 
61811807Smckusick     for (nlp = nl; nlp < npe; nlp++) {
61911807Smckusick 	nlp -> svalue = nlp -> value / sizeof(UNIT);
62011807Smckusick 	bucket_of_entry = (nlp->svalue - lowpc) / scale;
62111807Smckusick 	bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
62211807Smckusick 	if (bucket_of_entry < bucket_of_code) {
62311807Smckusick #	    ifdef DEBUG
62411807Smckusick 		if (debug & SAMPLEDEBUG) {
62511807Smckusick 		    printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
62611807Smckusick 			    nlp->svalue, nlp->svalue + UNITS_TO_CODE);
62711807Smckusick 		}
62811807Smckusick #	    endif DEBUG
62911807Smckusick 	    nlp->svalue += UNITS_TO_CODE;
63011807Smckusick 	}
63111807Smckusick     }
63211807Smckusick }
63311807Smckusick 
6344845Speter bool
6354845Speter funcsymbol( nlistp )
6364845Speter     struct nlist	*nlistp;
6374845Speter {
6384845Speter     extern char	*strtab;	/* string table from a.out */
6394851Speter     extern int	aflag;		/* if static functions aren't desired */
6404845Speter     char	*name;
6414845Speter 
6424845Speter 	/*
6434845Speter 	 *	must be a text symbol,
6444851Speter 	 *	and static text symbols don't qualify if aflag set.
6454845Speter 	 */
6464845Speter     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
6474851Speter 	   || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
6484845Speter 	return FALSE;
6494845Speter     }
6504845Speter 	/*
6517128Speter 	 *	can't have any `funny' characters in name,
6524845Speter 	 *	where `funny' includes	`.', .o file names
6534845Speter 	 *			and	`$', pascal labels.
6544845Speter 	 */
6554845Speter     for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
6564845Speter 	if ( *name == '.' || *name == '$' ) {
6574845Speter 	    return FALSE;
6584845Speter 	}
6594845Speter     }
6604845Speter     return TRUE;
6614845Speter }
6624845Speter 
6634510Speter done()
6644510Speter {
6654510Speter 
6664510Speter     exit(0);
6674510Speter }
668