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