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