xref: /csrg-svn/usr.bin/gprof/gprof.c (revision 4851)
14510Speter #ifndef lint
2*4851Speter     static	char *sccsid = "@(#)gprof.c	1.7 (Berkeley) 11/10/81";
34510Speter #endif lint
44510Speter 
54563Speter #include "gprof.h"
64510Speter 
74510Speter main(argc, argv)
84510Speter 	int argc;
94510Speter 	char **argv;
104510Speter {
114510Speter 
124510Speter     --argc;
134510Speter     argv++;
144510Speter     debug = 0;
154510Speter     while ( *argv != 0 && **argv == '-' ) {
164510Speter 	(*argv)++;
174510Speter 	if ( **argv == 'd' ) {
184510Speter 	    (*argv)++;
194510Speter 	    debug |= atoi( *argv );
204510Speter 	    debug |= ANYDEBUG;
214510Speter #	    ifdef DEBUG
224510Speter 		printf( "[main] debug = %d\n" , debug );
234510Speter #	    endif DEBUG
244845Speter 	} else if ( **argv == 'a' ) {
254845Speter 	    aflag++;
264845Speter 	} else if ( **argv == 'c' ) {
274845Speter 	    cflag++;
284510Speter 	} else if ( **argv == 'z' ) {
294510Speter 	    zflg++;
304510Speter 	}
314510Speter 	argv++;
324510Speter     }
334510Speter     if ( *argv != 0 ) {
344510Speter 	a_outname  = *argv;
354510Speter 	argv++;
364510Speter     } else {
374510Speter 	a_outname  = A_OUTNAME;
384510Speter     }
394510Speter     if ( *argv != 0 ) {
404563Speter 	gmonname = *argv;
414510Speter 	argv++;
424510Speter     } else {
434563Speter 	gmonname = GMONNAME;
444510Speter     }
454510Speter 	/*
464510Speter 	 *	get information about a.out file.
474510Speter 	 */
484510Speter     getnfile();
494510Speter 	/*
504510Speter 	 *	get information about mon.out file(s).
514510Speter 	 */
524563Speter     getpfile( gmonname );
534510Speter 	/*
544510Speter 	 *	assign samples to procedures
554510Speter 	 */
564510Speter     asgnsamples();
574510Speter 	/*
584510Speter 	 *	print the usual profile
594510Speter 	 */
604510Speter     printprof();
614510Speter 	/*
624510Speter 	 *	assemble and print the dynamic profile
634510Speter 	 */
644510Speter     doarcs();
654510Speter     done();
664510Speter }
674510Speter 
684510Speter /*
694510Speter  * Set up string and symbol tables from a.out.
704720Speter  *	and optionally the text space.
714510Speter  * On return symbol table is sorted by value.
724510Speter  */
734510Speter getnfile()
744510Speter {
754510Speter     FILE	*nfile;
764510Speter 
774510Speter     nfile = fopen( a_outname ,"r");
784510Speter     if (nfile == NULL) {
794510Speter 	perror( a_outname );
804510Speter 	done();
814510Speter     }
824510Speter     fread(&xbuf, 1, sizeof(xbuf), nfile);
834510Speter     if (N_BADMAG(xbuf)) {
844510Speter 	fprintf(stderr, "%s: bad format\n", a_outname );
854510Speter 	done();
864510Speter     }
874510Speter     getstrtab(nfile);
884510Speter     getsymtab(nfile);
894720Speter     gettextspace( nfile );
904510Speter     qsort(nl, nname, sizeof(nltype), valcmp);
914510Speter     fclose(nfile);
924510Speter #   ifdef DEBUG
934510Speter 	if ( debug & AOUTDEBUG ) {
944510Speter 	    register int j;
954510Speter 
964510Speter 	    for (j = 0; j < nname; j++){
974510Speter 		printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
984510Speter 	    }
994510Speter 	}
1004510Speter #   endif DEBUG
1014510Speter }
1024510Speter 
1034510Speter getstrtab(nfile)
1044510Speter     FILE	*nfile;
1054510Speter {
1064510Speter 
1074510Speter     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
1084510Speter     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
1094510Speter 	fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
1104510Speter 	done();
1114510Speter     }
1124510Speter     strtab = (char *)calloc(ssiz, 1);
1134510Speter     if (strtab == NULL) {
1144510Speter 	fprintf(stderr, "%s: no room for %d bytes of string table",
1154510Speter 		a_outname , ssiz);
1164510Speter 	done();
1174510Speter     }
1184510Speter     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
1194510Speter 	fprintf(stderr, "%s: error reading string table\n", a_outname );
1204510Speter 	done();
1214510Speter     }
1224510Speter }
1234510Speter 
1244510Speter     /*
1254510Speter      * Read in symbol table
1264510Speter      */
1274510Speter getsymtab(nfile)
1284510Speter     FILE	*nfile;
1294510Speter {
1304510Speter     register long	i;
1314510Speter     int			askfor;
1324510Speter     struct nlist	nbuf;
1334510Speter 
1344510Speter     /* pass1 - count symbols */
1354510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
1364510Speter     nname = 0;
1374510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
1384510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
1394845Speter 	if ( ! funcsymbol( &nbuf ) ) {
1404510Speter 	    continue;
1414510Speter 	}
1424510Speter 	nname++;
1434510Speter     }
1444510Speter     if (nname == 0) {
1454510Speter 	fprintf(stderr, "%s: no symbols\n", a_outname );
1464510Speter 	done();
1474510Speter     }
1484510Speter 	/*
1494510Speter 	 *	ask also for CYCLEFRACTION extra namelist entries for
1504510Speter 	 *	cycle entries.  these hide out at the end of the namelist
1514510Speter 	 *	and aren't accessed unless the whole namelist (nname+ncycles)
1524510Speter 	 *	is sorted and searched.
1534510Speter 	 */
1544510Speter     ncycles = nname * CYCLEFRACTION;
1554510Speter     askfor = nname + 1 + ncycles;
1564510Speter     nl = (nltype *) calloc( askfor , sizeof(nltype) );
1574510Speter     if (nl == 0) {
1584510Speter 	fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
1594510Speter 		askfor * sizeof(nltype) );
1604510Speter 	done();
1614510Speter     }
1624510Speter 
1634510Speter     /* pass2 - read symbols */
1644510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
1654510Speter     npe = nl;
1664510Speter     nname = 0;
1674510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
1684510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
1694845Speter 	if ( ! funcsymbol( &nbuf ) ) {
1704845Speter #	    ifdef DEBUG
1714845Speter 		if ( debug & AOUTDEBUG ) {
1724845Speter 		    printf( "[getsymtab] rejecting: 0x%x %s\n" ,
1734845Speter 			    nbuf.n_type , strtab + nbuf.n_un.n_strx );
1744845Speter 		}
1754845Speter #	    endif DEBUG
1764510Speter 	    continue;
1774510Speter 	}
1784510Speter 	npe->value = nbuf.n_value;
1794510Speter 	npe->name = strtab+nbuf.n_un.n_strx;
1804510Speter #	ifdef DEBUG
1814510Speter 	    if ( debug & AOUTDEBUG ) {
1824510Speter 		printf( "[getsymtab] %d %s 0x%08x\n" ,
1834510Speter 			nname , npe -> name , npe -> value );
1844510Speter 	    }
1854510Speter #	endif DEBUG
1864510Speter 	npe++;
1874510Speter 	nname++;
1884510Speter     }
1894510Speter     npe->value = -1;
1904510Speter     npe++;
1914510Speter }
1924510Speter 
1934510Speter     /*
1944720Speter      *	read in the text space of an a.out file
1954720Speter      */
1964720Speter gettextspace( nfile )
1974720Speter     FILE	*nfile;
1984720Speter {
1994720Speter     unsigned char	*malloc();
2004720Speter 
2014720Speter     if ( cflag == 0 ) {
2024720Speter 	return;
2034720Speter     }
2044720Speter     textspace = malloc( xbuf.a_text );
2054720Speter     if ( textspace == 0 ) {
2064720Speter 	fprintf( stderr , "gprof: ran out room for %d bytes of text space:  " );
2074720Speter 	fprintf( stderr , "can't do -c\n" , xbuf.a_text );
2084720Speter 	return;
2094720Speter     }
2104720Speter     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
2114720Speter     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
2124720Speter 	fprintf( stderr , "couldn't read text space:  " );
2134720Speter 	fprintf( stderr , "can't do -c\n" , xbuf.a_text );
2144720Speter 	free( textspace );
2154720Speter 	textspace = 0;
2164720Speter 	return;
2174720Speter     }
2184720Speter }
2194720Speter     /*
2204563Speter      *	information from a gmon.out file is in two parts:
2214510Speter      *	an array of sampling hits within pc ranges,
2224510Speter      *	and the arcs.
2234510Speter      */
2244510Speter getpfile(filename)
2254510Speter     char *filename;
2264510Speter {
2274510Speter     FILE		*pfile;
2284510Speter     FILE		*openpfile();
2294510Speter     struct rawarc	arc;
2304510Speter 
2314510Speter     pfile = openpfile(filename);
2324510Speter     readsamples(pfile);
2334510Speter 	/*
2344510Speter 	 *	the rest of the file consists of
2354510Speter 	 *	a bunch of <from,self,count> tuples.
2364510Speter 	 */
2374510Speter     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
2384510Speter #	ifdef DEBUG
2394510Speter 	    if ( debug & SAMPLEDEBUG ) {
2404752Speter 		printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
2414510Speter 			arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
2424510Speter 	    }
2434510Speter #	endif DEBUG
2444510Speter 	    /*
2454510Speter 	     *	add this arc
2464510Speter 	     */
2474510Speter 	tally( &arc );
2484510Speter     }
2494510Speter     fclose(pfile);
2504510Speter }
2514510Speter 
2524841Speter FILE *
2534841Speter openpfile(filename)
2544510Speter     char *filename;
2554510Speter {
2564510Speter     FILE	*pfile;
2574510Speter 
2584510Speter     if((pfile = fopen(filename, "r")) == NULL) {
2594510Speter 	perror(filename);
2604510Speter 	done();
2614510Speter     }
2624510Speter     fread(&h, sizeof(struct hdr), 1, pfile);
2634752Speter     s_lowpc = (unsigned long) h.lowpc;
2644752Speter     s_highpc = (unsigned long) h.highpc;
2654510Speter     lowpc = h.lowpc - (UNIT *)0;
2664510Speter     highpc = h.highpc - (UNIT *)0;
2674510Speter     sampbytes = h.ncnt - sizeof(struct hdr);
2684510Speter     nsamples = sampbytes / sizeof (unsigned UNIT);
2694510Speter     return(pfile);
2704510Speter }
2714510Speter 
2724510Speter tally( rawp )
2734510Speter     struct rawarc	*rawp;
2744510Speter {
2754510Speter     nltype		*parentp;
2764510Speter     nltype		*childp;
2774510Speter 
2784510Speter     parentp = nllookup( rawp -> raw_frompc );
2794510Speter     childp = nllookup( rawp -> raw_selfpc );
2804510Speter     childp -> ncall += rawp -> raw_count;
2814510Speter #   ifdef DEBUG
2824510Speter 	if ( debug & TALLYDEBUG ) {
2834510Speter 	    printf( "[tally] arc from %s to %s traversed %d times\n" ,
2844510Speter 		    parentp -> name , childp -> name , rawp -> raw_count );
2854510Speter 	}
2864510Speter #   endif DEBUG
2874720Speter     addarc( parentp , childp , rawp -> raw_count );
2884510Speter }
2894510Speter 
2904510Speter valcmp(p1, p2)
2914510Speter     nltype *p1, *p2;
2924510Speter {
2934510Speter     if ( p1 -> value < p2 -> value ) {
2944510Speter 	return LESSTHAN;
2954510Speter     }
2964510Speter     if ( p1 -> value > p2 -> value ) {
2974510Speter 	return GREATERTHAN;
2984510Speter     }
2994510Speter     return EQUALTO;
3004510Speter }
3014510Speter 
3024510Speter readsamples(pfile)
3034510Speter     FILE	*pfile;
3044510Speter {
3054510Speter     register i;
3064510Speter     unsigned UNIT	sample;
3074510Speter 
3084510Speter     if (samples == 0) {
3094510Speter 	samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
3104510Speter 	if (samples == 0) {
3114510Speter 	    fprintf( stderr , "prof: No room for %d sample pc's\n",
3124510Speter 		sampbytes / sizeof (unsigned UNIT));
3134510Speter 	    done();
3144510Speter 	}
3154510Speter     }
3164510Speter     for (i = 0; i < nsamples; i++) {
3174510Speter 	fread(&sample, sizeof (unsigned UNIT), 1, pfile);
3184510Speter 	if (feof(pfile))
3194510Speter 		break;
3204510Speter 	samples[i] += sample;
3214510Speter     }
3224510Speter     if (i != nsamples) {
3234510Speter 	fprintf(stderr,
3244510Speter 	    "prof: unexpected EOF after reading %d/%d samples\n",
3254510Speter 		--i, nsamples);
3264510Speter 	done();
3274510Speter     }
3284510Speter }
3294510Speter 
3304510Speter /*
3314510Speter  * Assign samples to the procedures to which they belong.
3324510Speter  */
3334510Speter asgnsamples()
3344510Speter {
3354510Speter     register int	j;
3364510Speter     unsigned UNIT	ccnt;
3374510Speter     double		time;
3384510Speter     unsigned long	pcl, pch;
3394510Speter     register int	i;
3404841Speter     unsigned long	overlap;
3414510Speter     unsigned long	svalue0, svalue1;
3424510Speter 
3434510Speter     /* read samples and assign to namelist symbols */
3444510Speter     scale = highpc - lowpc;
3454510Speter     scale /= nsamples;
3464510Speter     for (i=0; i < nsamples; i++) {
3474510Speter 	ccnt = samples[i];
3484510Speter 	if (ccnt == 0)
3494510Speter 		continue;
3504510Speter 	pcl = lowpc + scale*i;
3514510Speter 	pch = lowpc + scale*(i+1);
3524510Speter 	time = ccnt;
3534510Speter #	ifdef DEBUG
3544510Speter 	    if ( debug & SAMPLEDEBUG ) {
3554510Speter 		printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
3564510Speter 			ccnt , time , totime );
3574510Speter 	    }
3584510Speter #	endif DEBUG
3594510Speter 	totime += time;
3604510Speter 	for (j=0; j<nname; j++) {
3614510Speter 	    svalue0 = nl[j].value / sizeof(UNIT);
3624510Speter 	    svalue1 = nl[j+1].value / sizeof(UNIT);
3634510Speter 	    if (pch < svalue0)
3644510Speter 		    break;
3654510Speter 	    if (pcl >= svalue1)
3664510Speter 		    continue;
3674510Speter 	    overlap=min(pch,svalue1) - max(pcl,svalue0);
3684510Speter 	    if (overlap>0) {
3694510Speter #		ifdef DEBUG
3704510Speter 		    if ( debug & SAMPLEDEBUG ) {
3714510Speter 			printf( "[asgnsamples] %s gets %f ticks\n" ,
3724510Speter 				nl[j].name , overlap*time/scale );
3734510Speter 		    }
3744510Speter #		endif DEBUG
3754510Speter 		nl[j].time += overlap*time/scale;
3764510Speter 	    }
3774510Speter 	}
3784510Speter     }
3794510Speter #   ifdef DEBUG
3804510Speter 	if ( debug & SAMPLEDEBUG ) {
3814510Speter 	    printf( "[asgnsamples] totime %f\n" , totime );
3824510Speter 	}
3834510Speter #   endif DEBUG
3844510Speter     if (totime==0.0) {
3854510Speter 	fprintf( stderr , "No time accumulated\n" );
3864510Speter 	totime=1.0;
3874510Speter     }
3884510Speter }
3894510Speter 
3904510Speter 
3914841Speter unsigned long
3924510Speter min(a, b)
3934841Speter     unsigned long a,b;
3944510Speter {
3954510Speter     if (a<b)
3964510Speter 	return(a);
3974510Speter     return(b);
3984510Speter }
3994510Speter 
4004841Speter unsigned long
4014510Speter max(a, b)
4024841Speter     unsigned long a,b;
4034510Speter {
4044510Speter     if (a>b)
4054510Speter 	return(a);
4064510Speter     return(b);
4074510Speter }
4084510Speter 
4094845Speter bool
4104845Speter funcsymbol( nlistp )
4114845Speter     struct nlist	*nlistp;
4124845Speter {
4134845Speter     extern char	*strtab;	/* string table from a.out */
414*4851Speter     extern int	aflag;		/* if static functions aren't desired */
4154845Speter     char	*name;
4164845Speter 
4174845Speter 	/*
4184845Speter 	 *	must be a text symbol,
419*4851Speter 	 *	and static text symbols don't qualify if aflag set.
4204845Speter 	 */
4214845Speter     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
422*4851Speter 	   || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
4234845Speter 	return FALSE;
4244845Speter     }
4254845Speter 	/*
4264845Speter 	 *	can't have any `funny characters in name,
4274845Speter 	 *	where `funny' includes	`.', .o file names
4284845Speter 	 *			and	`$', pascal labels.
4294845Speter 	 */
4304845Speter     for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
4314845Speter 	if ( *name == '.' || *name == '$' ) {
4324845Speter 	    return FALSE;
4334845Speter 	}
4344845Speter     }
4354845Speter     return TRUE;
4364845Speter }
4374845Speter 
4384510Speter done()
4394510Speter {
4404510Speter 
4414510Speter     exit(0);
4424510Speter }
443