1331722Seadler/*
21590Srgrimes * Copyright (c) 1983, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
30105243Scharnier#if 0
311590Srgrimes#ifndef lint
321590Srgrimesstatic char sccsid[] = "@(#)printgprof.c	8.1 (Berkeley) 6/6/93";
33105243Scharnier#endif /* not lint */
3427313Scharnier#endif
35105243Scharnier
3699112Sobrien#include <sys/cdefs.h>
3799112Sobrien__FBSDID("$FreeBSD$");
381590Srgrimes
3927313Scharnier#include <err.h>
40129657Sstefanf#include <string.h>
41129657Sstefanf
421590Srgrimes#include "gprof.h"
431590Srgrimes#include "pathnames.h"
441590Srgrimes
45246783Scharnierint namecmp(const void *, const void *);
46246783Scharnierint timecmp(const void *, const void *);
47246783Scharnier
48105243Scharniervoid
49246783Scharnierprintprof(void)
501590Srgrimes{
511590Srgrimes    register nltype	*np;
521590Srgrimes    nltype		**sortednlp;
53246783Scharnier    int			idx;
541590Srgrimes
551590Srgrimes    actime = 0.0;
561590Srgrimes    printf( "\f\n" );
571590Srgrimes    flatprofheader();
581590Srgrimes	/*
591590Srgrimes	 *	Sort the symbol table in by time
601590Srgrimes	 */
611590Srgrimes    sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
62105243Scharnier    if ( sortednlp == (nltype **) 0 )
63105243Scharnier	errx( 1 , "[printprof] ran out of memory for time sorting" );
64246783Scharnier    for ( idx = 0 ; idx < nname ; idx += 1 ) {
65246783Scharnier	sortednlp[ idx ] = &nl[ idx ];
661590Srgrimes    }
671590Srgrimes    qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
68246783Scharnier    for ( idx = 0 ; idx < nname ; idx += 1 ) {
69246783Scharnier	np = sortednlp[ idx ];
701590Srgrimes	flatprofline( np );
711590Srgrimes    }
721590Srgrimes    actime = 0.0;
731590Srgrimes    free( sortednlp );
741590Srgrimes}
751590Srgrimes
76105243Scharnierint
77246783Scharniertimecmp(const void *v1, const void *v2)
781590Srgrimes{
79246783Scharnier    const nltype **npp1 = (const nltype **)v1;
80246783Scharnier    const nltype **npp2 = (const nltype **)v2;
811590Srgrimes    double	timediff;
821590Srgrimes    long	calldiff;
831590Srgrimes
841590Srgrimes    timediff = (*npp2) -> time - (*npp1) -> time;
851590Srgrimes    if ( timediff > 0.0 )
861590Srgrimes	return 1 ;
871590Srgrimes    if ( timediff < 0.0 )
881590Srgrimes	return -1;
891590Srgrimes    calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
901590Srgrimes    if ( calldiff > 0 )
911590Srgrimes	return 1;
921590Srgrimes    if ( calldiff < 0 )
931590Srgrimes	return -1;
941590Srgrimes    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
951590Srgrimes}
961590Srgrimes
971590Srgrimes    /*
981590Srgrimes     *	header for flatprofline
991590Srgrimes     */
100105243Scharniervoid
101246783Scharnierflatprofheader(void)
1021590Srgrimes{
1038874Srgrimes
1041590Srgrimes    if ( bflag ) {
1051590Srgrimes	printblurb( _PATH_FLAT_BLURB );
1061590Srgrimes    }
10791018Sbde    printf( "\ngranularity: each sample hit covers %g byte(s)" ,
10891735Sbde	    scale * HISTORICAL_SCALE_2 );
1091590Srgrimes    if ( totime > 0.0 ) {
1101590Srgrimes	printf( " for %.2f%% of %.2f seconds\n\n" ,
1111590Srgrimes		100.0/totime , totime / hz );
1121590Srgrimes    } else {
1131590Srgrimes	printf( " no time accumulated\n\n" );
1141590Srgrimes	    /*
115105243Scharnier	     *	this doesn't hurt since all the numerators will be zero.
1161590Srgrimes	     */
1171590Srgrimes	totime = 1.0;
1181590Srgrimes    }
1191590Srgrimes    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
1201590Srgrimes	    "%  " , "cumulative" , "self  " , "" , "self  " , "total " , "" );
1211590Srgrimes    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
1221590Srgrimes	    "time" , "seconds " , "seconds" , "calls" ,
12316227Sbde	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
12416227Sbde	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
12516227Sbde	    "name" );
1261590Srgrimes}
1271590Srgrimes
128105243Scharniervoid
129246783Scharnierflatprofline(register nltype *np)
1301590Srgrimes{
1311590Srgrimes
132151055Sbde    if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 &&
133151055Sbde	 np -> childtime == 0 ) {
1341590Srgrimes	return;
1351590Srgrimes    }
1361590Srgrimes    actime += np -> time;
1372513Sbde    if (hz >= 10000)
1382513Sbde	printf( "%5.1f %10.3f %8.3f" ,
1392513Sbde	    100 * np -> time / totime , actime / hz , np -> time / hz );
1402513Sbde    else
1412513Sbde	printf( "%5.1f %10.2f %8.2f" ,
1422513Sbde	    100 * np -> time / totime , actime / hz , np -> time / hz );
1431590Srgrimes    if ( np -> ncall != 0 ) {
14416227Sbde	if (hz >= 10000000)
14591018Sbde	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
14616227Sbde		1e9 * np -> time / hz / np -> ncall ,
14716227Sbde		1e9 * ( np -> time + np -> childtime ) / hz / np -> ncall );
14816227Sbde	else if (hz >= 10000)
14991018Sbde	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
1502513Sbde		1e6 * np -> time / hz / np -> ncall ,
1512513Sbde		1e6 * ( np -> time + np -> childtime ) / hz / np -> ncall );
1522513Sbde	else
15391018Sbde	    printf( " %8ld %8.2f %8.2f  " , np -> ncall ,
1542513Sbde		1000 * np -> time / hz / np -> ncall ,
1552513Sbde		1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
156151055Sbde    } else if ( np -> time != 0 || np -> childtime != 0 ) {
157151055Sbde	printf( " %8ld %7.2f%% %8.8s  " , np -> ncall ,
158151055Sbde	    100 * np -> time / ( np -> time + np -> childtime ) , "" );
1591590Srgrimes    } else {
1601590Srgrimes	printf( " %8.8s %8.8s %8.8s  " , "" , "" , "" );
1611590Srgrimes    }
1621590Srgrimes    printname( np );
1631590Srgrimes    printf( "\n" );
1641590Srgrimes}
1651590Srgrimes
166105243Scharniervoid
167246783Scharniergprofheader(void)
1681590Srgrimes{
1691590Srgrimes
1701590Srgrimes    if ( bflag ) {
1711590Srgrimes	printblurb( _PATH_CALLG_BLURB );
1721590Srgrimes    }
17391018Sbde    printf( "\ngranularity: each sample hit covers %g byte(s)" ,
17491735Sbde	    scale * HISTORICAL_SCALE_2 );
1751590Srgrimes    if ( printtime > 0.0 ) {
1761590Srgrimes	printf( " for %.2f%% of %.2f seconds\n\n" ,
1771590Srgrimes		100.0/printtime , printtime / hz );
1781590Srgrimes    } else {
1791590Srgrimes	printf( " no time propagated\n\n" );
1801590Srgrimes	    /*
1811590Srgrimes	     *	this doesn't hurt, since all the numerators will be 0.0
1821590Srgrimes	     */
1831590Srgrimes	printtime = 1.0;
1841590Srgrimes    }
1851590Srgrimes    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
1861590Srgrimes	"" , "" , "" , "" , "called" , "total" , "parents");
1871590Srgrimes    printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
1881590Srgrimes	"index" , "%time" , "self" , "descendents" ,
1891590Srgrimes	"called" , "self" , "name" , "index" );
1901590Srgrimes    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
1911590Srgrimes	"" , "" , "" , "" , "called" , "total" , "children");
1921590Srgrimes    printf( "\n" );
1931590Srgrimes}
1941590Srgrimes
195105243Scharniervoid
196246783Scharniergprofline(register nltype *np)
1971590Srgrimes{
1981590Srgrimes    char	kirkbuffer[ BUFSIZ ];
1991590Srgrimes
2001590Srgrimes    sprintf( kirkbuffer , "[%d]" , np -> index );
2011590Srgrimes    printf( "%-6.6s %5.1f %7.2f %11.2f" ,
2021590Srgrimes	    kirkbuffer ,
2031590Srgrimes	    100 * ( np -> propself + np -> propchild ) / printtime ,
2041590Srgrimes	    np -> propself / hz ,
2051590Srgrimes	    np -> propchild / hz );
2061590Srgrimes    if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
20791018Sbde	printf( " %7ld" , np -> npropcall );
2081590Srgrimes	if ( np -> selfcalls != 0 ) {
20991018Sbde	    printf( "+%-7ld " , np -> selfcalls );
2101590Srgrimes	} else {
2111590Srgrimes	    printf( " %7.7s " , "" );
2121590Srgrimes	}
2131590Srgrimes    } else {
2141590Srgrimes	printf( " %7.7s %7.7s " , "" , "" );
2151590Srgrimes    }
2161590Srgrimes    printname( np );
2171590Srgrimes    printf( "\n" );
2181590Srgrimes}
2191590Srgrimes
220105243Scharniervoid
221246783Scharnierprintgprof(nltype **timesortnlp)
2221590Srgrimes{
223246783Scharnier    int		idx;
2241590Srgrimes    nltype	*parentp;
2251590Srgrimes
2261590Srgrimes	/*
2271590Srgrimes	 *	Print out the structured profiling list
2281590Srgrimes	 */
2291590Srgrimes    gprofheader();
230246783Scharnier    for ( idx = 0 ; idx < nname + ncycle ; idx ++ ) {
231246783Scharnier	parentp = timesortnlp[ idx ];
2321590Srgrimes	if ( zflag == 0 &&
2331590Srgrimes	     parentp -> ncall == 0 &&
2341590Srgrimes	     parentp -> selfcalls == 0 &&
2351590Srgrimes	     parentp -> propself == 0 &&
2361590Srgrimes	     parentp -> propchild == 0 ) {
2371590Srgrimes	    continue;
2381590Srgrimes	}
2391590Srgrimes	if ( ! parentp -> printflag ) {
2401590Srgrimes	    continue;
2411590Srgrimes	}
2421590Srgrimes	if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
2431590Srgrimes		/*
2441590Srgrimes		 *	cycle header
2451590Srgrimes		 */
2461590Srgrimes	    printcycle( parentp );
2471590Srgrimes	    printmembers( parentp );
2481590Srgrimes	} else {
2491590Srgrimes	    printparents( parentp );
2501590Srgrimes	    gprofline( parentp );
2511590Srgrimes	    printchildren( parentp );
2521590Srgrimes	}
2531590Srgrimes	printf( "\n" );
2541590Srgrimes	printf( "-----------------------------------------------\n" );
2551590Srgrimes	printf( "\n" );
2561590Srgrimes    }
2571590Srgrimes    free( timesortnlp );
2581590Srgrimes}
2591590Srgrimes
2601590Srgrimes    /*
2611590Srgrimes     *	sort by decreasing propagated time
2621590Srgrimes     *	if times are equal, but one is a cycle header,
2631590Srgrimes     *		say that's first (e.g. less, i.e. -1).
2641590Srgrimes     *	if one's name doesn't have an underscore and the other does,
2651590Srgrimes     *		say the one is first.
2661590Srgrimes     *	all else being equal, sort by names.
2671590Srgrimes     */
2681590Srgrimesint
269246783Scharniertotalcmp(const void *v1, const void *v2)
2701590Srgrimes{
271246783Scharnier    const nltype **npp1 = (const nltype **)v1;
272246783Scharnier    const nltype **npp2 = (const nltype **)v2;
273246783Scharnier    register const nltype *np1 = *npp1;
274246783Scharnier    register const nltype *np2 = *npp2;
2751590Srgrimes    double		diff;
2761590Srgrimes
2771590Srgrimes    diff =    ( np1 -> propself + np1 -> propchild )
2781590Srgrimes	    - ( np2 -> propself + np2 -> propchild );
2791590Srgrimes    if ( diff < 0.0 )
2801590Srgrimes	    return 1;
2811590Srgrimes    if ( diff > 0.0 )
2821590Srgrimes	    return -1;
2838874Srgrimes    if ( np1 -> name == 0 && np1 -> cycleno != 0 )
2841590Srgrimes	return -1;
2851590Srgrimes    if ( np2 -> name == 0 && np2 -> cycleno != 0 )
2861590Srgrimes	return 1;
2871590Srgrimes    if ( np1 -> name == 0 )
2881590Srgrimes	return -1;
2891590Srgrimes    if ( np2 -> name == 0 )
2901590Srgrimes	return 1;
2911590Srgrimes    if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
2921590Srgrimes	return -1;
2931590Srgrimes    if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
2941590Srgrimes	return 1;
2951590Srgrimes    if ( np1 -> ncall > np2 -> ncall )
2961590Srgrimes	return -1;
2978874Srgrimes    if ( np1 -> ncall < np2 -> ncall )
2981590Srgrimes	return 1;
2991590Srgrimes    return strcmp( np1 -> name , np2 -> name );
3001590Srgrimes}
3011590Srgrimes
302105243Scharniervoid
303246783Scharnierprintparents(nltype *childp)
3041590Srgrimes{
3051590Srgrimes    nltype	*parentp;
3061590Srgrimes    arctype	*arcp;
3071590Srgrimes    nltype	*cycleheadp;
3081590Srgrimes
3091590Srgrimes    if ( childp -> cyclehead != 0 ) {
3101590Srgrimes	cycleheadp = childp -> cyclehead;
3111590Srgrimes    } else {
3121590Srgrimes	cycleheadp = childp;
3131590Srgrimes    }
3141590Srgrimes    if ( childp -> parents == 0 ) {
3151590Srgrimes	printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
3161590Srgrimes		"" , "" , "" , "" , "" , "" );
3171590Srgrimes	return;
3181590Srgrimes    }
3191590Srgrimes    sortparents( childp );
3201590Srgrimes    for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
3211590Srgrimes	parentp = arcp -> arc_parentp;
3221590Srgrimes	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
3231590Srgrimes	     ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
3241590Srgrimes		/*
3251590Srgrimes		 *	selfcall or call among siblings
3261590Srgrimes		 */
32791018Sbde	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
3281590Srgrimes		    "" , "" , "" , "" ,
3291590Srgrimes		    arcp -> arc_count , "" );
3301590Srgrimes	    printname( parentp );
3311590Srgrimes	    printf( "\n" );
3321590Srgrimes	} else {
3331590Srgrimes		/*
3341590Srgrimes		 *	regular parent of child
3351590Srgrimes		 */
33691018Sbde	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
3371590Srgrimes		    "" , "" ,
3381590Srgrimes		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
3391590Srgrimes		    arcp -> arc_count , cycleheadp -> npropcall );
3401590Srgrimes	    printname( parentp );
3411590Srgrimes	    printf( "\n" );
3421590Srgrimes	}
3431590Srgrimes    }
3441590Srgrimes}
3451590Srgrimes
346105243Scharniervoid
347246783Scharnierprintchildren(nltype *parentp)
3481590Srgrimes{
3491590Srgrimes    nltype	*childp;
3501590Srgrimes    arctype	*arcp;
3511590Srgrimes
3521590Srgrimes    sortchildren( parentp );
3531590Srgrimes    arcp = parentp -> children;
3541590Srgrimes    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
3551590Srgrimes	childp = arcp -> arc_childp;
3561590Srgrimes	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
3571590Srgrimes	    ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
3581590Srgrimes		/*
3591590Srgrimes		 *	self call or call to sibling
3601590Srgrimes		 */
36191018Sbde	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
3621590Srgrimes		    "" , "" , "" , "" , arcp -> arc_count , "" );
3631590Srgrimes	    printname( childp );
3641590Srgrimes	    printf( "\n" );
3651590Srgrimes	} else {
3661590Srgrimes		/*
3671590Srgrimes		 *	regular child of parent
3681590Srgrimes		 */
36991018Sbde	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
3701590Srgrimes		    "" , "" ,
3711590Srgrimes		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
3721590Srgrimes		    arcp -> arc_count , childp -> cyclehead -> npropcall );
3731590Srgrimes	    printname( childp );
3741590Srgrimes	    printf( "\n" );
3751590Srgrimes	}
3761590Srgrimes    }
3771590Srgrimes}
3781590Srgrimes
379105243Scharniervoid
380246783Scharnierprintname(nltype *selfp)
3811590Srgrimes{
3821590Srgrimes
3831590Srgrimes    if ( selfp -> name != 0 ) {
3841590Srgrimes	printf( "%s" , selfp -> name );
3851590Srgrimes#	ifdef DEBUG
3861590Srgrimes	    if ( debug & DFNDEBUG ) {
3871590Srgrimes		printf( "{%d} " , selfp -> toporder );
3881590Srgrimes	    }
3891590Srgrimes	    if ( debug & PROPDEBUG ) {
3901590Srgrimes		printf( "%5.2f%% " , selfp -> propfraction );
3911590Srgrimes	    }
39297631Swollman#	endif /* DEBUG */
3931590Srgrimes    }
3941590Srgrimes    if ( selfp -> cycleno != 0 ) {
3951590Srgrimes	printf( " <cycle %d>" , selfp -> cycleno );
3961590Srgrimes    }
3971590Srgrimes    if ( selfp -> index != 0 ) {
3981590Srgrimes	if ( selfp -> printflag ) {
3991590Srgrimes	    printf( " [%d]" , selfp -> index );
4001590Srgrimes	} else {
4011590Srgrimes	    printf( " (%d)" , selfp -> index );
4021590Srgrimes	}
4031590Srgrimes    }
4041590Srgrimes}
4051590Srgrimes
406105243Scharniervoid
407246783Scharniersortchildren(nltype *parentp)
4081590Srgrimes{
4091590Srgrimes    arctype	*arcp;
4101590Srgrimes    arctype	*detachedp;
4111590Srgrimes    arctype	sorted;
4121590Srgrimes    arctype	*prevp;
4131590Srgrimes
4141590Srgrimes	/*
4151590Srgrimes	 *	unlink children from parent,
4161590Srgrimes	 *	then insertion sort back on to sorted's children.
4171590Srgrimes	 *	    *arcp	the arc you have detached and are inserting.
4181590Srgrimes	 *	    *detachedp	the rest of the arcs to be sorted.
4191590Srgrimes	 *	    sorted	arc list onto which you insertion sort.
4201590Srgrimes	 *	    *prevp	arc before the arc you are comparing.
4211590Srgrimes	 */
4221590Srgrimes    sorted.arc_childlist = 0;
4231590Srgrimes    for (  (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
4241590Srgrimes	    arcp ;
4251590Srgrimes	   (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
4261590Srgrimes	    /*
4271590Srgrimes	     *	consider *arcp as disconnected
4281590Srgrimes	     *	insert it into sorted
4291590Srgrimes	     */
4301590Srgrimes	for (   prevp = &sorted ;
4311590Srgrimes		prevp -> arc_childlist ;
4321590Srgrimes		prevp = prevp -> arc_childlist ) {
4331590Srgrimes	    if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
4341590Srgrimes		break;
4351590Srgrimes	    }
4361590Srgrimes	}
4371590Srgrimes	arcp -> arc_childlist = prevp -> arc_childlist;
4381590Srgrimes	prevp -> arc_childlist = arcp;
4391590Srgrimes    }
4401590Srgrimes	/*
4411590Srgrimes	 *	reattach sorted children to parent
4421590Srgrimes	 */
4431590Srgrimes    parentp -> children = sorted.arc_childlist;
4441590Srgrimes}
4451590Srgrimes
446105243Scharniervoid
447246783Scharniersortparents(nltype *childp)
4481590Srgrimes{
4491590Srgrimes    arctype	*arcp;
4501590Srgrimes    arctype	*detachedp;
4511590Srgrimes    arctype	sorted;
4521590Srgrimes    arctype	*prevp;
4531590Srgrimes
4541590Srgrimes	/*
4551590Srgrimes	 *	unlink parents from child,
4561590Srgrimes	 *	then insertion sort back on to sorted's parents.
4571590Srgrimes	 *	    *arcp	the arc you have detached and are inserting.
4581590Srgrimes	 *	    *detachedp	the rest of the arcs to be sorted.
4591590Srgrimes	 *	    sorted	arc list onto which you insertion sort.
4601590Srgrimes	 *	    *prevp	arc before the arc you are comparing.
4611590Srgrimes	 */
4621590Srgrimes    sorted.arc_parentlist = 0;
4631590Srgrimes    for (  (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
4641590Srgrimes	    arcp ;
4651590Srgrimes	   (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
4661590Srgrimes	    /*
4671590Srgrimes	     *	consider *arcp as disconnected
4681590Srgrimes	     *	insert it into sorted
4691590Srgrimes	     */
4701590Srgrimes	for (   prevp = &sorted ;
4711590Srgrimes		prevp -> arc_parentlist ;
4721590Srgrimes		prevp = prevp -> arc_parentlist ) {
4731590Srgrimes	    if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
4741590Srgrimes		break;
4751590Srgrimes	    }
4761590Srgrimes	}
4771590Srgrimes	arcp -> arc_parentlist = prevp -> arc_parentlist;
4781590Srgrimes	prevp -> arc_parentlist = arcp;
4791590Srgrimes    }
4801590Srgrimes	/*
4811590Srgrimes	 *	reattach sorted arcs to child
4821590Srgrimes	 */
4831590Srgrimes    childp -> parents = sorted.arc_parentlist;
4841590Srgrimes}
4851590Srgrimes
4861590Srgrimes    /*
4871590Srgrimes     *	print a cycle header
4881590Srgrimes     */
489105243Scharniervoid
490246783Scharnierprintcycle(nltype *cyclep)
4911590Srgrimes{
4921590Srgrimes    char	kirkbuffer[ BUFSIZ ];
4931590Srgrimes
4941590Srgrimes    sprintf( kirkbuffer , "[%d]" , cyclep -> index );
49591018Sbde    printf( "%-6.6s %5.1f %7.2f %11.2f %7ld" ,
4961590Srgrimes	    kirkbuffer ,
4971590Srgrimes	    100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
4981590Srgrimes	    cyclep -> propself / hz ,
4991590Srgrimes	    cyclep -> propchild / hz ,
5001590Srgrimes	    cyclep -> npropcall );
5011590Srgrimes    if ( cyclep -> selfcalls != 0 ) {
50291018Sbde	printf( "+%-7ld" , cyclep -> selfcalls );
5031590Srgrimes    } else {
5041590Srgrimes	printf( " %7.7s" , "" );
5051590Srgrimes    }
5061590Srgrimes    printf( " <cycle %d as a whole>\t[%d]\n" ,
5071590Srgrimes	    cyclep -> cycleno , cyclep -> index );
5081590Srgrimes}
5091590Srgrimes
5101590Srgrimes    /*
5111590Srgrimes     *	print the members of a cycle
5121590Srgrimes     */
513105243Scharniervoid
514246783Scharnierprintmembers(nltype *cyclep)
5151590Srgrimes{
5161590Srgrimes    nltype	*memberp;
5171590Srgrimes
5181590Srgrimes    sortmembers( cyclep );
5191590Srgrimes    for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
52091018Sbde	printf( "%6.6s %5.5s %7.2f %11.2f %7ld" ,
5211590Srgrimes		"" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
5221590Srgrimes		memberp -> npropcall );
5231590Srgrimes	if ( memberp -> selfcalls != 0 ) {
52491018Sbde	    printf( "+%-7ld" , memberp -> selfcalls );
5251590Srgrimes	} else {
5261590Srgrimes	    printf( " %7.7s" , "" );
5271590Srgrimes	}
5281590Srgrimes	printf( "     " );
5291590Srgrimes	printname( memberp );
5301590Srgrimes	printf( "\n" );
5311590Srgrimes    }
5321590Srgrimes}
5331590Srgrimes
5341590Srgrimes    /*
5351590Srgrimes     *	sort members of a cycle
5361590Srgrimes     */
537105243Scharniervoid
538246783Scharniersortmembers(nltype *cyclep)
5391590Srgrimes{
5401590Srgrimes    nltype	*todo;
5411590Srgrimes    nltype	*doing;
5421590Srgrimes    nltype	*prev;
5431590Srgrimes
5441590Srgrimes	/*
5451590Srgrimes	 *	detach cycle members from cyclehead,
5461590Srgrimes	 *	and insertion sort them back on.
5471590Srgrimes	 */
5481590Srgrimes    todo = cyclep -> cnext;
5491590Srgrimes    cyclep -> cnext = 0;
5501590Srgrimes    for (  (doing = todo)&&(todo = doing -> cnext);
5511590Srgrimes	    doing ;
5521590Srgrimes	   (doing = todo )&&(todo = doing -> cnext )){
5531590Srgrimes	for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
5541590Srgrimes	    if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
5551590Srgrimes		break;
5561590Srgrimes	    }
5571590Srgrimes	}
5581590Srgrimes	doing -> cnext = prev -> cnext;
5591590Srgrimes	prev -> cnext = doing;
5601590Srgrimes    }
5611590Srgrimes}
5621590Srgrimes
5631590Srgrimes    /*
5641590Srgrimes     *	major sort is on propself + propchild,
5651590Srgrimes     *	next is sort on ncalls + selfcalls.
5661590Srgrimes     */
5671590Srgrimesint
568246783Scharniermembercmp(nltype *this, nltype *that)
5691590Srgrimes{
5701590Srgrimes    double	thistime = this -> propself + this -> propchild;
5711590Srgrimes    double	thattime = that -> propself + that -> propchild;
5721590Srgrimes    long	thiscalls = this -> ncall + this -> selfcalls;
5731590Srgrimes    long	thatcalls = that -> ncall + that -> selfcalls;
5741590Srgrimes
5751590Srgrimes    if ( thistime > thattime ) {
5761590Srgrimes	return GREATERTHAN;
5771590Srgrimes    }
5781590Srgrimes    if ( thistime < thattime ) {
5791590Srgrimes	return LESSTHAN;
5801590Srgrimes    }
5811590Srgrimes    if ( thiscalls > thatcalls ) {
5821590Srgrimes	return GREATERTHAN;
5831590Srgrimes    }
5841590Srgrimes    if ( thiscalls < thatcalls ) {
5851590Srgrimes	return LESSTHAN;
5861590Srgrimes    }
5871590Srgrimes    return EQUALTO;
5881590Srgrimes}
5891590Srgrimes    /*
5901590Srgrimes     *	compare two arcs to/from the same child/parent.
5911590Srgrimes     *	- if one arc is a self arc, it's least.
5921590Srgrimes     *	- if one arc is within a cycle, it's less than.
5931590Srgrimes     *	- if both arcs are within a cycle, compare arc counts.
5941590Srgrimes     *	- if neither arc is within a cycle, compare with
5951590Srgrimes     *		arc_time + arc_childtime as major key
5961590Srgrimes     *		arc count as minor key
5971590Srgrimes     */
5981590Srgrimesint
599246783Scharnierarccmp(arctype *thisp, arctype *thatp)
6001590Srgrimes{
6011590Srgrimes    nltype	*thisparentp = thisp -> arc_parentp;
6021590Srgrimes    nltype	*thischildp = thisp -> arc_childp;
6031590Srgrimes    nltype	*thatparentp = thatp -> arc_parentp;
6041590Srgrimes    nltype	*thatchildp = thatp -> arc_childp;
6051590Srgrimes    double	thistime;
6061590Srgrimes    double	thattime;
6071590Srgrimes
6081590Srgrimes#   ifdef DEBUG
6091590Srgrimes	if ( debug & TIMEDEBUG ) {
6101590Srgrimes	    printf( "[arccmp] " );
6111590Srgrimes	    printname( thisparentp );
6121590Srgrimes	    printf( " calls " );
6131590Srgrimes	    printname ( thischildp );
61491018Sbde	    printf( " %f + %f %ld/%ld\n" ,
6151590Srgrimes		    thisp -> arc_time , thisp -> arc_childtime ,
6161590Srgrimes		    thisp -> arc_count , thischildp -> ncall );
6171590Srgrimes	    printf( "[arccmp] " );
6181590Srgrimes	    printname( thatparentp );
6191590Srgrimes	    printf( " calls " );
6201590Srgrimes	    printname( thatchildp );
62191018Sbde	    printf( " %f + %f %ld/%ld\n" ,
6221590Srgrimes		    thatp -> arc_time , thatp -> arc_childtime ,
6231590Srgrimes		    thatp -> arc_count , thatchildp -> ncall );
6241590Srgrimes	    printf( "\n" );
6251590Srgrimes	}
62697631Swollman#   endif /* DEBUG */
6271590Srgrimes    if ( thisparentp == thischildp ) {
6281590Srgrimes	    /* this is a self call */
6291590Srgrimes	return LESSTHAN;
6301590Srgrimes    }
6311590Srgrimes    if ( thatparentp == thatchildp ) {
6321590Srgrimes	    /* that is a self call */
6331590Srgrimes	return GREATERTHAN;
6341590Srgrimes    }
6351590Srgrimes    if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
6361590Srgrimes	thisparentp -> cycleno == thischildp -> cycleno ) {
6371590Srgrimes	    /* this is a call within a cycle */
6381590Srgrimes	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
6391590Srgrimes	    thatparentp -> cycleno == thatchildp -> cycleno ) {
6401590Srgrimes		/* that is a call within the cycle, too */
6411590Srgrimes	    if ( thisp -> arc_count < thatp -> arc_count ) {
6421590Srgrimes		return LESSTHAN;
6431590Srgrimes	    }
6441590Srgrimes	    if ( thisp -> arc_count > thatp -> arc_count ) {
6451590Srgrimes		return GREATERTHAN;
6461590Srgrimes	    }
6471590Srgrimes	    return EQUALTO;
6481590Srgrimes	} else {
6491590Srgrimes		/* that isn't a call within the cycle */
6501590Srgrimes	    return LESSTHAN;
6511590Srgrimes	}
6521590Srgrimes    } else {
6531590Srgrimes	    /* this isn't a call within a cycle */
6541590Srgrimes	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
6551590Srgrimes	    thatparentp -> cycleno == thatchildp -> cycleno ) {
6561590Srgrimes		/* that is a call within a cycle */
6571590Srgrimes	    return GREATERTHAN;
6581590Srgrimes	} else {
6591590Srgrimes		/* neither is a call within a cycle */
6601590Srgrimes	    thistime = thisp -> arc_time + thisp -> arc_childtime;
6611590Srgrimes	    thattime = thatp -> arc_time + thatp -> arc_childtime;
6621590Srgrimes	    if ( thistime < thattime )
6631590Srgrimes		return LESSTHAN;
6641590Srgrimes	    if ( thistime > thattime )
6651590Srgrimes		return GREATERTHAN;
6661590Srgrimes	    if ( thisp -> arc_count < thatp -> arc_count )
6671590Srgrimes		return LESSTHAN;
6681590Srgrimes	    if ( thisp -> arc_count > thatp -> arc_count )
6691590Srgrimes		return GREATERTHAN;
6701590Srgrimes	    return EQUALTO;
6711590Srgrimes	}
6721590Srgrimes    }
6731590Srgrimes}
6741590Srgrimes
675105243Scharniervoid
676246783Scharnierprintblurb(const char *blurbname)
6771590Srgrimes{
6781590Srgrimes    FILE	*blurbfile;
6791590Srgrimes    int		input;
6801590Srgrimes
6811590Srgrimes    blurbfile = fopen( blurbname , "r" );
6821590Srgrimes    if ( blurbfile == NULL ) {
683105243Scharnier	warn( "%s" , blurbname );
6841590Srgrimes	return;
6851590Srgrimes    }
6861590Srgrimes    while ( ( input = getc( blurbfile ) ) != EOF ) {
6871590Srgrimes	putchar( input );
6881590Srgrimes    }
6891590Srgrimes    fclose( blurbfile );
6901590Srgrimes}
6911590Srgrimes
6921590Srgrimesint
693246783Scharniernamecmp(const void *v1, const void *v2)
6941590Srgrimes{
695246783Scharnier    const nltype **npp1 = (const nltype **)v1;
696246783Scharnier    const nltype **npp2 = (const nltype **)v2;
697246783Scharnier
6981590Srgrimes    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
6991590Srgrimes}
7001590Srgrimes
701105243Scharniervoid
702246783Scharnierprintindex(void)
7031590Srgrimes{
7041590Srgrimes    nltype		**namesortnlp;
7051590Srgrimes    register nltype	*nlp;
706246783Scharnier    int			idx, nnames, todo, i, j;
7071590Srgrimes    char		peterbuffer[ BUFSIZ ];
7081590Srgrimes
7091590Srgrimes	/*
710105243Scharnier	 *	Now, sort regular function name alphabetically
7111590Srgrimes	 *	to create an index.
7121590Srgrimes	 */
7131590Srgrimes    namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
714105243Scharnier    if ( namesortnlp == (nltype **) 0 )
715105243Scharnier	errx( 1 , "ran out of memory for sorting");
716246783Scharnier    for ( idx = 0 , nnames = 0 ; idx < nname ; idx++ ) {
717246783Scharnier	if ( zflag == 0 && nl[idx].ncall == 0 && nl[idx].time == 0 )
7181590Srgrimes		continue;
719246783Scharnier	namesortnlp[nnames++] = &nl[idx];
7201590Srgrimes    }
7211590Srgrimes    qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
722246783Scharnier    for ( idx = 1 , todo = nnames ; idx <= ncycle ; idx++ ) {
723246783Scharnier	namesortnlp[todo++] = &cyclenl[idx];
7241590Srgrimes    }
7251590Srgrimes    printf( "\f\nIndex by function name\n\n" );
726246783Scharnier    idx = ( todo + 2 ) / 3;
727246783Scharnier    for ( i = 0; i < idx ; i++ ) {
728246783Scharnier	for ( j = i; j < todo ; j += idx ) {
7291590Srgrimes	    nlp = namesortnlp[ j ];
7301590Srgrimes	    if ( nlp -> printflag ) {
7311590Srgrimes		sprintf( peterbuffer , "[%d]" , nlp -> index );
7321590Srgrimes	    } else {
7331590Srgrimes		sprintf( peterbuffer , "(%d)" , nlp -> index );
7341590Srgrimes	    }
7351590Srgrimes	    if ( j < nnames ) {
7361590Srgrimes		printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name );
7371590Srgrimes	    } else {
7381590Srgrimes		printf( "%6.6s " , peterbuffer );
7391590Srgrimes		sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
7401590Srgrimes		printf( "%-19.19s" , peterbuffer );
7411590Srgrimes	    }
7421590Srgrimes	}
7431590Srgrimes	printf( "\n" );
7441590Srgrimes    }
7451590Srgrimes    free( namesortnlp );
7461590Srgrimes}
747