xref: /csrg-svn/usr.bin/gprof/gprof.c (revision 4510)
1*4510Speter #ifndef lint
2*4510Speter     static	char *sccsid = "@(#)gprof.c	1.1 (Berkeley) 10/15/81";
3*4510Speter #endif lint
4*4510Speter 
5*4510Speter #include "dprof.h"
6*4510Speter 
7*4510Speter main(argc, argv)
8*4510Speter 	int argc;
9*4510Speter 	char **argv;
10*4510Speter {
11*4510Speter 
12*4510Speter     --argc;
13*4510Speter     argv++;
14*4510Speter     debug = 0;
15*4510Speter     while ( *argv != 0 && **argv == '-' ) {
16*4510Speter 	(*argv)++;
17*4510Speter 	if ( **argv == 'd' ) {
18*4510Speter 	    (*argv)++;
19*4510Speter 	    debug |= atoi( *argv );
20*4510Speter 	    debug |= ANYDEBUG;
21*4510Speter #	    ifdef DEBUG
22*4510Speter 		printf( "[main] debug = %d\n" , debug );
23*4510Speter #	    endif DEBUG
24*4510Speter 	} else if ( **argv == 'z' ) {
25*4510Speter 	    zflg++;
26*4510Speter 	}
27*4510Speter 	argv++;
28*4510Speter     }
29*4510Speter     if ( *argv != 0 ) {
30*4510Speter 	a_outname  = *argv;
31*4510Speter 	argv++;
32*4510Speter     } else {
33*4510Speter 	a_outname  = A_OUTNAME;
34*4510Speter     }
35*4510Speter     if ( *argv != 0 ) {
36*4510Speter 	dmonname = *argv;
37*4510Speter 	argv++;
38*4510Speter     } else {
39*4510Speter 	dmonname = DMONNAME;
40*4510Speter     }
41*4510Speter 	/*
42*4510Speter 	 *	get information about a.out file.
43*4510Speter 	 */
44*4510Speter     getnfile();
45*4510Speter 	/*
46*4510Speter 	 *	get information about mon.out file(s).
47*4510Speter 	 */
48*4510Speter     getpfile( dmonname );
49*4510Speter 	/*
50*4510Speter 	 *	assign samples to procedures
51*4510Speter 	 */
52*4510Speter     asgnsamples();
53*4510Speter 	/*
54*4510Speter 	 *	print the usual profile
55*4510Speter 	 */
56*4510Speter     printprof();
57*4510Speter 	/*
58*4510Speter 	 *	assemble and print the dynamic profile
59*4510Speter 	 */
60*4510Speter     doarcs();
61*4510Speter     done();
62*4510Speter }
63*4510Speter 
64*4510Speter printprof()
65*4510Speter {
66*4510Speter     register nltype	*np;
67*4510Speter     nltype		**sortednlp;
68*4510Speter     int			index;
69*4510Speter 
70*4510Speter     actime = 0.0;
71*4510Speter     putprofheader();
72*4510Speter 	/*
73*4510Speter 	 *	Sort the symbol table in by time
74*4510Speter 	 */
75*4510Speter     sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
76*4510Speter     if ( sortednlp == (nltype **) 0 ) {
77*4510Speter 	fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
78*4510Speter     }
79*4510Speter     for ( index = 0 ; index < nname ; index += 1 ) {
80*4510Speter 	sortednlp[ index ] = &nl[ index ];
81*4510Speter     }
82*4510Speter     qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
83*4510Speter     for ( index = 0 ; index < nname ; index += 1 ) {
84*4510Speter 	np = sortednlp[ index ];
85*4510Speter 	putprofline( np , 1 );
86*4510Speter     }
87*4510Speter     actime = 0.0;
88*4510Speter     printf( "\ngranularity: each sample hit covers %.1f bytes" , scale );
89*4510Speter     printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ );
90*4510Speter }
91*4510Speter 
92*4510Speter putprofline( np , cumflag )
93*4510Speter     register nltype	*np;
94*4510Speter     int			cumflag;
95*4510Speter {
96*4510Speter     double	time;
97*4510Speter     long	calls = np -> ncall + np -> selfcalls;
98*4510Speter 
99*4510Speter     if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) {
100*4510Speter 	return;
101*4510Speter     }
102*4510Speter     if ( cumflag ) {
103*4510Speter 	time = (np->time + np->childtime) / totime;
104*4510Speter 	actime += np->time;
105*4510Speter 	if ( np -> index != 0 ) {
106*4510Speter 	    printf( "[%d]" , np -> index );
107*4510Speter 	}
108*4510Speter 	printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ );
109*4510Speter     } else {
110*4510Speter 	printf( "\t%5.5s %7.7s" , "" , "" );
111*4510Speter     }
112*4510Speter     printf( " %7.1f", np -> time / HZ );
113*4510Speter     if ( np -> childtime != 0.0 ) {
114*4510Speter 	printf( " %7.1f" , np -> childtime / HZ );
115*4510Speter     } else {
116*4510Speter 	printf( " %7.7s" , "" );
117*4510Speter     }
118*4510Speter     if ( calls != 0 ) {
119*4510Speter 	printf( " %7d" , np -> ncall );
120*4510Speter 	if ( np -> selfcalls != 0 ) {
121*4510Speter 	    printf( "+%-7d  " , np -> selfcalls );
122*4510Speter 	} else {
123*4510Speter 	    printf( " %7.7s  " , "" );
124*4510Speter 	}
125*4510Speter     } else {
126*4510Speter 	printf( " %7.7s %7.7s  " , "" , "" );
127*4510Speter     }
128*4510Speter     if ( ! cumflag ) {
129*4510Speter 	printf( "    " );
130*4510Speter     }
131*4510Speter     printname( np );
132*4510Speter     printf( "\n" );
133*4510Speter }
134*4510Speter 
135*4510Speter     /*
136*4510Speter      *	header for putprofline
137*4510Speter      */
138*4510Speter putprofheader()
139*4510Speter {
140*4510Speter 
141*4510Speter     printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" ,
142*4510Speter 	    "%time" , "cumsecs" , "  self" , " child" , "ncall" , "" , "name" );
143*4510Speter }
144*4510Speter 
145*4510Speter /*
146*4510Speter  * Set up string and symbol tables from a.out.
147*4510Speter  * On return symbol table is sorted by value.
148*4510Speter  */
149*4510Speter getnfile()
150*4510Speter {
151*4510Speter     FILE	*nfile;
152*4510Speter 
153*4510Speter     nfile = fopen( a_outname ,"r");
154*4510Speter     if (nfile == NULL) {
155*4510Speter 	perror( a_outname );
156*4510Speter 	done();
157*4510Speter     }
158*4510Speter     fread(&xbuf, 1, sizeof(xbuf), nfile);
159*4510Speter     if (N_BADMAG(xbuf)) {
160*4510Speter 	fprintf(stderr, "%s: bad format\n", a_outname );
161*4510Speter 	done();
162*4510Speter     }
163*4510Speter     getstrtab(nfile);
164*4510Speter     getsymtab(nfile);
165*4510Speter     qsort(nl, nname, sizeof(nltype), valcmp);
166*4510Speter     fclose(nfile);
167*4510Speter #   ifdef DEBUG
168*4510Speter 	if ( debug & AOUTDEBUG ) {
169*4510Speter 	    register int j;
170*4510Speter 
171*4510Speter 	    for (j = 0; j < nname; j++){
172*4510Speter 		printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
173*4510Speter 	    }
174*4510Speter 	}
175*4510Speter #   endif DEBUG
176*4510Speter }
177*4510Speter 
178*4510Speter getstrtab(nfile)
179*4510Speter     FILE	*nfile;
180*4510Speter {
181*4510Speter 
182*4510Speter     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
183*4510Speter     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
184*4510Speter 	fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
185*4510Speter 	done();
186*4510Speter     }
187*4510Speter     strtab = (char *)calloc(ssiz, 1);
188*4510Speter     if (strtab == NULL) {
189*4510Speter 	fprintf(stderr, "%s: no room for %d bytes of string table",
190*4510Speter 		a_outname , ssiz);
191*4510Speter 	done();
192*4510Speter     }
193*4510Speter     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
194*4510Speter 	fprintf(stderr, "%s: error reading string table\n", a_outname );
195*4510Speter 	done();
196*4510Speter     }
197*4510Speter }
198*4510Speter 
199*4510Speter     /*
200*4510Speter      * Read in symbol table
201*4510Speter      */
202*4510Speter getsymtab(nfile)
203*4510Speter     FILE	*nfile;
204*4510Speter {
205*4510Speter     register long	i;
206*4510Speter     int			askfor;
207*4510Speter     struct nlist	nbuf;
208*4510Speter 
209*4510Speter     /* pass1 - count symbols */
210*4510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
211*4510Speter     nname = 0;
212*4510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
213*4510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
214*4510Speter 	if ( nbuf.n_type != N_TEXT+N_EXT ) {
215*4510Speter 	    continue;
216*4510Speter 	}
217*4510Speter 	nname++;
218*4510Speter     }
219*4510Speter     if (nname == 0) {
220*4510Speter 	fprintf(stderr, "%s: no symbols\n", a_outname );
221*4510Speter 	done();
222*4510Speter     }
223*4510Speter 	/*
224*4510Speter 	 *	ask also for CYCLEFRACTION extra namelist entries for
225*4510Speter 	 *	cycle entries.  these hide out at the end of the namelist
226*4510Speter 	 *	and aren't accessed unless the whole namelist (nname+ncycles)
227*4510Speter 	 *	is sorted and searched.
228*4510Speter 	 */
229*4510Speter     ncycles = nname * CYCLEFRACTION;
230*4510Speter     askfor = nname + 1 + ncycles;
231*4510Speter     nl = (nltype *) calloc( askfor , sizeof(nltype) );
232*4510Speter     if (nl == 0) {
233*4510Speter 	fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
234*4510Speter 		askfor * sizeof(nltype) );
235*4510Speter 	done();
236*4510Speter     }
237*4510Speter 
238*4510Speter     /* pass2 - read symbols */
239*4510Speter     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
240*4510Speter     npe = nl;
241*4510Speter     nname = 0;
242*4510Speter     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
243*4510Speter 	fread(&nbuf, sizeof(nbuf), 1, nfile);
244*4510Speter 	if ( nbuf.n_type != N_TEXT+N_EXT ) {
245*4510Speter 	    continue;
246*4510Speter 	}
247*4510Speter 	npe->value = nbuf.n_value;
248*4510Speter 	npe->name = strtab+nbuf.n_un.n_strx;
249*4510Speter #	ifdef DEBUG
250*4510Speter 	    if ( debug & AOUTDEBUG ) {
251*4510Speter 		printf( "[getsymtab] %d %s 0x%08x\n" ,
252*4510Speter 			nname , npe -> name , npe -> value );
253*4510Speter 	    }
254*4510Speter #	endif DEBUG
255*4510Speter 	npe++;
256*4510Speter 	nname++;
257*4510Speter     }
258*4510Speter     npe->value = -1;
259*4510Speter     npe++;
260*4510Speter }
261*4510Speter 
262*4510Speter     /*
263*4510Speter      *	information from a dmon.out file is in two parts:
264*4510Speter      *	an array of sampling hits within pc ranges,
265*4510Speter      *	and the arcs.
266*4510Speter      */
267*4510Speter getpfile(filename)
268*4510Speter     char *filename;
269*4510Speter {
270*4510Speter     FILE		*pfile;
271*4510Speter     FILE		*openpfile();
272*4510Speter     struct rawarc	arc;
273*4510Speter 
274*4510Speter     pfile = openpfile(filename);
275*4510Speter     readsamples(pfile);
276*4510Speter 	/*
277*4510Speter 	 *	the rest of the file consists of
278*4510Speter 	 *	a bunch of <from,self,count> tuples.
279*4510Speter 	 */
280*4510Speter     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
281*4510Speter #	ifdef DEBUG
282*4510Speter 	    if ( debug & SAMPLEDEBUG ) {
283*4510Speter 		printf( "[getpfile] frompc %d selfpc %d count %d\n" ,
284*4510Speter 			arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
285*4510Speter 	    }
286*4510Speter #	endif DEBUG
287*4510Speter 	    /*
288*4510Speter 	     *	add this arc
289*4510Speter 	     */
290*4510Speter 	tally( &arc );
291*4510Speter     }
292*4510Speter     fclose(pfile);
293*4510Speter }
294*4510Speter 
295*4510Speter FILE *openpfile(filename)
296*4510Speter     char *filename;
297*4510Speter {
298*4510Speter     FILE	*pfile;
299*4510Speter 
300*4510Speter     if((pfile = fopen(filename, "r")) == NULL) {
301*4510Speter 	perror(filename);
302*4510Speter 	done();
303*4510Speter     }
304*4510Speter     fread(&h, sizeof(struct hdr), 1, pfile);
305*4510Speter     lowpc = h.lowpc - (UNIT *)0;
306*4510Speter     highpc = h.highpc - (UNIT *)0;
307*4510Speter     sampbytes = h.ncnt - sizeof(struct hdr);
308*4510Speter     nsamples = sampbytes / sizeof (unsigned UNIT);
309*4510Speter     return(pfile);
310*4510Speter }
311*4510Speter 
312*4510Speter tally( rawp )
313*4510Speter     struct rawarc	*rawp;
314*4510Speter {
315*4510Speter     nltype		*parentp;
316*4510Speter     nltype		*childp;
317*4510Speter     arctype		*arcp;
318*4510Speter     arctype		*malloc();
319*4510Speter 
320*4510Speter     parentp = nllookup( rawp -> raw_frompc );
321*4510Speter     childp = nllookup( rawp -> raw_selfpc );
322*4510Speter     childp -> ncall += rawp -> raw_count;
323*4510Speter #   ifdef DEBUG
324*4510Speter 	if ( debug & TALLYDEBUG ) {
325*4510Speter 	    printf( "[tally] arc from %s to %s traversed %d times\n" ,
326*4510Speter 		    parentp -> name , childp -> name , rawp -> raw_count );
327*4510Speter 	}
328*4510Speter #   endif DEBUG
329*4510Speter     arcp = arclookup( parentp , childp );
330*4510Speter     if ( arcp != 0 ) {
331*4510Speter 	    /*
332*4510Speter 	     *	a hit:  just increment the count.
333*4510Speter 	     */
334*4510Speter #	ifdef DEBUG
335*4510Speter 	    if ( debug & TALLYDEBUG ) {
336*4510Speter 		printf( "[tally] hit %d += %d\n" ,
337*4510Speter 			arcp -> arc_count , rawp -> raw_count );
338*4510Speter 	    }
339*4510Speter #	endif DEBUG
340*4510Speter 	arcp -> arc_count += rawp -> raw_count;
341*4510Speter 	return;
342*4510Speter     }
343*4510Speter     arcp = malloc( sizeof *arcp );
344*4510Speter     arcp -> arc_parentp = parentp;
345*4510Speter     arcp -> arc_childp = childp;
346*4510Speter     arcp -> arc_count = rawp -> raw_count;
347*4510Speter 	/*
348*4510Speter 	 *	prepend this child to the children of this parent
349*4510Speter 	 */
350*4510Speter     arcp -> arc_childlist = parentp -> children;
351*4510Speter     parentp -> children = arcp;
352*4510Speter 	/*
353*4510Speter 	 *	prepend this parent to the parents of this child
354*4510Speter 	 */
355*4510Speter     arcp -> arc_parentlist = childp -> parents;
356*4510Speter     childp -> parents = arcp;
357*4510Speter }
358*4510Speter 
359*4510Speter valcmp(p1, p2)
360*4510Speter     nltype *p1, *p2;
361*4510Speter {
362*4510Speter     if ( p1 -> value < p2 -> value ) {
363*4510Speter 	return LESSTHAN;
364*4510Speter     }
365*4510Speter     if ( p1 -> value > p2 -> value ) {
366*4510Speter 	return GREATERTHAN;
367*4510Speter     }
368*4510Speter     return EQUALTO;
369*4510Speter }
370*4510Speter 
371*4510Speter readsamples(pfile)
372*4510Speter     FILE	*pfile;
373*4510Speter {
374*4510Speter     register i;
375*4510Speter     unsigned UNIT	sample;
376*4510Speter 
377*4510Speter     if (samples == 0) {
378*4510Speter 	samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
379*4510Speter 	if (samples == 0) {
380*4510Speter 	    fprintf( stderr , "prof: No room for %d sample pc's\n",
381*4510Speter 		sampbytes / sizeof (unsigned UNIT));
382*4510Speter 	    done();
383*4510Speter 	}
384*4510Speter     }
385*4510Speter     for (i = 0; i < nsamples; i++) {
386*4510Speter 	fread(&sample, sizeof (unsigned UNIT), 1, pfile);
387*4510Speter 	if (feof(pfile))
388*4510Speter 		break;
389*4510Speter 	samples[i] += sample;
390*4510Speter     }
391*4510Speter     if (i != nsamples) {
392*4510Speter 	fprintf(stderr,
393*4510Speter 	    "prof: unexpected EOF after reading %d/%d samples\n",
394*4510Speter 		--i, nsamples);
395*4510Speter 	done();
396*4510Speter     }
397*4510Speter }
398*4510Speter 
399*4510Speter /*
400*4510Speter  * Assign samples to the procedures to which they belong.
401*4510Speter  */
402*4510Speter asgnsamples()
403*4510Speter {
404*4510Speter     register int	j;
405*4510Speter     unsigned UNIT	ccnt;
406*4510Speter     double		time;
407*4510Speter     unsigned long	pcl, pch;
408*4510Speter     register int	i;
409*4510Speter     int			overlap;
410*4510Speter     unsigned long	svalue0, svalue1;
411*4510Speter 
412*4510Speter     /* read samples and assign to namelist symbols */
413*4510Speter     scale = highpc - lowpc;
414*4510Speter     scale /= nsamples;
415*4510Speter     for (i=0; i < nsamples; i++) {
416*4510Speter 	ccnt = samples[i];
417*4510Speter 	if (ccnt == 0)
418*4510Speter 		continue;
419*4510Speter 	pcl = lowpc + scale*i;
420*4510Speter 	pch = lowpc + scale*(i+1);
421*4510Speter 	time = ccnt;
422*4510Speter #	ifdef DEBUG
423*4510Speter 	    if ( debug & SAMPLEDEBUG ) {
424*4510Speter 		printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
425*4510Speter 			ccnt , time , totime );
426*4510Speter 	    }
427*4510Speter #	endif DEBUG
428*4510Speter 	totime += time;
429*4510Speter 	for (j=0; j<nname; j++) {
430*4510Speter 	    svalue0 = nl[j].value / sizeof(UNIT);
431*4510Speter 	    svalue1 = nl[j+1].value / sizeof(UNIT);
432*4510Speter 	    if (pch < svalue0)
433*4510Speter 		    break;
434*4510Speter 	    if (pcl >= svalue1)
435*4510Speter 		    continue;
436*4510Speter 	    overlap=min(pch,svalue1) - max(pcl,svalue0);
437*4510Speter 	    if (overlap>0) {
438*4510Speter #		ifdef DEBUG
439*4510Speter 		    if ( debug & SAMPLEDEBUG ) {
440*4510Speter 			printf( "[asgnsamples] %s gets %f ticks\n" ,
441*4510Speter 				nl[j].name , overlap*time/scale );
442*4510Speter 		    }
443*4510Speter #		endif DEBUG
444*4510Speter 		nl[j].time += overlap*time/scale;
445*4510Speter 	    }
446*4510Speter 	}
447*4510Speter     }
448*4510Speter #   ifdef DEBUG
449*4510Speter 	if ( debug & SAMPLEDEBUG ) {
450*4510Speter 	    printf( "[asgnsamples] totime %f\n" , totime );
451*4510Speter 	}
452*4510Speter #   endif DEBUG
453*4510Speter     if (totime==0.0) {
454*4510Speter 	fprintf( stderr , "No time accumulated\n" );
455*4510Speter 	totime=1.0;
456*4510Speter     }
457*4510Speter }
458*4510Speter 
459*4510Speter 
460*4510Speter min(a, b)
461*4510Speter     unsigned a,b;
462*4510Speter {
463*4510Speter     if (a<b)
464*4510Speter 	return(a);
465*4510Speter     return(b);
466*4510Speter }
467*4510Speter 
468*4510Speter max(a, b)
469*4510Speter     unsigned a,b;
470*4510Speter {
471*4510Speter     if (a>b)
472*4510Speter 	return(a);
473*4510Speter     return(b);
474*4510Speter }
475*4510Speter 
476*4510Speter timecmp( npp1 , npp2 )
477*4510Speter     nltype **npp1, **npp2;
478*4510Speter {
479*4510Speter     double d;
480*4510Speter 
481*4510Speter     d = (*npp2)->time - (*npp1)->time;
482*4510Speter     if (d > 0.0)
483*4510Speter 	return(1);
484*4510Speter     if (d < 0.0)
485*4510Speter 	return(-1);
486*4510Speter     return(strcmp((*npp1)->name,(*npp2)->name));
487*4510Speter }
488*4510Speter 
489*4510Speter done()
490*4510Speter {
491*4510Speter 
492*4510Speter     exit(0);
493*4510Speter }
494