xref: /freebsd/usr.bin/gprof/printgprof.c (revision 1669d8afc64812c8d2d1d147ae1fd42ff441e1b1)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #if 0
35 #ifndef lint
36 static char sccsid[] = "@(#)printgprof.c	8.1 (Berkeley) 6/6/93";
37 #endif /* not lint */
38 #endif
39 
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42 
43 #include <err.h>
44 #include <string.h>
45 
46 #include "gprof.h"
47 #include "pathnames.h"
48 
49 void
50 printprof()
51 {
52     register nltype	*np;
53     nltype		**sortednlp;
54     int			index, timecmp();
55 
56     actime = 0.0;
57     printf( "\f\n" );
58     flatprofheader();
59 	/*
60 	 *	Sort the symbol table in by time
61 	 */
62     sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
63     if ( sortednlp == (nltype **) 0 )
64 	errx( 1 , "[printprof] ran out of memory for time sorting" );
65     for ( index = 0 ; index < nname ; index += 1 ) {
66 	sortednlp[ index ] = &nl[ index ];
67     }
68     qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
69     for ( index = 0 ; index < nname ; index += 1 ) {
70 	np = sortednlp[ index ];
71 	flatprofline( np );
72     }
73     actime = 0.0;
74     free( sortednlp );
75 }
76 
77 int
78 timecmp( npp1 , npp2 )
79     nltype **npp1, **npp2;
80 {
81     double	timediff;
82     long	calldiff;
83 
84     timediff = (*npp2) -> time - (*npp1) -> time;
85     if ( timediff > 0.0 )
86 	return 1 ;
87     if ( timediff < 0.0 )
88 	return -1;
89     calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
90     if ( calldiff > 0 )
91 	return 1;
92     if ( calldiff < 0 )
93 	return -1;
94     return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
95 }
96 
97     /*
98      *	header for flatprofline
99      */
100 void
101 flatprofheader()
102 {
103 
104     if ( bflag ) {
105 	printblurb( _PATH_FLAT_BLURB );
106     }
107     printf( "\ngranularity: each sample hit covers %g byte(s)" ,
108 	    scale * HISTORICAL_SCALE_2 );
109     if ( totime > 0.0 ) {
110 	printf( " for %.2f%% of %.2f seconds\n\n" ,
111 		100.0/totime , totime / hz );
112     } else {
113 	printf( " no time accumulated\n\n" );
114 	    /*
115 	     *	this doesn't hurt since all the numerators will be zero.
116 	     */
117 	totime = 1.0;
118     }
119     printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
120 	    "%  " , "cumulative" , "self  " , "" , "self  " , "total " , "" );
121     printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
122 	    "time" , "seconds " , "seconds" , "calls" ,
123 	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
124 	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
125 	    "name" );
126 }
127 
128 void
129 flatprofline( np )
130     register nltype	*np;
131 {
132 
133     if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 &&
134 	 np -> childtime == 0 ) {
135 	return;
136     }
137     actime += np -> time;
138     if (hz >= 10000)
139 	printf( "%5.1f %10.3f %8.3f" ,
140 	    100 * np -> time / totime , actime / hz , np -> time / hz );
141     else
142 	printf( "%5.1f %10.2f %8.2f" ,
143 	    100 * np -> time / totime , actime / hz , np -> time / hz );
144     if ( np -> ncall != 0 ) {
145 	if (hz >= 10000000)
146 	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
147 		1e9 * np -> time / hz / np -> ncall ,
148 		1e9 * ( np -> time + np -> childtime ) / hz / np -> ncall );
149 	else if (hz >= 10000)
150 	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
151 		1e6 * np -> time / hz / np -> ncall ,
152 		1e6 * ( np -> time + np -> childtime ) / hz / np -> ncall );
153 	else
154 	    printf( " %8ld %8.2f %8.2f  " , np -> ncall ,
155 		1000 * np -> time / hz / np -> ncall ,
156 		1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
157     } else if ( np -> time != 0 || np -> childtime != 0 ) {
158 	printf( " %8ld %7.2f%% %8.8s  " , np -> ncall ,
159 	    100 * np -> time / ( np -> time + np -> childtime ) , "" );
160     } else {
161 	printf( " %8.8s %8.8s %8.8s  " , "" , "" , "" );
162     }
163     printname( np );
164     printf( "\n" );
165 }
166 
167 void
168 gprofheader()
169 {
170 
171     if ( bflag ) {
172 	printblurb( _PATH_CALLG_BLURB );
173     }
174     printf( "\ngranularity: each sample hit covers %g byte(s)" ,
175 	    scale * HISTORICAL_SCALE_2 );
176     if ( printtime > 0.0 ) {
177 	printf( " for %.2f%% of %.2f seconds\n\n" ,
178 		100.0/printtime , printtime / hz );
179     } else {
180 	printf( " no time propagated\n\n" );
181 	    /*
182 	     *	this doesn't hurt, since all the numerators will be 0.0
183 	     */
184 	printtime = 1.0;
185     }
186     printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
187 	"" , "" , "" , "" , "called" , "total" , "parents");
188     printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
189 	"index" , "%time" , "self" , "descendents" ,
190 	"called" , "self" , "name" , "index" );
191     printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
192 	"" , "" , "" , "" , "called" , "total" , "children");
193     printf( "\n" );
194 }
195 
196 void
197 gprofline( np )
198     register nltype	*np;
199 {
200     char	kirkbuffer[ BUFSIZ ];
201 
202     sprintf( kirkbuffer , "[%d]" , np -> index );
203     printf( "%-6.6s %5.1f %7.2f %11.2f" ,
204 	    kirkbuffer ,
205 	    100 * ( np -> propself + np -> propchild ) / printtime ,
206 	    np -> propself / hz ,
207 	    np -> propchild / hz );
208     if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
209 	printf( " %7ld" , np -> npropcall );
210 	if ( np -> selfcalls != 0 ) {
211 	    printf( "+%-7ld " , np -> selfcalls );
212 	} else {
213 	    printf( " %7.7s " , "" );
214 	}
215     } else {
216 	printf( " %7.7s %7.7s " , "" , "" );
217     }
218     printname( np );
219     printf( "\n" );
220 }
221 
222 void
223 printgprof(timesortnlp)
224     nltype	**timesortnlp;
225 {
226     int		index;
227     nltype	*parentp;
228 
229 	/*
230 	 *	Print out the structured profiling list
231 	 */
232     gprofheader();
233     for ( index = 0 ; index < nname + ncycle ; index ++ ) {
234 	parentp = timesortnlp[ index ];
235 	if ( zflag == 0 &&
236 	     parentp -> ncall == 0 &&
237 	     parentp -> selfcalls == 0 &&
238 	     parentp -> propself == 0 &&
239 	     parentp -> propchild == 0 ) {
240 	    continue;
241 	}
242 	if ( ! parentp -> printflag ) {
243 	    continue;
244 	}
245 	if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
246 		/*
247 		 *	cycle header
248 		 */
249 	    printcycle( parentp );
250 	    printmembers( parentp );
251 	} else {
252 	    printparents( parentp );
253 	    gprofline( parentp );
254 	    printchildren( parentp );
255 	}
256 	printf( "\n" );
257 	printf( "-----------------------------------------------\n" );
258 	printf( "\n" );
259     }
260     free( timesortnlp );
261 }
262 
263     /*
264      *	sort by decreasing propagated time
265      *	if times are equal, but one is a cycle header,
266      *		say that's first (e.g. less, i.e. -1).
267      *	if one's name doesn't have an underscore and the other does,
268      *		say the one is first.
269      *	all else being equal, sort by names.
270      */
271 int
272 totalcmp( npp1 , npp2 )
273     nltype	**npp1;
274     nltype	**npp2;
275 {
276     register nltype	*np1 = *npp1;
277     register nltype	*np2 = *npp2;
278     double		diff;
279 
280     diff =    ( np1 -> propself + np1 -> propchild )
281 	    - ( np2 -> propself + np2 -> propchild );
282     if ( diff < 0.0 )
283 	    return 1;
284     if ( diff > 0.0 )
285 	    return -1;
286     if ( np1 -> name == 0 && np1 -> cycleno != 0 )
287 	return -1;
288     if ( np2 -> name == 0 && np2 -> cycleno != 0 )
289 	return 1;
290     if ( np1 -> name == 0 )
291 	return -1;
292     if ( np2 -> name == 0 )
293 	return 1;
294     if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
295 	return -1;
296     if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
297 	return 1;
298     if ( np1 -> ncall > np2 -> ncall )
299 	return -1;
300     if ( np1 -> ncall < np2 -> ncall )
301 	return 1;
302     return strcmp( np1 -> name , np2 -> name );
303 }
304 
305 void
306 printparents( childp )
307     nltype	*childp;
308 {
309     nltype	*parentp;
310     arctype	*arcp;
311     nltype	*cycleheadp;
312 
313     if ( childp -> cyclehead != 0 ) {
314 	cycleheadp = childp -> cyclehead;
315     } else {
316 	cycleheadp = childp;
317     }
318     if ( childp -> parents == 0 ) {
319 	printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
320 		"" , "" , "" , "" , "" , "" );
321 	return;
322     }
323     sortparents( childp );
324     for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
325 	parentp = arcp -> arc_parentp;
326 	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
327 	     ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
328 		/*
329 		 *	selfcall or call among siblings
330 		 */
331 	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
332 		    "" , "" , "" , "" ,
333 		    arcp -> arc_count , "" );
334 	    printname( parentp );
335 	    printf( "\n" );
336 	} else {
337 		/*
338 		 *	regular parent of child
339 		 */
340 	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
341 		    "" , "" ,
342 		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
343 		    arcp -> arc_count , cycleheadp -> npropcall );
344 	    printname( parentp );
345 	    printf( "\n" );
346 	}
347     }
348 }
349 
350 void
351 printchildren( parentp )
352     nltype	*parentp;
353 {
354     nltype	*childp;
355     arctype	*arcp;
356 
357     sortchildren( parentp );
358     arcp = parentp -> children;
359     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
360 	childp = arcp -> arc_childp;
361 	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
362 	    ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
363 		/*
364 		 *	self call or call to sibling
365 		 */
366 	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
367 		    "" , "" , "" , "" , arcp -> arc_count , "" );
368 	    printname( childp );
369 	    printf( "\n" );
370 	} else {
371 		/*
372 		 *	regular child of parent
373 		 */
374 	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
375 		    "" , "" ,
376 		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
377 		    arcp -> arc_count , childp -> cyclehead -> npropcall );
378 	    printname( childp );
379 	    printf( "\n" );
380 	}
381     }
382 }
383 
384 void
385 printname( selfp )
386     nltype	*selfp;
387 {
388 
389     if ( selfp -> name != 0 ) {
390 	printf( "%s" , selfp -> name );
391 #	ifdef DEBUG
392 	    if ( debug & DFNDEBUG ) {
393 		printf( "{%d} " , selfp -> toporder );
394 	    }
395 	    if ( debug & PROPDEBUG ) {
396 		printf( "%5.2f%% " , selfp -> propfraction );
397 	    }
398 #	endif /* DEBUG */
399     }
400     if ( selfp -> cycleno != 0 ) {
401 	printf( " <cycle %d>" , selfp -> cycleno );
402     }
403     if ( selfp -> index != 0 ) {
404 	if ( selfp -> printflag ) {
405 	    printf( " [%d]" , selfp -> index );
406 	} else {
407 	    printf( " (%d)" , selfp -> index );
408 	}
409     }
410 }
411 
412 void
413 sortchildren( parentp )
414     nltype	*parentp;
415 {
416     arctype	*arcp;
417     arctype	*detachedp;
418     arctype	sorted;
419     arctype	*prevp;
420 
421 	/*
422 	 *	unlink children from parent,
423 	 *	then insertion sort back on to sorted's children.
424 	 *	    *arcp	the arc you have detached and are inserting.
425 	 *	    *detachedp	the rest of the arcs to be sorted.
426 	 *	    sorted	arc list onto which you insertion sort.
427 	 *	    *prevp	arc before the arc you are comparing.
428 	 */
429     sorted.arc_childlist = 0;
430     for (  (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
431 	    arcp ;
432 	   (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
433 	    /*
434 	     *	consider *arcp as disconnected
435 	     *	insert it into sorted
436 	     */
437 	for (   prevp = &sorted ;
438 		prevp -> arc_childlist ;
439 		prevp = prevp -> arc_childlist ) {
440 	    if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
441 		break;
442 	    }
443 	}
444 	arcp -> arc_childlist = prevp -> arc_childlist;
445 	prevp -> arc_childlist = arcp;
446     }
447 	/*
448 	 *	reattach sorted children to parent
449 	 */
450     parentp -> children = sorted.arc_childlist;
451 }
452 
453 void
454 sortparents( childp )
455     nltype	*childp;
456 {
457     arctype	*arcp;
458     arctype	*detachedp;
459     arctype	sorted;
460     arctype	*prevp;
461 
462 	/*
463 	 *	unlink parents from child,
464 	 *	then insertion sort back on to sorted's parents.
465 	 *	    *arcp	the arc you have detached and are inserting.
466 	 *	    *detachedp	the rest of the arcs to be sorted.
467 	 *	    sorted	arc list onto which you insertion sort.
468 	 *	    *prevp	arc before the arc you are comparing.
469 	 */
470     sorted.arc_parentlist = 0;
471     for (  (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
472 	    arcp ;
473 	   (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
474 	    /*
475 	     *	consider *arcp as disconnected
476 	     *	insert it into sorted
477 	     */
478 	for (   prevp = &sorted ;
479 		prevp -> arc_parentlist ;
480 		prevp = prevp -> arc_parentlist ) {
481 	    if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
482 		break;
483 	    }
484 	}
485 	arcp -> arc_parentlist = prevp -> arc_parentlist;
486 	prevp -> arc_parentlist = arcp;
487     }
488 	/*
489 	 *	reattach sorted arcs to child
490 	 */
491     childp -> parents = sorted.arc_parentlist;
492 }
493 
494     /*
495      *	print a cycle header
496      */
497 void
498 printcycle( cyclep )
499     nltype	*cyclep;
500 {
501     char	kirkbuffer[ BUFSIZ ];
502 
503     sprintf( kirkbuffer , "[%d]" , cyclep -> index );
504     printf( "%-6.6s %5.1f %7.2f %11.2f %7ld" ,
505 	    kirkbuffer ,
506 	    100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
507 	    cyclep -> propself / hz ,
508 	    cyclep -> propchild / hz ,
509 	    cyclep -> npropcall );
510     if ( cyclep -> selfcalls != 0 ) {
511 	printf( "+%-7ld" , cyclep -> selfcalls );
512     } else {
513 	printf( " %7.7s" , "" );
514     }
515     printf( " <cycle %d as a whole>\t[%d]\n" ,
516 	    cyclep -> cycleno , cyclep -> index );
517 }
518 
519     /*
520      *	print the members of a cycle
521      */
522 void
523 printmembers( cyclep )
524     nltype	*cyclep;
525 {
526     nltype	*memberp;
527 
528     sortmembers( cyclep );
529     for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
530 	printf( "%6.6s %5.5s %7.2f %11.2f %7ld" ,
531 		"" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
532 		memberp -> npropcall );
533 	if ( memberp -> selfcalls != 0 ) {
534 	    printf( "+%-7ld" , memberp -> selfcalls );
535 	} else {
536 	    printf( " %7.7s" , "" );
537 	}
538 	printf( "     " );
539 	printname( memberp );
540 	printf( "\n" );
541     }
542 }
543 
544     /*
545      *	sort members of a cycle
546      */
547 void
548 sortmembers( cyclep )
549     nltype	*cyclep;
550 {
551     nltype	*todo;
552     nltype	*doing;
553     nltype	*prev;
554 
555 	/*
556 	 *	detach cycle members from cyclehead,
557 	 *	and insertion sort them back on.
558 	 */
559     todo = cyclep -> cnext;
560     cyclep -> cnext = 0;
561     for (  (doing = todo)&&(todo = doing -> cnext);
562 	    doing ;
563 	   (doing = todo )&&(todo = doing -> cnext )){
564 	for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
565 	    if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
566 		break;
567 	    }
568 	}
569 	doing -> cnext = prev -> cnext;
570 	prev -> cnext = doing;
571     }
572 }
573 
574     /*
575      *	major sort is on propself + propchild,
576      *	next is sort on ncalls + selfcalls.
577      */
578 int
579 membercmp( this , that )
580     nltype	*this;
581     nltype	*that;
582 {
583     double	thistime = this -> propself + this -> propchild;
584     double	thattime = that -> propself + that -> propchild;
585     long	thiscalls = this -> ncall + this -> selfcalls;
586     long	thatcalls = that -> ncall + that -> selfcalls;
587 
588     if ( thistime > thattime ) {
589 	return GREATERTHAN;
590     }
591     if ( thistime < thattime ) {
592 	return LESSTHAN;
593     }
594     if ( thiscalls > thatcalls ) {
595 	return GREATERTHAN;
596     }
597     if ( thiscalls < thatcalls ) {
598 	return LESSTHAN;
599     }
600     return EQUALTO;
601 }
602     /*
603      *	compare two arcs to/from the same child/parent.
604      *	- if one arc is a self arc, it's least.
605      *	- if one arc is within a cycle, it's less than.
606      *	- if both arcs are within a cycle, compare arc counts.
607      *	- if neither arc is within a cycle, compare with
608      *		arc_time + arc_childtime as major key
609      *		arc count as minor key
610      */
611 int
612 arccmp( thisp , thatp )
613     arctype	*thisp;
614     arctype	*thatp;
615 {
616     nltype	*thisparentp = thisp -> arc_parentp;
617     nltype	*thischildp = thisp -> arc_childp;
618     nltype	*thatparentp = thatp -> arc_parentp;
619     nltype	*thatchildp = thatp -> arc_childp;
620     double	thistime;
621     double	thattime;
622 
623 #   ifdef DEBUG
624 	if ( debug & TIMEDEBUG ) {
625 	    printf( "[arccmp] " );
626 	    printname( thisparentp );
627 	    printf( " calls " );
628 	    printname ( thischildp );
629 	    printf( " %f + %f %ld/%ld\n" ,
630 		    thisp -> arc_time , thisp -> arc_childtime ,
631 		    thisp -> arc_count , thischildp -> ncall );
632 	    printf( "[arccmp] " );
633 	    printname( thatparentp );
634 	    printf( " calls " );
635 	    printname( thatchildp );
636 	    printf( " %f + %f %ld/%ld\n" ,
637 		    thatp -> arc_time , thatp -> arc_childtime ,
638 		    thatp -> arc_count , thatchildp -> ncall );
639 	    printf( "\n" );
640 	}
641 #   endif /* DEBUG */
642     if ( thisparentp == thischildp ) {
643 	    /* this is a self call */
644 	return LESSTHAN;
645     }
646     if ( thatparentp == thatchildp ) {
647 	    /* that is a self call */
648 	return GREATERTHAN;
649     }
650     if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
651 	thisparentp -> cycleno == thischildp -> cycleno ) {
652 	    /* this is a call within a cycle */
653 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
654 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
655 		/* that is a call within the cycle, too */
656 	    if ( thisp -> arc_count < thatp -> arc_count ) {
657 		return LESSTHAN;
658 	    }
659 	    if ( thisp -> arc_count > thatp -> arc_count ) {
660 		return GREATERTHAN;
661 	    }
662 	    return EQUALTO;
663 	} else {
664 		/* that isn't a call within the cycle */
665 	    return LESSTHAN;
666 	}
667     } else {
668 	    /* this isn't a call within a cycle */
669 	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
670 	    thatparentp -> cycleno == thatchildp -> cycleno ) {
671 		/* that is a call within a cycle */
672 	    return GREATERTHAN;
673 	} else {
674 		/* neither is a call within a cycle */
675 	    thistime = thisp -> arc_time + thisp -> arc_childtime;
676 	    thattime = thatp -> arc_time + thatp -> arc_childtime;
677 	    if ( thistime < thattime )
678 		return LESSTHAN;
679 	    if ( thistime > thattime )
680 		return GREATERTHAN;
681 	    if ( thisp -> arc_count < thatp -> arc_count )
682 		return LESSTHAN;
683 	    if ( thisp -> arc_count > thatp -> arc_count )
684 		return GREATERTHAN;
685 	    return EQUALTO;
686 	}
687     }
688 }
689 
690 void
691 printblurb( blurbname )
692     char	*blurbname;
693 {
694     FILE	*blurbfile;
695     int		input;
696 
697     blurbfile = fopen( blurbname , "r" );
698     if ( blurbfile == NULL ) {
699 	warn( "%s" , blurbname );
700 	return;
701     }
702     while ( ( input = getc( blurbfile ) ) != EOF ) {
703 	putchar( input );
704     }
705     fclose( blurbfile );
706 }
707 
708 int
709 namecmp( npp1 , npp2 )
710     nltype **npp1, **npp2;
711 {
712     return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
713 }
714 
715 void
716 printindex()
717 {
718     nltype		**namesortnlp;
719     register nltype	*nlp;
720     int			index, nnames, todo, i, j;
721     char		peterbuffer[ BUFSIZ ];
722 
723 	/*
724 	 *	Now, sort regular function name alphabetically
725 	 *	to create an index.
726 	 */
727     namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
728     if ( namesortnlp == (nltype **) 0 )
729 	errx( 1 , "ran out of memory for sorting");
730     for ( index = 0 , nnames = 0 ; index < nname ; index++ ) {
731 	if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 )
732 		continue;
733 	namesortnlp[nnames++] = &nl[index];
734     }
735     qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
736     for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) {
737 	namesortnlp[todo++] = &cyclenl[index];
738     }
739     printf( "\f\nIndex by function name\n\n" );
740     index = ( todo + 2 ) / 3;
741     for ( i = 0; i < index ; i++ ) {
742 	for ( j = i; j < todo ; j += index ) {
743 	    nlp = namesortnlp[ j ];
744 	    if ( nlp -> printflag ) {
745 		sprintf( peterbuffer , "[%d]" , nlp -> index );
746 	    } else {
747 		sprintf( peterbuffer , "(%d)" , nlp -> index );
748 	    }
749 	    if ( j < nnames ) {
750 		printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name );
751 	    } else {
752 		printf( "%6.6s " , peterbuffer );
753 		sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
754 		printf( "%-19.19s" , peterbuffer );
755 	    }
756 	}
757 	printf( "\n" );
758     }
759     free( namesortnlp );
760 }
761