xref: /csrg-svn/usr.bin/gprof/printgprof.c (revision 7222)
1 #ifndef lint
2     static	char *sccsid = "@(#)printgprof.c	1.10 (Berkeley) 06/18/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 -> propself + np -> propchild ) / printtime ,
115 	    np -> propself / HZ ,
116 	    np -> propchild / 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 propself + propchild.
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 -> propself == 0 &&
167 	     parentp -> propchild == 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 propagated time
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 -> propself + np1 -> propchild )
208 	    - ( np2 -> propself + np2 -> propchild );
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     if ( np1 -> ncall > np2 -> ncall )
226 	return -1;
227     if ( np1 -> ncall < np2 -> ncall )
228 	return 1;
229     return strcmp( np1 -> name , np2 -> name );
230 }
231 
232 printparents( childp )
233     nltype	*childp;
234 {
235     nltype	*parentp;
236     arctype	*arcp;
237     nltype	*cycleheadp;
238 
239     if ( childp -> cyclehead != 0 ) {
240 	cycleheadp = childp -> cyclehead;
241     } else {
242 	cycleheadp = childp;
243     }
244     if ( childp -> parents == 0 ) {
245 	printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
246 		"" , "" , "" , "" , "" , "" );
247 	return;
248     }
249     sortparents( childp );
250     for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
251 	parentp = arcp -> arc_parentp;
252 	if ( childp == parentp ||
253 	     ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
254 		/*
255 		 *	selfcall or call among siblings
256 		 */
257 	    printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
258 		    "" , "" , "" , "" ,
259 		    arcp -> arc_count , "" );
260 	    printname( parentp );
261 	    printf( "\n" );
262 	} else {
263 		/*
264 		 *	regular parent of child
265 		 */
266 	    printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
267 		    "" , "" ,
268 		    arcp -> arc_time / HZ , arcp -> arc_childtime / HZ ,
269 		    arcp -> arc_count , cycleheadp -> ncall );
270 	    printname( parentp );
271 	    printf( "\n" );
272 	}
273     }
274 }
275 
276 printchildren( parentp )
277     nltype	*parentp;
278 {
279     nltype	*childp;
280     arctype	*arcp;
281 
282     sortchildren( parentp );
283     arcp = parentp -> children;
284     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
285 	childp = arcp -> arc_childp;
286 	if ( childp == parentp ||
287 	    ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
288 		/*
289 		 *	self call or call to sibling
290 		 */
291 	    printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
292 		    "" , "" , "" , "" , arcp -> arc_count , "" );
293 	    printname( childp );
294 	    printf( "\n" );
295 	} else {
296 		/*
297 		 *	regular child of parent
298 		 */
299 	    printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
300 		    "" , "" ,
301 		    arcp -> arc_time / HZ , arcp -> arc_childtime / HZ ,
302 		    arcp -> arc_count , childp -> cyclehead -> ncall );
303 	    printname( childp );
304 	    printf( "\n" );
305 	}
306     }
307 }
308 
309 printname( selfp )
310     nltype	*selfp;
311 {
312 
313     if ( selfp -> name != 0 ) {
314 	printf( "%s" , selfp -> name );
315 #	ifdef DEBUG
316 	    if ( debug & DFNDEBUG ) {
317 		printf( "{%d} " , selfp -> toporder );
318 	    }
319 	    if ( debug & PROPDEBUG ) {
320 		printf( "%5.2f%% " , selfp -> propfraction );
321 	    }
322 #	endif DEBUG
323     }
324     if ( selfp -> cycleno != 0 ) {
325 	printf( "\t<cycle %d>" , selfp -> cycleno );
326     }
327     if ( selfp -> index != 0 ) {
328 	if ( selfp -> printflag ) {
329 	    printf( " [%d]" , selfp -> index );
330 	} else {
331 	    printf( " (%d)" , selfp -> index );
332 	}
333     }
334 }
335 
336 sortchildren( parentp )
337     nltype	*parentp;
338 {
339     arctype	*arcp;
340     arctype	*detachedp;
341     arctype	sorted;
342     arctype	*prevp;
343 
344 	/*
345 	 *	unlink children from parent,
346 	 *	then insertion sort back on to sorted's children.
347 	 *	    *arcp	the arc you have detached and are inserting.
348 	 *	    *detachedp	the rest of the arcs to be sorted.
349 	 *	    sorted	arc list onto which you insertion sort.
350 	 *	    *prevp	arc before the arc you are comparing.
351 	 */
352     sorted.arc_childlist = 0;
353     for (   arcp = parentp -> children , detachedp = arcp -> arc_childlist ;
354 	    arcp ;
355 	    arcp = detachedp , detachedp = detachedp -> arc_childlist ) {
356 	    /*
357 	     *	consider *arcp as disconnected
358 	     *	insert it into sorted
359 	     */
360 	for (   prevp = &sorted ;
361 		prevp -> arc_childlist ;
362 		prevp = prevp -> arc_childlist ) {
363 	    if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
364 		break;
365 	    }
366 	}
367 	arcp -> arc_childlist = prevp -> arc_childlist;
368 	prevp -> arc_childlist = arcp;
369     }
370 	/*
371 	 *	reattach sorted children to parent
372 	 */
373     parentp -> children = sorted.arc_childlist;
374 }
375 
376 sortparents( childp )
377     nltype	*childp;
378 {
379     arctype	*arcp;
380     arctype	*detachedp;
381     arctype	sorted;
382     arctype	*prevp;
383 
384 	/*
385 	 *	unlink parents from child,
386 	 *	then insertion sort back on to sorted's parents.
387 	 *	    *arcp	the arc you have detached and are inserting.
388 	 *	    *detachedp	the rest of the arcs to be sorted.
389 	 *	    sorted	arc list onto which you insertion sort.
390 	 *	    *prevp	arc before the arc you are comparing.
391 	 */
392     sorted.arc_parentlist = 0;
393     for (   arcp = childp -> parents , detachedp = arcp -> arc_parentlist ;
394 	    arcp ;
395 	    arcp = detachedp , detachedp = detachedp -> arc_parentlist ) {
396 	    /*
397 	     *	consider *arcp as disconnected
398 	     *	insert it into sorted
399 	     */
400 	for (   prevp = &sorted ;
401 		prevp -> arc_parentlist ;
402 		prevp = prevp -> arc_parentlist ) {
403 	    if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
404 		break;
405 	    }
406 	}
407 	arcp -> arc_parentlist = prevp -> arc_parentlist;
408 	prevp -> arc_parentlist = arcp;
409     }
410 	/*
411 	 *	reattach sorted arcs to child
412 	 */
413     childp -> parents = sorted.arc_parentlist;
414 }
415 
416     /*
417      *	print a cycle header
418      */
419 printcycle( cyclep )
420     nltype	*cyclep;
421 {
422     char	kirkbuffer[ BUFSIZ ];
423 
424     sprintf( kirkbuffer , "[%d]" , cyclep -> index );
425     printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
426 	    kirkbuffer ,
427 	    100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
428 	    cyclep -> propself / HZ ,
429 	    cyclep -> propchild / HZ ,
430 	    cyclep -> ncall );
431     if ( cyclep -> selfcalls != 0 ) {
432 	printf( "+%-7d" , cyclep -> selfcalls );
433     } else {
434 	printf( " %7.7s" , "" );
435     }
436     printf( " <cycle %d as a whole>\t[%d]\n" ,
437 	    cyclep -> cycleno , cyclep -> index );
438 }
439 
440     /*
441      *	print the members of a cycle
442      */
443 printmembers( cyclep )
444     nltype	*cyclep;
445 {
446     nltype	*memberp;
447 
448     sortmembers( cyclep );
449     for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
450 	printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
451 		"" , "" , memberp -> propself / HZ , memberp -> propchild / HZ ,
452 		memberp -> ncall );
453 	if ( memberp -> selfcalls != 0 ) {
454 	    printf( "+%-7d" , memberp -> selfcalls );
455 	} else {
456 	    printf( " %7.7s" , "" );
457 	}
458 	printf( "     " );
459 	printname( memberp );
460 	printf( "\n" );
461     }
462 }
463 
464     /*
465      *	sort members of a cycle
466      */
467 sortmembers( cyclep )
468     nltype	*cyclep;
469 {
470     nltype	*todo;
471     nltype	*doing;
472     nltype	*prev;
473 
474 	/*
475 	 *	detach cycle members from cyclehead,
476 	 *	and insertion sort them back on.
477 	 */
478     todo = cyclep -> cnext;
479     cyclep -> cnext = 0;
480     for (   doing = todo , todo = doing -> cnext ;
481 	    doing ;
482 	    doing = todo , todo = doing -> cnext ) {
483 	for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
484 	    if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
485 		break;
486 	    }
487 	}
488 	doing -> cnext = prev -> cnext;
489 	prev -> cnext = doing;
490     }
491 }
492 
493     /*
494      *	major sort is on propself + propchild,
495      *	next is sort on ncalls + selfcalls.
496      */
497 int
498 membercmp( this , that )
499     nltype	*this;
500     nltype	*that;
501 {
502     double	thistime = this -> propself + this -> propchild;
503     double	thattime = that -> propself + that -> propchild;
504     long	thiscalls = this -> ncall + this -> selfcalls;
505     long	thatcalls = that -> ncall + that -> selfcalls;
506 
507     if ( thistime > thattime ) {
508 	return GREATERTHAN;
509     }
510     if ( thistime < thattime ) {
511 	return LESSTHAN;
512     }
513     if ( thiscalls > thatcalls ) {
514 	return GREATERTHAN;
515     }
516     if ( thiscalls < thatcalls ) {
517 	return LESSTHAN;
518     }
519     return EQUALTO;
520 }
521     /*
522      *	compare two arcs to/from the same child/parent.
523      *	- if one arc is a self arc, it's least.
524      *	- if one arc is within a cycle, it's less than.
525      *	- if both arcs are within a cycle, compare arc counts.
526      *	- if neither arc is within a cycle, compare with
527      *		arc_time + arc_childtime as major key
528      *		arc count as minor key
529      */
530 int
531 arccmp( thisp , thatp )
532     arctype	*thisp;
533     arctype	*thatp;
534 {
535     nltype	*thisparentp = thisp -> arc_parentp;
536     nltype	*thischildp = thisp -> arc_childp;
537     nltype	*thatparentp = thatp -> arc_parentp;
538     nltype	*thatchildp = thatp -> arc_childp;
539     double	thistime;
540     double	thattime;
541 
542 #   ifdef DEBUG
543 	if ( debug & TIMEDEBUG ) {
544 	    printf( "[arccmp] " );
545 	    printname( thisparentp );
546 	    printf( " calls " );
547 	    printname ( thischildp );
548 	    printf( " %f + %f %d/%d\n" ,
549 		    thisp -> arc_time , thisp -> arc_childtime ,
550 		    thisp -> arc_count , thischildp -> ncall );
551 	    printf( "[arccmp] " );
552 	    printname( thatparentp );
553 	    printf( " calls " );
554 	    printname( thatchildp );
555 	    printf( " %f + %f %d/%d\n" ,
556 		    thatp -> arc_time , thatp -> arc_childtime ,
557 		    thatp -> arc_count , thatchildp -> ncall );
558 	    printf( "\n" );
559 	}
560 #   endif DEBUG
561     if ( thisparentp == thischildp ) {
562 	    /* this is a self call */
563 	return LESSTHAN;
564     }
565     if ( thatparentp == thatchildp ) {
566 	    /* that is a self call */
567 	return GREATERTHAN;
568     }
569     if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
570 	thisparentp -> cycleno == thischildp -> cycleno ) {
571 	    /* this is a call within a cycle */
572 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
573 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
574 		/* that is a call within the cycle, too */
575 	    if ( thisp -> arc_count < thatp -> arc_count ) {
576 		return LESSTHAN;
577 	    }
578 	    if ( thisp -> arc_count > thatp -> arc_count ) {
579 		return GREATERTHAN;
580 	    }
581 	    return EQUALTO;
582 	} else {
583 		/* that isn't a call within the cycle */
584 	    return LESSTHAN;
585 	}
586     } else {
587 	    /* this isn't a call within a cycle */
588 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
589 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
590 		/* that is a call within a cycle */
591 	    return GREATERTHAN;
592 	} else {
593 		/* neither is a call within a cycle */
594 	    thistime = thisp -> arc_time + thisp -> arc_childtime;
595 	    thattime = thatp -> arc_time + thatp -> arc_childtime;
596 	    if ( thistime < thattime )
597 		return LESSTHAN;
598 	    if ( thistime > thattime )
599 		return GREATERTHAN;
600 	    if ( thisp -> arc_count < thatp -> arc_count )
601 		return LESSTHAN;
602 	    if ( thisp -> arc_count > thatp -> arc_count )
603 		return GREATERTHAN;
604 	    return EQUALTO;
605 	}
606     }
607 }
608 
609 printblurb( blurbname )
610     char	*blurbname;
611 {
612     char	pathname[ BUFSIZ ];
613     FILE	*blurbfile;
614     int		input;
615 
616     sprintf( pathname , "%s%s" , BLURBLIB , blurbname );
617     blurbfile = fopen( pathname , "r" );
618     if ( blurbfile == NULL ) {
619 	perror( pathname );
620 	return;
621     }
622     while ( ( input = getc( blurbfile ) ) != EOF ) {
623 	putchar( input );
624     }
625     fclose( blurbfile );
626 }
627