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