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