printgprof.c revision 151055
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
36static 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: head/usr.bin/gprof/printgprof.c 151055 2005-10-07 10:59:41Z bde $");
42
43#include <err.h>
44#include <string.h>
45
46#include "gprof.h"
47#include "pathnames.h"
48
49void
50printprof()
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
77int
78timecmp( 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     */
100void
101flatprofheader()
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
128void
129flatprofline( 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
167void
168gprofheader()
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
196void
197gprofline( 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
222void
223printgprof(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     */
271int
272totalcmp( 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
305void
306printparents( 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
350void
351printchildren( 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
384void
385printname( 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
412void
413sortchildren( 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
453void
454sortparents( 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     */
497void
498printcycle( 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     */
522void
523printmembers( 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     */
547void
548sortmembers( 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     */
578int
579membercmp( 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     */
611int
612arccmp( 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
690void
691printblurb( 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
708int
709namecmp( npp1 , npp2 )
710    nltype **npp1, **npp2;
711{
712    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
713}
714
715void
716printindex()
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