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