xref: /csrg-svn/usr.bin/gprof/printgprof.c (revision 7172)
1 #ifndef lint
2     static	char *sccsid = "@(#)printgprof.c	1.9 (Berkeley) 06/14/82";
3 #endif lint
4 
5 #include "gprof.h"
6 
7 printprof()
8 {
9     register nltype	*np;
10     nltype		**sortednlp;
11     int			index;
12 
13     printf( "\ngranularity: each sample hit covers %d byte(s)" ,
14 	    (long) scale * sizeof(UNIT) );
15     printf( " for %.2f%% of %.2f seconds\n\n" , 100.0/totime , totime / HZ );
16     actime = 0.0;
17     flatprofheader();
18 	/*
19 	 *	Sort the symbol table in by time
20 	 */
21     sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
22     if ( sortednlp == (nltype **) 0 ) {
23 	fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
24     }
25     for ( index = 0 ; index < nname ; index += 1 ) {
26 	sortednlp[ index ] = &nl[ index ];
27     }
28     qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
29     for ( index = 0 ; index < nname ; index += 1 ) {
30 	np = sortednlp[ index ];
31 	flatprofline( np );
32     }
33     actime = 0.0;
34 }
35 
36 timecmp( npp1 , npp2 )
37     nltype **npp1, **npp2;
38 {
39     double	timediff;
40     long	calldiff;
41 
42     timediff = (*npp2) -> time - (*npp1) -> time;
43     if ( timediff > 0.0 )
44 	return 1 ;
45     if ( timediff < 0.0 )
46 	return -1;
47     calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
48     if ( calldiff > 0 )
49 	return 1;
50     if ( calldiff < 0 )
51 	return -1;
52     return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
53 }
54 
55     /*
56      *	header for flatprofline
57      */
58 flatprofheader()
59 {
60 
61     if ( bflag ) {
62 	printblurb( "flat.blurb" );
63     }
64     printf( "%5.5s %7.7s %7.7s %7.7s %-8.8s\n" ,
65 	    "%time" , "cumsecs" , "seconds" , "calls" , "name" );
66 }
67 
68 flatprofline( np )
69     register nltype	*np;
70 {
71 
72     if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) {
73 	return;
74     }
75     actime += np -> time;
76     printf( "%5.1f %7.2f %7.2f" ,
77 	100 * np -> time / totime , actime / HZ , np -> time / HZ );
78     if ( np -> ncall != 0 ) {
79 	printf( " %7d" , np -> ncall );
80     } else {
81 	printf( " %7.7s" , "" );
82     }
83     printf( " %s\n" , np -> name );
84 }
85 
86 gprofheader()
87 {
88 
89     if ( bflag ) {
90 	printblurb( "callg.blurb" );
91     }
92     printf( "\ngranularity: each sample hit covers %d byte(s)" ,
93 	    (long) scale * sizeof(UNIT) );
94     printf( " for %.2f%% of %.2f seconds\n\n" ,
95 	    100.0/printtime , printtime / HZ );
96     printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
97 	"" , "" , "" , "" , "called" , "total" , "parents" , "" );
98     printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
99 	"index" , "%time" , "self" , "descendents" ,
100 	"called" , "self" , "name" , "index" );
101     printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
102 	"" , "" , "" , "" , "called" , "total" , "children" , "" );
103     printf( "\n" );
104 }
105 
106 gprofline( np )
107     register nltype	*np;
108 {
109     char	kirkbuffer[ BUFSIZ ];
110 
111     sprintf( kirkbuffer , "[%d]" , np -> index );
112     printf( "%-6.6s %5.1f %7.2f %11.2f" ,
113 	    kirkbuffer ,
114 	    100 * ( np -> time + np -> childtime ) / printtime ,
115 	    np -> time / HZ ,
116 	    np -> childtime / HZ );
117     if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
118 	printf( " %7d" , np -> ncall );
119 	if ( np -> selfcalls != 0 ) {
120 	    printf( "+%-7d " , np -> selfcalls );
121 	} else {
122 	    printf( " %7.7s " , "" );
123 	}
124     } else {
125 	printf( " %7.7s %7.7s " , "" , "" );
126     }
127     printname( np );
128     printf( "\n" );
129 }
130 
131 printgprof()
132 {
133     nltype	**timesortnlp;
134     int		index;
135     nltype	*parentp;
136 
137 	/*
138 	 *	Now, sort by time + childtime.
139 	 *	sorting both the regular function names
140 	 *	and cycle headers.
141 	 */
142     timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
143     if ( timesortnlp == (nltype **) 0 ) {
144 	fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
145     }
146     for ( index = 0 ; index < nname ; index++ ) {
147 	timesortnlp[index] = &nl[index];
148     }
149     for ( index = 1 ; index <= ncycle ; index++ ) {
150 	timesortnlp[nname+index-1] = &cyclenl[index];
151     }
152     qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
153     for ( index = 0 ; index < nname + ncycle ; index++ ) {
154 	timesortnlp[ index ] -> index = index + 1;
155     }
156 	/*
157 	 *	Now, print out the structured profiling list
158 	 */
159     printf( "\f\n" );
160     gprofheader();
161     for ( index = 0 ; index < nname + ncycle ; index ++ ) {
162 	parentp = timesortnlp[ index ];
163 	if ( zflag == 0 &&
164 	     parentp -> ncall == 0 &&
165 	     parentp -> selfcalls == 0 &&
166 	     parentp -> time == 0 &&
167 	     parentp -> childtime == 0 ) {
168 	    continue;
169 	}
170 	if ( ! parentp -> printflag ) {
171 	    continue;
172 	}
173 	if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
174 		/*
175 		 *	cycle header
176 		 */
177 	    printcycle( parentp );
178 	    printmembers( parentp );
179 	} else {
180 	    printparents( parentp );
181 	    gprofline( parentp );
182 	    printchildren( parentp );
183 	}
184 	printf( "\n" );
185 	printf( "-----------------------------------------------\n" );
186 	printf( "\n" );
187     }
188 }
189 
190     /*
191      *	sort by decreasing total time (time+childtime)
192      *	if times are equal, but one is a cycle header,
193      *		say that's first (e.g. less, i.e. -1).
194      *	if one's name doesn't have an underscore and the other does,
195      *		say the one is first.
196      *	all else being equal, sort by names.
197      */
198 int
199 totalcmp( npp1 , npp2 )
200     nltype	**npp1;
201     nltype	**npp2;
202 {
203     register nltype	*np1 = *npp1;
204     register nltype	*np2 = *npp2;
205     double		diff;
206 
207     diff =    ( np1 -> time + np1 -> childtime )
208 	    - ( np2 -> time + np2 -> childtime );
209     if ( diff < 0.0 )
210 	    return 1;
211     if ( diff > 0.0 )
212 	    return -1;
213     if ( np1 -> name == 0 && np1 -> cycleno != 0 )
214 	return -1;
215     if ( np2 -> name == 0 && np2 -> cycleno != 0 )
216 	return 1;
217     if ( np1 -> name == 0 )
218 	return -1;
219     if ( np2 -> name == 0 )
220 	return 1;
221     if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
222 	return -1;
223     if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
224 	return 1;
225     return strcmp( np1 -> name , np2 -> name );
226 }
227 
228 printparents( childp )
229     nltype	*childp;
230 {
231     nltype	*parentp;
232     arctype	*arcp;
233     nltype	*cycleheadp;
234 
235     if ( childp -> cyclehead != 0 ) {
236 	cycleheadp = childp -> cyclehead;
237     } else {
238 	cycleheadp = childp;
239     }
240     if ( childp -> parents == 0 ) {
241 	printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
242 		"" , "" , "" , "" , "" , "" );
243 	return;
244     }
245     sortparents( childp );
246     for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
247 	parentp = arcp -> arc_parentp;
248 	if ( childp == parentp ||
249 	     ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
250 		/*
251 		 *	selfcall or call among siblings
252 		 */
253 	    printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
254 		    "" , "" , "" , "" ,
255 		    arcp -> arc_count , "" );
256 	    printname( parentp );
257 	    printf( "\n" );
258 	} else {
259 		/*
260 		 *	regular parent of child
261 		 */
262 	    printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
263 		    "" , "" ,
264 		    arcp -> arc_time / HZ , arcp -> arc_childtime / HZ ,
265 		    arcp -> arc_count , cycleheadp -> ncall );
266 	    printname( parentp );
267 	    printf( "\n" );
268 	}
269     }
270 }
271 
272 printchildren( parentp )
273     nltype	*parentp;
274 {
275     nltype	*childp;
276     arctype	*arcp;
277 
278     sortchildren( parentp );
279     arcp = parentp -> children;
280     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
281 	childp = arcp -> arc_childp;
282 	if ( childp == parentp ||
283 	    ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
284 		/*
285 		 *	self call or call to sibling
286 		 */
287 	    printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
288 		    "" , "" , "" , "" , arcp -> arc_count , "" );
289 	    printname( childp );
290 	    printf( "\n" );
291 	} else {
292 		/*
293 		 *	regular child of parent
294 		 */
295 	    printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
296 		    "" , "" ,
297 		    arcp -> arc_time / HZ , arcp -> arc_childtime / HZ ,
298 		    arcp -> arc_count , childp -> cyclehead -> ncall );
299 	    printname( childp );
300 	    printf( "\n" );
301 	}
302     }
303 }
304 
305 printname( selfp )
306     nltype	*selfp;
307 {
308 
309     if ( selfp -> name != 0 ) {
310 	printf( "%s" , selfp -> name );
311 #	ifdef DEBUG
312 	    if ( debug & DFNDEBUG ) {
313 		printf( "{%d} " , selfp -> toporder );
314 	    }
315 #	endif DEBUG
316     }
317     if ( selfp -> cycleno != 0 ) {
318 	printf( "\t<cycle %d>" , selfp -> cycleno );
319     }
320     if ( selfp -> index != 0 ) {
321 	if ( selfp -> printflag ) {
322 	    printf( " [%d]" , selfp -> index );
323 	} else {
324 	    printf( " (%d)" , selfp -> index );
325 	}
326     }
327 }
328 
329 sortchildren( parentp )
330     nltype	*parentp;
331 {
332     arctype	*arcp;
333     arctype	*detachedp;
334     arctype	sorted;
335     arctype	*prevp;
336 
337 	/*
338 	 *	unlink children from parent,
339 	 *	then insertion sort back on to sorted's children.
340 	 *	    *arcp	the arc you have detached and are inserting.
341 	 *	    *detachedp	the rest of the arcs to be sorted.
342 	 *	    sorted	arc list onto which you insertion sort.
343 	 *	    *prevp	arc before the arc you are comparing.
344 	 */
345     sorted.arc_childlist = 0;
346     for (   arcp = parentp -> children , detachedp = arcp -> arc_childlist ;
347 	    arcp ;
348 	    arcp = detachedp , detachedp = detachedp -> arc_childlist ) {
349 	    /*
350 	     *	consider *arcp as disconnected
351 	     *	insert it into sorted
352 	     */
353 	for (   prevp = &sorted ;
354 		prevp -> arc_childlist ;
355 		prevp = prevp -> arc_childlist ) {
356 	    if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
357 		break;
358 	    }
359 	}
360 	arcp -> arc_childlist = prevp -> arc_childlist;
361 	prevp -> arc_childlist = arcp;
362     }
363 	/*
364 	 *	reattach sorted children to parent
365 	 */
366     parentp -> children = sorted.arc_childlist;
367 }
368 
369 sortparents( childp )
370     nltype	*childp;
371 {
372     arctype	*arcp;
373     arctype	*detachedp;
374     arctype	sorted;
375     arctype	*prevp;
376 
377 	/*
378 	 *	unlink parents from child,
379 	 *	then insertion sort back on to sorted's parents.
380 	 *	    *arcp	the arc you have detached and are inserting.
381 	 *	    *detachedp	the rest of the arcs to be sorted.
382 	 *	    sorted	arc list onto which you insertion sort.
383 	 *	    *prevp	arc before the arc you are comparing.
384 	 */
385     sorted.arc_parentlist = 0;
386     for (   arcp = childp -> parents , detachedp = arcp -> arc_parentlist ;
387 	    arcp ;
388 	    arcp = detachedp , detachedp = detachedp -> arc_parentlist ) {
389 	    /*
390 	     *	consider *arcp as disconnected
391 	     *	insert it into sorted
392 	     */
393 	for (   prevp = &sorted ;
394 		prevp -> arc_parentlist ;
395 		prevp = prevp -> arc_parentlist ) {
396 	    if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
397 		break;
398 	    }
399 	}
400 	arcp -> arc_parentlist = prevp -> arc_parentlist;
401 	prevp -> arc_parentlist = arcp;
402     }
403 	/*
404 	 *	reattach sorted arcs to child
405 	 */
406     childp -> parents = sorted.arc_parentlist;
407 }
408 
409     /*
410      *	print a cycle header
411      */
412 printcycle( cyclep )
413     nltype	*cyclep;
414 {
415     char	kirkbuffer[ BUFSIZ ];
416 
417     sprintf( kirkbuffer , "[%d]" , cyclep -> index );
418     printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
419 	    kirkbuffer ,
420 	    100 * ( cyclep -> time + cyclep -> childtime ) / printtime ,
421 	    cyclep -> time / HZ ,
422 	    cyclep -> childtime / HZ ,
423 	    cyclep -> ncall );
424     if ( cyclep -> selfcalls != 0 ) {
425 	printf( "+%-7d" , cyclep -> selfcalls );
426     } else {
427 	printf( " %7.7s" , "" );
428     }
429     printf( " <cycle %d as a whole>\t[%d]\n" ,
430 	    cyclep -> cycleno , cyclep -> index );
431 }
432 
433     /*
434      *	print the members of a cycle
435      */
436 printmembers( cyclep )
437     nltype	*cyclep;
438 {
439     nltype	*memberp;
440 
441     sortmembers( cyclep );
442     for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
443 	printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
444 		"" , "" , memberp -> time / HZ , memberp -> childtime / HZ ,
445 		memberp -> ncall );
446 	if ( memberp -> selfcalls != 0 ) {
447 	    printf( "+%-7d" , memberp -> selfcalls );
448 	} else {
449 	    printf( " %7.7s" , "" );
450 	}
451 	printf( "     " );
452 	printname( memberp );
453 	printf( "\n" );
454     }
455 }
456 
457     /*
458      *	sort members of a cycle
459      */
460 sortmembers( cyclep )
461     nltype	*cyclep;
462 {
463     nltype	*todo;
464     nltype	*doing;
465     nltype	*prev;
466 
467 	/*
468 	 *	detach cycle members from cyclehead,
469 	 *	and insertion sort them back on.
470 	 */
471     todo = cyclep -> cnext;
472     cyclep -> cnext = 0;
473     for (   doing = todo , todo = doing -> cnext ;
474 	    doing ;
475 	    doing = todo , todo = doing -> cnext ) {
476 	for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
477 	    if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
478 		break;
479 	    }
480 	}
481 	doing -> cnext = prev -> cnext;
482 	prev -> cnext = doing;
483     }
484 }
485 
486     /*
487      *	major sort is on time + childtime,
488      *	next is sort on ncalls + selfcalls.
489      */
490 int
491 membercmp( this , that )
492     nltype	*this;
493     nltype	*that;
494 {
495     double	thistime = this -> time + this -> childtime;
496     double	thattime = that -> time + that -> childtime;
497     long	thiscalls = this -> ncall + this -> selfcalls;
498     long	thatcalls = that -> ncall + that -> selfcalls;
499 
500     if ( thistime > thattime ) {
501 	return GREATERTHAN;
502     }
503     if ( thistime < thattime ) {
504 	return LESSTHAN;
505     }
506     if ( thiscalls > thatcalls ) {
507 	return GREATERTHAN;
508     }
509     if ( thiscalls < thatcalls ) {
510 	return LESSTHAN;
511     }
512     return EQUALTO;
513 }
514     /*
515      *	compare two arcs to/from the same child/parent.
516      *	- if one arc is a self arc, it's least.
517      *	- if one arc is within a cycle, it's less than.
518      *	- if both arcs are within a cycle, compare arc counts.
519      *	- if neither arc is within a cycle, compare with
520      *		time + childtime as major key
521      *		arc count as minor key
522      */
523 int
524 arccmp( thisp , thatp )
525     arctype	*thisp;
526     arctype	*thatp;
527 {
528     nltype	*thisparentp = thisp -> arc_parentp;
529     nltype	*thischildp = thisp -> arc_childp;
530     nltype	*thatparentp = thatp -> arc_parentp;
531     nltype	*thatchildp = thatp -> arc_childp;
532     double	thistime;
533     double	thattime;
534 
535 #   ifdef DEBUG
536 	if ( debug & TIMEDEBUG ) {
537 	    printf( "[arccmp] " );
538 	    printname( thisparentp );
539 	    printf( " calls " );
540 	    printname ( thischildp );
541 	    printf( " %f + %f %d/%d\n" ,
542 		    thisp -> arc_time , thisp -> arc_childtime ,
543 		    thisp -> arc_count , thischildp -> ncall );
544 	    printf( "[arccmp] " );
545 	    printname( thatparentp );
546 	    printf( " calls " );
547 	    printname( thatchildp );
548 	    printf( " %f + %f %d/%d\n" ,
549 		    thatp -> arc_time , thatp -> arc_childtime ,
550 		    thatp -> arc_count , thatchildp -> ncall );
551 	    printf( "\n" );
552 	}
553 #   endif DEBUG
554     if ( thisparentp == thischildp ) {
555 	    /* this is a self call */
556 	return LESSTHAN;
557     }
558     if ( thatparentp == thatchildp ) {
559 	    /* that is a self call */
560 	return GREATERTHAN;
561     }
562     if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
563 	thisparentp -> cycleno == thischildp -> cycleno ) {
564 	    /* this is a call within a cycle */
565 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
566 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
567 		/* that is a call within the cycle, too */
568 	    if ( thisp -> arc_count < thatp -> arc_count ) {
569 		return LESSTHAN;
570 	    }
571 	    if ( thisp -> arc_count > thatp -> arc_count ) {
572 		return GREATERTHAN;
573 	    }
574 	    return EQUALTO;
575 	} else {
576 		/* that isn't a call within the cycle */
577 	    return LESSTHAN;
578 	}
579     } else {
580 	    /* this isn't a call within a cycle */
581 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
582 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
583 		/* that is a call within a cycle */
584 	    return GREATERTHAN;
585 	} else {
586 		/* neither is a call within a cycle */
587 	    thistime = thisp -> arc_time + thisp -> arc_childtime;
588 	    thattime = thatp -> arc_time + thatp -> arc_childtime;
589 	    if ( thistime < thattime )
590 		return LESSTHAN;
591 	    if ( thistime > thattime )
592 		return GREATERTHAN;
593 	    if ( thisp -> arc_count < thatp -> arc_count )
594 		return LESSTHAN;
595 	    if ( thisp -> arc_count > thatp -> arc_count )
596 		return GREATERTHAN;
597 	    return EQUALTO;
598 	}
599     }
600 }
601 
602 printblurb( blurbname )
603     char	*blurbname;
604 {
605     char	pathname[ BUFSIZ ];
606     FILE	*blurbfile;
607     int		input;
608 
609     sprintf( pathname , "%s%s" , BLURBLIB , blurbname );
610     blurbfile = fopen( pathname , "r" );
611     if ( blurbfile == NULL ) {
612 	perror( pathname );
613 	return;
614     }
615     while ( ( input = getc( blurbfile ) ) != EOF ) {
616 	putchar( input );
617     }
618     fclose( blurbfile );
619 }
620