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