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