xref: /csrg-svn/usr.bin/gprof/gprof.c (revision 4563)
14510Speter #ifndef lint
2*4563Speter     static	char *sccsid = "@(#)gprof.c	1.2 (Berkeley) 10/20/81";
34510Speter #endif lint
44510Speter 
5*4563Speter #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
244510Speter 	} else if ( **argv == 'z' ) {
254510Speter 	    zflg++;
264510Speter 	}
274510Speter 	argv++;
284510Speter     }
294510Speter     if ( *argv != 0 ) {
304510Speter 	a_outname  = *argv;
314510Speter 	argv++;
324510Speter     } else {
334510Speter 	a_outname  = A_OUTNAME;
344510Speter     }
354510Speter     if ( *argv != 0 ) {
36*4563Speter 	gmonname = *argv;
374510Speter 	argv++;
384510Speter     } else {
39*4563Speter 	gmonname = GMONNAME;
404510Speter     }
414510Speter 	/*
424510Speter 	 *	get information about a.out file.
434510Speter 	 */
444510Speter     getnfile();
454510Speter 	/*
464510Speter 	 *	get information about mon.out file(s).
474510Speter 	 */
48*4563Speter     getpfile( gmonname );
494510Speter 	/*
504510Speter 	 *	assign samples to procedures
514510Speter 	 */
524510Speter     asgnsamples();
534510Speter 	/*
544510Speter 	 *	print the usual profile
554510Speter 	 */
564510Speter     printprof();
574510Speter 	/*
584510Speter 	 *	assemble and print the dynamic profile
594510Speter 	 */
604510Speter     doarcs();
614510Speter     done();
624510Speter }
634510Speter 
644510Speter printprof()
654510Speter {
664510Speter     register nltype	*np;
674510Speter     nltype		**sortednlp;
684510Speter     int			index;
694510Speter 
704510Speter     actime = 0.0;
714510Speter     putprofheader();
724510Speter 	/*
734510Speter 	 *	Sort the symbol table in by time
744510Speter 	 */
754510Speter     sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
764510Speter     if ( sortednlp == (nltype **) 0 ) {
774510Speter 	fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
784510Speter     }
794510Speter     for ( index = 0 ; index < nname ; index += 1 ) {
804510Speter 	sortednlp[ index ] = &nl[ index ];
814510Speter     }
824510Speter     qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
834510Speter     for ( index = 0 ; index < nname ; index += 1 ) {
844510Speter 	np = sortednlp[ index ];
854510Speter 	putprofline( np , 1 );
864510Speter     }
874510Speter     actime = 0.0;
884510Speter     printf( "\ngranularity: each sample hit covers %.1f bytes" , scale );
894510Speter     printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ );
904510Speter }
914510Speter 
924510Speter putprofline( np , cumflag )
934510Speter     register nltype	*np;
944510Speter     int			cumflag;
954510Speter {
964510Speter     double	time;
974510Speter     long	calls = np -> ncall + np -> selfcalls;
984510Speter 
994510Speter     if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) {
1004510Speter 	return;
1014510Speter     }
1024510Speter     if ( cumflag ) {
1034510Speter 	time = (np->time + np->childtime) / totime;
1044510Speter 	actime += np->time;
1054510Speter 	if ( np -> index != 0 ) {
1064510Speter 	    printf( "[%d]" , np -> index );
1074510Speter 	}
1084510Speter 	printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ );
1094510Speter     } else {
1104510Speter 	printf( "\t%5.5s %7.7s" , "" , "" );
1114510Speter     }
1124510Speter     printf( " %7.1f", np -> time / HZ );
1134510Speter     if ( np -> childtime != 0.0 ) {
1144510Speter 	printf( " %7.1f" , np -> childtime / HZ );
1154510Speter     } else {
1164510Speter 	printf( " %7.7s" , "" );
1174510Speter     }
1184510Speter     if ( calls != 0 ) {
1194510Speter 	printf( " %7d" , np -> ncall );
1204510Speter 	if ( np -> selfcalls != 0 ) {
1214510Speter 	    printf( "+%-7d  " , np -> selfcalls );
1224510Speter 	} else {
1234510Speter 	    printf( " %7.7s  " , "" );
1244510Speter 	}
1254510Speter     } else {
1264510Speter 	printf( " %7.7s %7.7s  " , "" , "" );
1274510Speter     }
1284510Speter     if ( ! cumflag ) {
1294510Speter 	printf( "    " );
1304510Speter     }
1314510Speter     printname( np );
1324510Speter     printf( "\n" );
1334510Speter }
1344510Speter 
1354510Speter     /*
1364510Speter      *	header for putprofline
1374510Speter      */
1384510Speter putprofheader()
1394510Speter {
1404510Speter 
1414510Speter     printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" ,
1424510Speter 	    "%time" , "cumsecs" , "  self" , " child" , "ncall" , "" , "name" );
1434510Speter }
1444510Speter 
1454510Speter /*
1464510Speter  * Set up string and symbol tables from a.out.
1474510Speter  * On return symbol table is sorted by value.
1484510Speter  */
1494510Speter getnfile()
1504510Speter {
1514510Speter     FILE	*nfile;
1524510Speter 
1534510Speter     nfile = fopen( a_outname ,"r");
1544510Speter     if (nfile == NULL) {
1554510Speter 	perror( a_outname );
1564510Speter 	done();
1574510Speter     }
1584510Speter     fread(&xbuf, 1, sizeof(xbuf), nfile);
1594510Speter     if (N_BADMAG(xbuf)) {
1604510Speter 	fprintf(stderr, "%s: bad format\n", a_outname );
1614510Speter 	done();
1624510Speter     }
1634510Speter     getstrtab(nfile);
1644510Speter     getsymtab(nfile);
1654510Speter     qsort(nl, nname, sizeof(nltype), valcmp);
1664510Speter     fclose(nfile);
1674510Speter #   ifdef DEBUG
1684510Speter 	if ( debug & AOUTDEBUG ) {
1694510Speter 	    register int j;
1704510Speter 
1714510Speter 	    for (j = 0; j < nname; j++){
1724510Speter 		printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
1734510Speter 	    }
1744510Speter 	}
1754510Speter #   endif DEBUG
1764510Speter }
1774510Speter 
1784510Speter getstrtab(nfile)
1794510Speter     FILE	*nfile;
1804510Speter {
1814510Speter 
1824510Speter     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
1834510Speter     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
1844510Speter 	fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
1854510Speter 	done();
1864510Speter     }
1874510Speter     strtab = (char *)calloc(ssiz, 1);
1884510Speter     if (strtab == NULL) {
1894510Speter 	fprintf(stderr, "%s: no room for %d bytes of string table",
1904510Speter 		a_outname , ssiz);
1914510Speter 	done();
1924510Speter     }
1934510Speter     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
1944510Speter 	fprintf(stderr, "%s: error reading string table\n", a_outname );
1954510Speter 	done();
1964510Speter     }
1974510Speter }
1984510Speter 
1994510Speter     /*
2004510Speter      * Read in symbol table
2014510Speter      */
2024510Speter getsymtab(nfile)
2034510Speter     FILE	*nfile;
2044510Speter {
2054510Speter     register long	i;
2064510Speter     int			askfor;
2074510Speter     struct nlist	nbuf;
2084510Speter 
2094510Speter     /* pass1 - count symbols */
2104510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
2114510Speter     nname = 0;
2124510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2134510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
2144510Speter 	if ( nbuf.n_type != N_TEXT+N_EXT ) {
2154510Speter 	    continue;
2164510Speter 	}
2174510Speter 	nname++;
2184510Speter     }
2194510Speter     if (nname == 0) {
2204510Speter 	fprintf(stderr, "%s: no symbols\n", a_outname );
2214510Speter 	done();
2224510Speter     }
2234510Speter 	/*
2244510Speter 	 *	ask also for CYCLEFRACTION extra namelist entries for
2254510Speter 	 *	cycle entries.  these hide out at the end of the namelist
2264510Speter 	 *	and aren't accessed unless the whole namelist (nname+ncycles)
2274510Speter 	 *	is sorted and searched.
2284510Speter 	 */
2294510Speter     ncycles = nname * CYCLEFRACTION;
2304510Speter     askfor = nname + 1 + ncycles;
2314510Speter     nl = (nltype *) calloc( askfor , sizeof(nltype) );
2324510Speter     if (nl == 0) {
2334510Speter 	fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
2344510Speter 		askfor * sizeof(nltype) );
2354510Speter 	done();
2364510Speter     }
2374510Speter 
2384510Speter     /* pass2 - read symbols */
2394510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
2404510Speter     npe = nl;
2414510Speter     nname = 0;
2424510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2434510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
2444510Speter 	if ( nbuf.n_type != N_TEXT+N_EXT ) {
2454510Speter 	    continue;
2464510Speter 	}
2474510Speter 	npe->value = nbuf.n_value;
2484510Speter 	npe->name = strtab+nbuf.n_un.n_strx;
2494510Speter #	ifdef DEBUG
2504510Speter 	    if ( debug & AOUTDEBUG ) {
2514510Speter 		printf( "[getsymtab] %d %s 0x%08x\n" ,
2524510Speter 			nname , npe -> name , npe -> value );
2534510Speter 	    }
2544510Speter #	endif DEBUG
2554510Speter 	npe++;
2564510Speter 	nname++;
2574510Speter     }
2584510Speter     npe->value = -1;
2594510Speter     npe++;
2604510Speter }
2614510Speter 
2624510Speter     /*
263*4563Speter      *	information from a gmon.out file is in two parts:
2644510Speter      *	an array of sampling hits within pc ranges,
2654510Speter      *	and the arcs.
2664510Speter      */
2674510Speter getpfile(filename)
2684510Speter     char *filename;
2694510Speter {
2704510Speter     FILE		*pfile;
2714510Speter     FILE		*openpfile();
2724510Speter     struct rawarc	arc;
2734510Speter 
2744510Speter     pfile = openpfile(filename);
2754510Speter     readsamples(pfile);
2764510Speter 	/*
2774510Speter 	 *	the rest of the file consists of
2784510Speter 	 *	a bunch of <from,self,count> tuples.
2794510Speter 	 */
2804510Speter     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
2814510Speter #	ifdef DEBUG
2824510Speter 	    if ( debug & SAMPLEDEBUG ) {
2834510Speter 		printf( "[getpfile] frompc %d selfpc %d count %d\n" ,
2844510Speter 			arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
2854510Speter 	    }
2864510Speter #	endif DEBUG
2874510Speter 	    /*
2884510Speter 	     *	add this arc
2894510Speter 	     */
2904510Speter 	tally( &arc );
2914510Speter     }
2924510Speter     fclose(pfile);
2934510Speter }
2944510Speter 
2954510Speter FILE *openpfile(filename)
2964510Speter     char *filename;
2974510Speter {
2984510Speter     FILE	*pfile;
2994510Speter 
3004510Speter     if((pfile = fopen(filename, "r")) == NULL) {
3014510Speter 	perror(filename);
3024510Speter 	done();
3034510Speter     }
3044510Speter     fread(&h, sizeof(struct hdr), 1, pfile);
3054510Speter     lowpc = h.lowpc - (UNIT *)0;
3064510Speter     highpc = h.highpc - (UNIT *)0;
3074510Speter     sampbytes = h.ncnt - sizeof(struct hdr);
3084510Speter     nsamples = sampbytes / sizeof (unsigned UNIT);
3094510Speter     return(pfile);
3104510Speter }
3114510Speter 
3124510Speter tally( rawp )
3134510Speter     struct rawarc	*rawp;
3144510Speter {
3154510Speter     nltype		*parentp;
3164510Speter     nltype		*childp;
3174510Speter     arctype		*arcp;
3184510Speter     arctype		*malloc();
3194510Speter 
3204510Speter     parentp = nllookup( rawp -> raw_frompc );
3214510Speter     childp = nllookup( rawp -> raw_selfpc );
3224510Speter     childp -> ncall += rawp -> raw_count;
3234510Speter #   ifdef DEBUG
3244510Speter 	if ( debug & TALLYDEBUG ) {
3254510Speter 	    printf( "[tally] arc from %s to %s traversed %d times\n" ,
3264510Speter 		    parentp -> name , childp -> name , rawp -> raw_count );
3274510Speter 	}
3284510Speter #   endif DEBUG
3294510Speter     arcp = arclookup( parentp , childp );
3304510Speter     if ( arcp != 0 ) {
3314510Speter 	    /*
3324510Speter 	     *	a hit:  just increment the count.
3334510Speter 	     */
3344510Speter #	ifdef DEBUG
3354510Speter 	    if ( debug & TALLYDEBUG ) {
3364510Speter 		printf( "[tally] hit %d += %d\n" ,
3374510Speter 			arcp -> arc_count , rawp -> raw_count );
3384510Speter 	    }
3394510Speter #	endif DEBUG
3404510Speter 	arcp -> arc_count += rawp -> raw_count;
3414510Speter 	return;
3424510Speter     }
3434510Speter     arcp = malloc( sizeof *arcp );
3444510Speter     arcp -> arc_parentp = parentp;
3454510Speter     arcp -> arc_childp = childp;
3464510Speter     arcp -> arc_count = rawp -> raw_count;
3474510Speter 	/*
3484510Speter 	 *	prepend this child to the children of this parent
3494510Speter 	 */
3504510Speter     arcp -> arc_childlist = parentp -> children;
3514510Speter     parentp -> children = arcp;
3524510Speter 	/*
3534510Speter 	 *	prepend this parent to the parents of this child
3544510Speter 	 */
3554510Speter     arcp -> arc_parentlist = childp -> parents;
3564510Speter     childp -> parents = arcp;
3574510Speter }
3584510Speter 
3594510Speter valcmp(p1, p2)
3604510Speter     nltype *p1, *p2;
3614510Speter {
3624510Speter     if ( p1 -> value < p2 -> value ) {
3634510Speter 	return LESSTHAN;
3644510Speter     }
3654510Speter     if ( p1 -> value > p2 -> value ) {
3664510Speter 	return GREATERTHAN;
3674510Speter     }
3684510Speter     return EQUALTO;
3694510Speter }
3704510Speter 
3714510Speter readsamples(pfile)
3724510Speter     FILE	*pfile;
3734510Speter {
3744510Speter     register i;
3754510Speter     unsigned UNIT	sample;
3764510Speter 
3774510Speter     if (samples == 0) {
3784510Speter 	samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
3794510Speter 	if (samples == 0) {
3804510Speter 	    fprintf( stderr , "prof: No room for %d sample pc's\n",
3814510Speter 		sampbytes / sizeof (unsigned UNIT));
3824510Speter 	    done();
3834510Speter 	}
3844510Speter     }
3854510Speter     for (i = 0; i < nsamples; i++) {
3864510Speter 	fread(&sample, sizeof (unsigned UNIT), 1, pfile);
3874510Speter 	if (feof(pfile))
3884510Speter 		break;
3894510Speter 	samples[i] += sample;
3904510Speter     }
3914510Speter     if (i != nsamples) {
3924510Speter 	fprintf(stderr,
3934510Speter 	    "prof: unexpected EOF after reading %d/%d samples\n",
3944510Speter 		--i, nsamples);
3954510Speter 	done();
3964510Speter     }
3974510Speter }
3984510Speter 
3994510Speter /*
4004510Speter  * Assign samples to the procedures to which they belong.
4014510Speter  */
4024510Speter asgnsamples()
4034510Speter {
4044510Speter     register int	j;
4054510Speter     unsigned UNIT	ccnt;
4064510Speter     double		time;
4074510Speter     unsigned long	pcl, pch;
4084510Speter     register int	i;
4094510Speter     int			overlap;
4104510Speter     unsigned long	svalue0, svalue1;
4114510Speter 
4124510Speter     /* read samples and assign to namelist symbols */
4134510Speter     scale = highpc - lowpc;
4144510Speter     scale /= nsamples;
4154510Speter     for (i=0; i < nsamples; i++) {
4164510Speter 	ccnt = samples[i];
4174510Speter 	if (ccnt == 0)
4184510Speter 		continue;
4194510Speter 	pcl = lowpc + scale*i;
4204510Speter 	pch = lowpc + scale*(i+1);
4214510Speter 	time = ccnt;
4224510Speter #	ifdef DEBUG
4234510Speter 	    if ( debug & SAMPLEDEBUG ) {
4244510Speter 		printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
4254510Speter 			ccnt , time , totime );
4264510Speter 	    }
4274510Speter #	endif DEBUG
4284510Speter 	totime += time;
4294510Speter 	for (j=0; j<nname; j++) {
4304510Speter 	    svalue0 = nl[j].value / sizeof(UNIT);
4314510Speter 	    svalue1 = nl[j+1].value / sizeof(UNIT);
4324510Speter 	    if (pch < svalue0)
4334510Speter 		    break;
4344510Speter 	    if (pcl >= svalue1)
4354510Speter 		    continue;
4364510Speter 	    overlap=min(pch,svalue1) - max(pcl,svalue0);
4374510Speter 	    if (overlap>0) {
4384510Speter #		ifdef DEBUG
4394510Speter 		    if ( debug & SAMPLEDEBUG ) {
4404510Speter 			printf( "[asgnsamples] %s gets %f ticks\n" ,
4414510Speter 				nl[j].name , overlap*time/scale );
4424510Speter 		    }
4434510Speter #		endif DEBUG
4444510Speter 		nl[j].time += overlap*time/scale;
4454510Speter 	    }
4464510Speter 	}
4474510Speter     }
4484510Speter #   ifdef DEBUG
4494510Speter 	if ( debug & SAMPLEDEBUG ) {
4504510Speter 	    printf( "[asgnsamples] totime %f\n" , totime );
4514510Speter 	}
4524510Speter #   endif DEBUG
4534510Speter     if (totime==0.0) {
4544510Speter 	fprintf( stderr , "No time accumulated\n" );
4554510Speter 	totime=1.0;
4564510Speter     }
4574510Speter }
4584510Speter 
4594510Speter 
4604510Speter min(a, b)
4614510Speter     unsigned a,b;
4624510Speter {
4634510Speter     if (a<b)
4644510Speter 	return(a);
4654510Speter     return(b);
4664510Speter }
4674510Speter 
4684510Speter max(a, b)
4694510Speter     unsigned a,b;
4704510Speter {
4714510Speter     if (a>b)
4724510Speter 	return(a);
4734510Speter     return(b);
4744510Speter }
4754510Speter 
4764510Speter timecmp( npp1 , npp2 )
4774510Speter     nltype **npp1, **npp2;
4784510Speter {
4794510Speter     double d;
4804510Speter 
4814510Speter     d = (*npp2)->time - (*npp1)->time;
4824510Speter     if (d > 0.0)
4834510Speter 	return(1);
4844510Speter     if (d < 0.0)
4854510Speter 	return(-1);
4864510Speter     return(strcmp((*npp1)->name,(*npp2)->name));
4874510Speter }
4884510Speter 
4894510Speter done()
4904510Speter {
4914510Speter 
4924510Speter     exit(0);
4934510Speter }
494