11590Srgrimes/*
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
3227327Scharnierstatic char sccsid[] = "@(#)arcs.c	8.1 (Berkeley) 6/6/93";
33105243Scharnier#endif /* not lint */
3427313Scharnier#endif
35105243Scharnier
3699112Sobrien#include <sys/cdefs.h>
3799112Sobrien__FBSDID("$FreeBSD: releng/10.3/usr.bin/gprof/arcs.c 246783 2013-02-14 08:16:03Z charnier $");
381590Srgrimes
3927313Scharnier#include <err.h>
401590Srgrimes#include "gprof.h"
411590Srgrimes
421590Srgrimes#ifdef DEBUG
431590Srgrimesint visited;
441590Srgrimesint viable;
451590Srgrimesint newcycle;
461590Srgrimesint oldcycle;
4797631Swollman#endif /* DEBUG */
481590Srgrimes
49246783Scharnierint topcmp(const void *, const void *);
50246783Scharnier
511590Srgrimes    /*
521590Srgrimes     *	add (or just increment) an arc
531590Srgrimes     */
54105243Scharniervoid
55246783Scharnieraddarc(nltype *parentp, nltype *childp, long count)
561590Srgrimes{
571590Srgrimes    arctype		*arcp;
581590Srgrimes
591590Srgrimes#   ifdef DEBUG
601590Srgrimes	if ( debug & TALLYDEBUG ) {
6191018Sbde	    printf( "[addarc] %ld arcs from %s to %s\n" ,
621590Srgrimes		    count , parentp -> name , childp -> name );
631590Srgrimes	}
6497631Swollman#   endif /* DEBUG */
651590Srgrimes    arcp = arclookup( parentp , childp );
661590Srgrimes    if ( arcp != 0 ) {
671590Srgrimes	    /*
681590Srgrimes	     *	a hit:  just increment the count.
691590Srgrimes	     */
701590Srgrimes#	ifdef DEBUG
711590Srgrimes	    if ( debug & TALLYDEBUG ) {
7291018Sbde		printf( "[tally] hit %ld += %ld\n" ,
731590Srgrimes			arcp -> arc_count , count );
741590Srgrimes	    }
7597631Swollman#	endif /* DEBUG */
761590Srgrimes	arcp -> arc_count += count;
771590Srgrimes	return;
781590Srgrimes    }
791590Srgrimes    arcp = (arctype *)calloc( 1 , sizeof *arcp );
80105243Scharnier    if (arcp == NULL)
81105243Scharnier	errx( 1 , "malloc failed" );
821590Srgrimes    arcp -> arc_parentp = parentp;
831590Srgrimes    arcp -> arc_childp = childp;
841590Srgrimes    arcp -> arc_count = count;
851590Srgrimes	/*
861590Srgrimes	 *	prepend this child to the children of this parent
871590Srgrimes	 */
881590Srgrimes    arcp -> arc_childlist = parentp -> children;
891590Srgrimes    parentp -> children = arcp;
901590Srgrimes	/*
911590Srgrimes	 *	prepend this parent to the parents of this child
921590Srgrimes	 */
931590Srgrimes    arcp -> arc_parentlist = childp -> parents;
941590Srgrimes    childp -> parents = arcp;
951590Srgrimes}
961590Srgrimes
971590Srgrimes    /*
981590Srgrimes     *	the code below topologically sorts the graph (collapsing cycles),
991590Srgrimes     *	and propagates time bottom up and flags top down.
1001590Srgrimes     */
1011590Srgrimes
1021590Srgrimes    /*
1031590Srgrimes     *	the topologically sorted name list pointers
1041590Srgrimes     */
1051590Srgrimesnltype	**topsortnlp;
1061590Srgrimes
107105243Scharnierint
108246783Scharniertopcmp(const void *v1, const void *v2)
1091590Srgrimes{
110246783Scharnier    const nltype **npp1 = (const nltype **)v1;
111246783Scharnier    const nltype **npp2 = (const nltype **)v2;
112246783Scharnier
1131590Srgrimes    return (*npp1) -> toporder - (*npp2) -> toporder;
1141590Srgrimes}
1151590Srgrimes
1161590Srgrimesnltype **
117246783Scharnierdoarcs(void)
1181590Srgrimes{
1191590Srgrimes    nltype	*parentp, **timesortnlp;
1201590Srgrimes    arctype	*arcp;
1211590Srgrimes    long	index;
1221590Srgrimes    long	pass;
1231590Srgrimes
1241590Srgrimes	/*
1251590Srgrimes	 *	initialize various things:
1261590Srgrimes	 *	    zero out child times.
1271590Srgrimes	 *	    count self-recursive calls.
1281590Srgrimes	 *	    indicate that nothing is on cycles.
1291590Srgrimes	 */
1301590Srgrimes    for ( parentp = nl ; parentp < npe ; parentp++ ) {
1311590Srgrimes	parentp -> childtime = 0.0;
1321590Srgrimes	arcp = arclookup( parentp , parentp );
1331590Srgrimes	if ( arcp != 0 ) {
1341590Srgrimes	    parentp -> ncall -= arcp -> arc_count;
1351590Srgrimes	    parentp -> selfcalls = arcp -> arc_count;
1361590Srgrimes	} else {
1371590Srgrimes	    parentp -> selfcalls = 0;
1381590Srgrimes	}
1391590Srgrimes	parentp -> npropcall = parentp -> ncall;
1401590Srgrimes	parentp -> propfraction = 0.0;
1411590Srgrimes	parentp -> propself = 0.0;
1421590Srgrimes	parentp -> propchild = 0.0;
1431590Srgrimes	parentp -> printflag = FALSE;
1441590Srgrimes	parentp -> toporder = DFN_NAN;
1451590Srgrimes	parentp -> cycleno = 0;
1461590Srgrimes	parentp -> cyclehead = parentp;
1471590Srgrimes	parentp -> cnext = 0;
1481590Srgrimes    }
1491590Srgrimes    for ( pass = 1 ; ; pass++ ) {
1501590Srgrimes	    /*
1511590Srgrimes	     *	topologically order things
1521590Srgrimes	     *	if any node is unnumbered,
1531590Srgrimes	     *	    number it and any of its descendents.
1541590Srgrimes	     */
1551590Srgrimes	for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) {
1561590Srgrimes	    if ( parentp -> toporder == DFN_NAN ) {
1571590Srgrimes		dfn( parentp );
1581590Srgrimes	    }
1591590Srgrimes	}
1601590Srgrimes	    /*
1611590Srgrimes	     *	link together nodes on the same cycle
1621590Srgrimes	     */
1631590Srgrimes	cyclelink();
1641590Srgrimes	    /*
1651590Srgrimes	     *	if no cycles to break up, proceed
1661590Srgrimes	     */
1671590Srgrimes	if ( ! Cflag )
1681590Srgrimes	    break;
1691590Srgrimes	    /*
1701590Srgrimes	     *	analyze cycles to determine breakup
1711590Srgrimes	     */
1721590Srgrimes#	ifdef DEBUG
1731590Srgrimes	    if ( debug & BREAKCYCLE ) {
17491018Sbde		printf("[doarcs] pass %ld, cycle(s) %d\n" , pass , ncycle );
1751590Srgrimes	    }
17697631Swollman#	endif /* DEBUG */
1771590Srgrimes	if ( pass == 1 ) {
1781590Srgrimes	    printf( "\n\n%s %s\n%s %d:\n" ,
1791590Srgrimes		"The following arcs were deleted" ,
1801590Srgrimes		"from the propagation calculation" ,
1811590Srgrimes		"to reduce the maximum cycle size to", cyclethreshold );
1821590Srgrimes	}
1831590Srgrimes	if ( cycleanalyze() )
1841590Srgrimes	    break;
1851590Srgrimes	free ( cyclenl );
1861590Srgrimes	ncycle = 0;
1871590Srgrimes	for ( parentp = nl ; parentp < npe ; parentp++ ) {
1881590Srgrimes	    parentp -> toporder = DFN_NAN;
1891590Srgrimes	    parentp -> cycleno = 0;
1901590Srgrimes	    parentp -> cyclehead = parentp;
1911590Srgrimes	    parentp -> cnext = 0;
1921590Srgrimes	}
1931590Srgrimes    }
1941590Srgrimes    if ( pass > 1 ) {
1951590Srgrimes	printf( "\f\n" );
1961590Srgrimes    } else {
1971590Srgrimes	printf( "\tNone\n\n" );
1981590Srgrimes    }
1991590Srgrimes	/*
2001590Srgrimes	 *	Sort the symbol table in reverse topological order
2011590Srgrimes	 */
2021590Srgrimes    topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
203105243Scharnier    if ( topsortnlp == (nltype **) 0 )
204105243Scharnier	errx( 1 , "[doarcs] ran out of memory for topo sorting" );
2051590Srgrimes    for ( index = 0 ; index < nname ; index += 1 ) {
2061590Srgrimes	topsortnlp[ index ] = &nl[ index ];
2071590Srgrimes    }
2081590Srgrimes    qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
2091590Srgrimes#   ifdef DEBUG
2101590Srgrimes	if ( debug & DFNDEBUG ) {
2111590Srgrimes	    printf( "[doarcs] topological sort listing\n" );
2121590Srgrimes	    for ( index = 0 ; index < nname ; index += 1 ) {
2131590Srgrimes		printf( "[doarcs] " );
2141590Srgrimes		printf( "%d:" , topsortnlp[ index ] -> toporder );
2151590Srgrimes		printname( topsortnlp[ index ] );
2161590Srgrimes		printf( "\n" );
2171590Srgrimes	    }
2181590Srgrimes	}
21997631Swollman#   endif /* DEBUG */
2201590Srgrimes	/*
2211590Srgrimes	 *	starting from the topological top,
2221590Srgrimes	 *	propagate print flags to children.
2231590Srgrimes	 *	also, calculate propagation fractions.
2241590Srgrimes	 *	this happens before time propagation
2251590Srgrimes	 *	since time propagation uses the fractions.
2261590Srgrimes	 */
2271590Srgrimes    doflags();
2281590Srgrimes	/*
2298874Srgrimes	 *	starting from the topological bottom,
230105243Scharnier	 *	propagate children times up to parents.
2311590Srgrimes	 */
2321590Srgrimes    dotime();
2331590Srgrimes	/*
2341590Srgrimes	 *	Now, sort by propself + propchild.
2351590Srgrimes	 *	sorting both the regular function names
2361590Srgrimes	 *	and cycle headers.
2371590Srgrimes	 */
2381590Srgrimes    timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
239105243Scharnier    if ( timesortnlp == (nltype **) 0 )
240105243Scharnier	errx( 1 , "ran out of memory for sorting" );
2411590Srgrimes    for ( index = 0 ; index < nname ; index++ ) {
2421590Srgrimes	timesortnlp[index] = &nl[index];
2431590Srgrimes    }
2441590Srgrimes    for ( index = 1 ; index <= ncycle ; index++ ) {
2451590Srgrimes	timesortnlp[nname+index-1] = &cyclenl[index];
2461590Srgrimes    }
2471590Srgrimes    qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
2481590Srgrimes    for ( index = 0 ; index < nname + ncycle ; index++ ) {
2491590Srgrimes	timesortnlp[ index ] -> index = index + 1;
2501590Srgrimes    }
2511590Srgrimes    return( timesortnlp );
2521590Srgrimes}
2531590Srgrimes
254105243Scharniervoid
255246783Scharnierdotime(void)
2561590Srgrimes{
2571590Srgrimes    int	index;
2581590Srgrimes
2591590Srgrimes    cycletime();
2601590Srgrimes    for ( index = 0 ; index < nname ; index += 1 ) {
2611590Srgrimes	timepropagate( topsortnlp[ index ] );
2621590Srgrimes    }
2631590Srgrimes}
2641590Srgrimes
265105243Scharniervoid
266246783Scharniertimepropagate(nltype *parentp)
2671590Srgrimes{
2681590Srgrimes    arctype	*arcp;
2691590Srgrimes    nltype	*childp;
2701590Srgrimes    double	share;
2711590Srgrimes    double	propshare;
2721590Srgrimes
2731590Srgrimes    if ( parentp -> propfraction == 0.0 ) {
2741590Srgrimes	return;
2751590Srgrimes    }
2761590Srgrimes	/*
2771590Srgrimes	 *	gather time from children of this parent.
2781590Srgrimes	 */
2791590Srgrimes    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
2801590Srgrimes	childp = arcp -> arc_childp;
2811590Srgrimes	if ( arcp -> arc_flags & DEADARC ) {
2821590Srgrimes	    continue;
2831590Srgrimes	}
2841590Srgrimes	if ( arcp -> arc_count == 0 ) {
2851590Srgrimes	    continue;
2861590Srgrimes	}
2871590Srgrimes	if ( childp == parentp ) {
2881590Srgrimes	    continue;
2891590Srgrimes	}
2901590Srgrimes	if ( childp -> propfraction == 0.0 ) {
2911590Srgrimes	    continue;
2921590Srgrimes	}
2931590Srgrimes	if ( childp -> cyclehead != childp ) {
2941590Srgrimes	    if ( parentp -> cycleno == childp -> cycleno ) {
2951590Srgrimes		continue;
2961590Srgrimes	    }
2971590Srgrimes	    if ( parentp -> toporder <= childp -> toporder ) {
2981590Srgrimes		fprintf( stderr , "[propagate] toporder botches\n" );
2991590Srgrimes	    }
3001590Srgrimes	    childp = childp -> cyclehead;
3011590Srgrimes	} else {
3021590Srgrimes	    if ( parentp -> toporder <= childp -> toporder ) {
3031590Srgrimes		fprintf( stderr , "[propagate] toporder botches\n" );
3041590Srgrimes		continue;
3051590Srgrimes	    }
3061590Srgrimes	}
3071590Srgrimes	if ( childp -> npropcall == 0 ) {
3081590Srgrimes	    continue;
3091590Srgrimes	}
3101590Srgrimes	    /*
3111590Srgrimes	     *	distribute time for this arc
3121590Srgrimes	     */
3131590Srgrimes	arcp -> arc_time = childp -> time
3141590Srgrimes			        * ( ( (double) arcp -> arc_count ) /
3151590Srgrimes				    ( (double) childp -> npropcall ) );
3161590Srgrimes	arcp -> arc_childtime = childp -> childtime
3171590Srgrimes			        * ( ( (double) arcp -> arc_count ) /
3181590Srgrimes				    ( (double) childp -> npropcall ) );
3191590Srgrimes	share = arcp -> arc_time + arcp -> arc_childtime;
3201590Srgrimes	parentp -> childtime += share;
3211590Srgrimes	    /*
3221590Srgrimes	     *	( 1 - propfraction ) gets lost along the way
3231590Srgrimes	     */
3241590Srgrimes	propshare = parentp -> propfraction * share;
3251590Srgrimes	    /*
3261590Srgrimes	     *	fix things for printing
3271590Srgrimes	     */
3281590Srgrimes	parentp -> propchild += propshare;
3291590Srgrimes	arcp -> arc_time *= parentp -> propfraction;
3301590Srgrimes	arcp -> arc_childtime *= parentp -> propfraction;
3311590Srgrimes	    /*
3321590Srgrimes	     *	add this share to the parent's cycle header, if any.
3331590Srgrimes	     */
3341590Srgrimes	if ( parentp -> cyclehead != parentp ) {
3351590Srgrimes	    parentp -> cyclehead -> childtime += share;
3361590Srgrimes	    parentp -> cyclehead -> propchild += propshare;
3371590Srgrimes	}
3381590Srgrimes#	ifdef DEBUG
3391590Srgrimes	    if ( debug & PROPDEBUG ) {
3401590Srgrimes		printf( "[dotime] child \t" );
3411590Srgrimes		printname( childp );
34291018Sbde		printf( " with %f %f %ld/%ld\n" ,
3431590Srgrimes			childp -> time , childp -> childtime ,
3441590Srgrimes			arcp -> arc_count , childp -> npropcall );
3451590Srgrimes		printf( "[dotime] parent\t" );
3461590Srgrimes		printname( parentp );
3471590Srgrimes		printf( "\n[dotime] share %f\n" , share );
3481590Srgrimes	    }
34997631Swollman#	endif /* DEBUG */
3501590Srgrimes    }
3511590Srgrimes}
3521590Srgrimes
353105243Scharniervoid
354246783Scharniercyclelink(void)
3551590Srgrimes{
3561590Srgrimes    register nltype	*nlp;
3571590Srgrimes    register nltype	*cyclenlp;
3581590Srgrimes    int			cycle;
3591590Srgrimes    nltype		*memberp;
3601590Srgrimes    arctype		*arcp;
3611590Srgrimes
3621590Srgrimes	/*
363105243Scharnier	 *	Count the number of cycles, and initialize the cycle lists
3641590Srgrimes	 */
3651590Srgrimes    ncycle = 0;
3661590Srgrimes    for ( nlp = nl ; nlp < npe ; nlp++ ) {
3671590Srgrimes	    /*
3681590Srgrimes	     *	this is how you find unattached cycles
3691590Srgrimes	     */
3701590Srgrimes	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
3711590Srgrimes	    ncycle += 1;
3721590Srgrimes	}
3731590Srgrimes    }
3741590Srgrimes	/*
3751590Srgrimes	 *	cyclenl is indexed by cycle number:
3761590Srgrimes	 *	i.e. it is origin 1, not origin 0.
3771590Srgrimes	 */
3781590Srgrimes    cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
379105243Scharnier    if ( cyclenl == 0 )
380228629Sdim	errx( 1 , "no room for %zu bytes of cycle headers" ,
38127414Scharnier		   ( ncycle + 1 ) * sizeof( nltype ) );
3821590Srgrimes	/*
3831590Srgrimes	 *	now link cycles to true cycleheads,
3841590Srgrimes	 *	number them, accumulate the data for the cycle
3851590Srgrimes	 */
3861590Srgrimes    cycle = 0;
3871590Srgrimes    for ( nlp = nl ; nlp < npe ; nlp++ ) {
3881590Srgrimes	if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) {
3891590Srgrimes	    continue;
3901590Srgrimes	}
3911590Srgrimes	cycle += 1;
3921590Srgrimes	cyclenlp = &cyclenl[cycle];
3931590Srgrimes        cyclenlp -> name = 0;		/* the name */
3941590Srgrimes        cyclenlp -> value = 0;		/* the pc entry point */
3951590Srgrimes        cyclenlp -> time = 0.0;		/* ticks in this routine */
3961590Srgrimes        cyclenlp -> childtime = 0.0;	/* cumulative ticks in children */
3971590Srgrimes	cyclenlp -> ncall = 0;		/* how many times called */
3981590Srgrimes	cyclenlp -> selfcalls = 0;	/* how many calls to self */
3991590Srgrimes	cyclenlp -> propfraction = 0.0;	/* what % of time propagates */
4001590Srgrimes	cyclenlp -> propself = 0.0;	/* how much self time propagates */
4011590Srgrimes	cyclenlp -> propchild = 0.0;	/* how much child time propagates */
4021590Srgrimes	cyclenlp -> printflag = TRUE;	/* should this be printed? */
4031590Srgrimes	cyclenlp -> index = 0;		/* index in the graph list */
4041590Srgrimes	cyclenlp -> toporder = DFN_NAN;	/* graph call chain top-sort order */
4051590Srgrimes	cyclenlp -> cycleno = cycle;	/* internal number of cycle on */
4061590Srgrimes	cyclenlp -> cyclehead = cyclenlp;	/* pointer to head of cycle */
4071590Srgrimes	cyclenlp -> cnext = nlp;	/* pointer to next member of cycle */
4081590Srgrimes	cyclenlp -> parents = 0;	/* list of caller arcs */
4091590Srgrimes	cyclenlp -> children = 0;	/* list of callee arcs */
4101590Srgrimes#	ifdef DEBUG
4111590Srgrimes	    if ( debug & CYCLEDEBUG ) {
4121590Srgrimes		printf( "[cyclelink] " );
4131590Srgrimes		printname( nlp );
4141590Srgrimes		printf( " is the head of cycle %d\n" , cycle );
4151590Srgrimes	    }
41697631Swollman#	endif /* DEBUG */
4171590Srgrimes	    /*
4181590Srgrimes	     *	link members to cycle header
4191590Srgrimes	     */
4208874Srgrimes	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4211590Srgrimes	    memberp -> cycleno = cycle;
4221590Srgrimes	    memberp -> cyclehead = cyclenlp;
4231590Srgrimes	}
4241590Srgrimes	    /*
4251590Srgrimes	     *	count calls from outside the cycle
4261590Srgrimes	     *	and those among cycle members
4271590Srgrimes	     */
4281590Srgrimes	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4291590Srgrimes	    for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
4301590Srgrimes		if ( arcp -> arc_parentp == memberp ) {
4311590Srgrimes		    continue;
4321590Srgrimes		}
4331590Srgrimes		if ( arcp -> arc_parentp -> cycleno == cycle ) {
4341590Srgrimes		    cyclenlp -> selfcalls += arcp -> arc_count;
4351590Srgrimes		} else {
4361590Srgrimes		    cyclenlp -> npropcall += arcp -> arc_count;
4371590Srgrimes		}
4381590Srgrimes	    }
4391590Srgrimes	}
4401590Srgrimes    }
4411590Srgrimes}
4421590Srgrimes
4431590Srgrimes    /*
4441590Srgrimes     *	analyze cycles to determine breakup
4451590Srgrimes     */
446105243Scharnierbool
447246783Scharniercycleanalyze(void)
4481590Srgrimes{
4491590Srgrimes    arctype	**cyclestack;
4501590Srgrimes    arctype	**stkp;
4511590Srgrimes    arctype	**arcpp;
4521590Srgrimes    arctype	**endlist;
4531590Srgrimes    arctype	*arcp;
4541590Srgrimes    nltype	*nlp;
4551590Srgrimes    cltype	*clp;
4561590Srgrimes    bool	ret;
4571590Srgrimes    bool	done;
4581590Srgrimes    int		size;
4591590Srgrimes    int		cycleno;
4601590Srgrimes
4611590Srgrimes	/*
4621590Srgrimes	 *	calculate the size of the cycle, and find nodes that
4631590Srgrimes	 *	exit the cycle as they are desirable targets to cut
4641590Srgrimes	 *	some of their parents
4651590Srgrimes	 */
4661590Srgrimes    for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) {
4671590Srgrimes	size = 0;
4681590Srgrimes	for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) {
4691590Srgrimes	    size += 1;
4701590Srgrimes	    nlp -> parentcnt = 0;
4711590Srgrimes	    nlp -> flags &= ~HASCYCLEXIT;
4721590Srgrimes	    for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) {
4731590Srgrimes		nlp -> parentcnt += 1;
4741590Srgrimes		if ( arcp -> arc_parentp -> cycleno != cycleno )
4751590Srgrimes		    nlp -> flags |= HASCYCLEXIT;
4761590Srgrimes	    }
4771590Srgrimes	}
4781590Srgrimes	if ( size <= cyclethreshold )
4791590Srgrimes	    continue;
4801590Srgrimes	done = FALSE;
4811590Srgrimes        cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) );
482105243Scharnier	if ( cyclestack == 0 )
483228629Sdim	    errx( 1, "no room for %zu bytes of cycle stack" ,
48427414Scharnier			   ( size + 1 ) * sizeof( arctype * ) );
4851590Srgrimes#	ifdef DEBUG
4861590Srgrimes	    if ( debug & BREAKCYCLE ) {
4871590Srgrimes		printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" ,
4881590Srgrimes		    cycleno , ncycle , size );
4891590Srgrimes	    }
49097631Swollman#	endif /* DEBUG */
4911590Srgrimes	for ( nlp = cyclenl[ cycleno ] . cnext ; nlp ; nlp = nlp -> cnext ) {
4921590Srgrimes	    stkp = &cyclestack[0];
4931590Srgrimes	    nlp -> flags |= CYCLEHEAD;
4941590Srgrimes	    ret = descend ( nlp , cyclestack , stkp );
4951590Srgrimes	    nlp -> flags &= ~CYCLEHEAD;
4961590Srgrimes	    if ( ret == FALSE )
4971590Srgrimes		break;
4981590Srgrimes	}
4991590Srgrimes	free( cyclestack );
5001590Srgrimes	if ( cyclecnt > 0 ) {
5011590Srgrimes	    compresslist();
5021590Srgrimes	    for ( clp = cyclehead ; clp ; ) {
5031590Srgrimes		endlist = &clp -> list[ clp -> size ];
5041590Srgrimes		for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
5051590Srgrimes		    (*arcpp) -> arc_cyclecnt--;
5061590Srgrimes		cyclecnt--;
5071590Srgrimes		clp = clp -> next;
5081590Srgrimes		free( clp );
5091590Srgrimes	    }
5101590Srgrimes	    cyclehead = 0;
5111590Srgrimes	}
5121590Srgrimes    }
5131590Srgrimes#   ifdef DEBUG
5141590Srgrimes	if ( debug & BREAKCYCLE ) {
5151590Srgrimes	    printf("%s visited %d, viable %d, newcycle %d, oldcycle %d\n",
5161590Srgrimes		"[doarcs]" , visited , viable , newcycle , oldcycle);
5171590Srgrimes	}
51897631Swollman#   endif /* DEBUG */
5191590Srgrimes    return( done );
5201590Srgrimes}
5211590Srgrimes
522105243Scharnierbool
523246783Scharnierdescend(nltype *node, arctype **stkstart, arctype **stkp)
5241590Srgrimes{
5251590Srgrimes    arctype	*arcp;
5261590Srgrimes    bool	ret;
5271590Srgrimes
5281590Srgrimes    for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) {
5291590Srgrimes#	ifdef DEBUG
5301590Srgrimes	    visited++;
53197631Swollman#	endif /* DEBUG */
5321590Srgrimes	if ( arcp -> arc_childp -> cycleno != node -> cycleno
5331590Srgrimes	    || ( arcp -> arc_childp -> flags & VISITED )
5341590Srgrimes	    || ( arcp -> arc_flags & DEADARC ) )
5351590Srgrimes	    continue;
5361590Srgrimes#	ifdef DEBUG
5371590Srgrimes	    viable++;
53897631Swollman#	endif /* DEBUG */
5391590Srgrimes	*stkp = arcp;
5401590Srgrimes	if ( arcp -> arc_childp -> flags & CYCLEHEAD ) {
5411590Srgrimes	    if ( addcycle( stkstart , stkp ) == FALSE )
5421590Srgrimes		return( FALSE );
5431590Srgrimes	    continue;
5441590Srgrimes	}
5451590Srgrimes	arcp -> arc_childp -> flags |= VISITED;
5461590Srgrimes	ret = descend( arcp -> arc_childp , stkstart , stkp + 1 );
5471590Srgrimes	arcp -> arc_childp -> flags &= ~VISITED;
5481590Srgrimes	if ( ret == FALSE )
5491590Srgrimes	    return( FALSE );
5501590Srgrimes    }
551105243Scharnier    return( TRUE );
5521590Srgrimes}
5531590Srgrimes
554105243Scharnierbool
555246783Scharnieraddcycle(arctype **stkstart, arctype **stkend)
5561590Srgrimes{
5571590Srgrimes    arctype	**arcpp;
5581590Srgrimes    arctype	**stkloc;
5591590Srgrimes    arctype	**stkp;
5601590Srgrimes    arctype	**endlist;
5611590Srgrimes    arctype	*minarc;
5621590Srgrimes    arctype	*arcp;
5631590Srgrimes    cltype	*clp;
5641590Srgrimes    int		size;
5651590Srgrimes
5661590Srgrimes    size = stkend - stkstart + 1;
5671590Srgrimes    if ( size <= 1 )
5681590Srgrimes	return( TRUE );
5691590Srgrimes    for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) {
5701590Srgrimes	if ( *arcpp > minarc )
5711590Srgrimes	    continue;
5721590Srgrimes	minarc = *arcpp;
5731590Srgrimes	stkloc = arcpp;
5741590Srgrimes    }
5751590Srgrimes    for ( clp = cyclehead ; clp ; clp = clp -> next ) {
5761590Srgrimes	if ( clp -> size != size )
5771590Srgrimes	    continue;
5781590Srgrimes	stkp = stkloc;
5791590Srgrimes	endlist = &clp -> list[ size ];
5801590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
5811590Srgrimes	    if ( *stkp++ != *arcpp )
5821590Srgrimes		break;
5831590Srgrimes	    if ( stkp > stkend )
5841590Srgrimes		stkp = stkstart;
5851590Srgrimes	}
5861590Srgrimes	if ( arcpp == endlist ) {
5871590Srgrimes#	    ifdef DEBUG
5881590Srgrimes		oldcycle++;
58997631Swollman#	    endif /* DEBUG */
5901590Srgrimes	    return( TRUE );
5911590Srgrimes	}
5921590Srgrimes    }
5931590Srgrimes    clp = (cltype *)
5941590Srgrimes	calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
5951590Srgrimes    if ( clp == 0 ) {
596228629Sdim	warnx( "no room for %zu bytes of subcycle storage" ,
59727313Scharnier	    sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
5981590Srgrimes	return( FALSE );
5991590Srgrimes    }
6001590Srgrimes    stkp = stkloc;
6011590Srgrimes    endlist = &clp -> list[ size ];
6021590Srgrimes    for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
6031590Srgrimes	arcp = *arcpp = *stkp++;
6041590Srgrimes	if ( stkp > stkend )
6051590Srgrimes	    stkp = stkstart;
6061590Srgrimes	arcp -> arc_cyclecnt++;
6071590Srgrimes	if ( ( arcp -> arc_flags & ONLIST ) == 0 ) {
6081590Srgrimes	    arcp -> arc_flags |= ONLIST;
6091590Srgrimes	    arcp -> arc_next = archead;
6101590Srgrimes	    archead = arcp;
6111590Srgrimes	}
6121590Srgrimes    }
6131590Srgrimes    clp -> size = size;
6141590Srgrimes    clp -> next = cyclehead;
6151590Srgrimes    cyclehead = clp;
6161590Srgrimes#   ifdef DEBUG
6171590Srgrimes	newcycle++;
6181590Srgrimes	if ( debug & SUBCYCLELIST ) {
6191590Srgrimes	    printsubcycle( clp );
6201590Srgrimes	}
62197631Swollman#   endif /* DEBUG */
6221590Srgrimes    cyclecnt++;
6231590Srgrimes    if ( cyclecnt >= CYCLEMAX )
6241590Srgrimes	return( FALSE );
6251590Srgrimes    return( TRUE );
6261590Srgrimes}
6271590Srgrimes
628105243Scharniervoid
629246783Scharniercompresslist(void)
6301590Srgrimes{
6311590Srgrimes    cltype	*clp;
6321590Srgrimes    cltype	**prev;
6331590Srgrimes    arctype	**arcpp;
6341590Srgrimes    arctype	**endlist;
6351590Srgrimes    arctype	*arcp;
6361590Srgrimes    arctype	*maxarcp;
6371590Srgrimes    arctype	*maxexitarcp;
6381590Srgrimes    arctype	*maxwithparentarcp;
6391590Srgrimes    arctype	*maxnoparentarcp;
6401590Srgrimes    int		maxexitcnt;
6411590Srgrimes    int		maxwithparentcnt;
6421590Srgrimes    int		maxnoparentcnt;
64391012Sbde#   ifdef DEBUG
64491012Sbde	const char	*type;
64597631Swollman#   endif /* DEBUG */
6461590Srgrimes
6471590Srgrimes    maxexitcnt = 0;
6481590Srgrimes    maxwithparentcnt = 0;
6491590Srgrimes    maxnoparentcnt = 0;
6501590Srgrimes    for ( endlist = &archead , arcp = archead ; arcp ; ) {
6511590Srgrimes	if ( arcp -> arc_cyclecnt == 0 ) {
6521590Srgrimes	    arcp -> arc_flags &= ~ONLIST;
6531590Srgrimes	    *endlist = arcp -> arc_next;
6541590Srgrimes	    arcp -> arc_next = 0;
6551590Srgrimes	    arcp = *endlist;
6561590Srgrimes	    continue;
6571590Srgrimes	}
6581590Srgrimes	if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) {
6591590Srgrimes	    if ( arcp -> arc_cyclecnt > maxexitcnt ||
6601590Srgrimes		( arcp -> arc_cyclecnt == maxexitcnt &&
6611590Srgrimes		arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) {
6621590Srgrimes		maxexitcnt = arcp -> arc_cyclecnt;
6631590Srgrimes		maxexitarcp = arcp;
6641590Srgrimes	    }
6651590Srgrimes	} else if ( arcp -> arc_childp -> parentcnt > 1 ) {
6661590Srgrimes	    if ( arcp -> arc_cyclecnt > maxwithparentcnt ||
6671590Srgrimes		( arcp -> arc_cyclecnt == maxwithparentcnt &&
6681590Srgrimes		arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) {
6691590Srgrimes		maxwithparentcnt = arcp -> arc_cyclecnt;
6701590Srgrimes		maxwithparentarcp = arcp;
6711590Srgrimes	    }
6721590Srgrimes	} else {
6731590Srgrimes	    if ( arcp -> arc_cyclecnt > maxnoparentcnt ||
6741590Srgrimes		( arcp -> arc_cyclecnt == maxnoparentcnt &&
6751590Srgrimes		arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) {
6761590Srgrimes		maxnoparentcnt = arcp -> arc_cyclecnt;
6771590Srgrimes		maxnoparentarcp = arcp;
6781590Srgrimes	    }
6791590Srgrimes	}
6801590Srgrimes	endlist = &arcp -> arc_next;
6811590Srgrimes	arcp = arcp -> arc_next;
6821590Srgrimes    }
6831590Srgrimes    if ( maxexitcnt > 0 ) {
6841590Srgrimes	/*
6851590Srgrimes	 *	first choice is edge leading to node with out-of-cycle parent
6861590Srgrimes	 */
6871590Srgrimes	maxarcp = maxexitarcp;
6881590Srgrimes#	ifdef DEBUG
6891590Srgrimes	    type = "exit";
69097631Swollman#	endif /* DEBUG */
6911590Srgrimes    } else if ( maxwithparentcnt > 0 ) {
6921590Srgrimes	/*
6931590Srgrimes	 *	second choice is edge leading to node with at least one
6941590Srgrimes	 *	other in-cycle parent
6951590Srgrimes	 */
6961590Srgrimes	maxarcp = maxwithparentarcp;
6971590Srgrimes#	ifdef DEBUG
6981590Srgrimes	    type = "internal";
69997631Swollman#	endif /* DEBUG */
7001590Srgrimes    } else {
7011590Srgrimes	/*
7021590Srgrimes	 *	last choice is edge leading to node with only this arc as
7031590Srgrimes	 *	a parent (as it will now be orphaned)
7041590Srgrimes	 */
7051590Srgrimes	maxarcp = maxnoparentarcp;
7061590Srgrimes#	ifdef DEBUG
7071590Srgrimes	    type = "orphan";
70897631Swollman#	endif /* DEBUG */
7091590Srgrimes    }
7101590Srgrimes    maxarcp -> arc_flags |= DEADARC;
7111590Srgrimes    maxarcp -> arc_childp -> parentcnt -= 1;
7121590Srgrimes    maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count;
7131590Srgrimes#   ifdef DEBUG
7141590Srgrimes	if ( debug & BREAKCYCLE ) {
71591018Sbde	    printf( "%s delete %s arc: %s (%ld) -> %s from %u cycle(s)\n" ,
7161590Srgrimes		"[compresslist]" , type , maxarcp -> arc_parentp -> name ,
7171590Srgrimes		maxarcp -> arc_count , maxarcp -> arc_childp -> name ,
7181590Srgrimes		maxarcp -> arc_cyclecnt );
7191590Srgrimes	}
72097631Swollman#   endif /* DEBUG */
72191018Sbde    printf( "\t%s to %s with %ld calls\n" , maxarcp -> arc_parentp -> name ,
7221590Srgrimes	maxarcp -> arc_childp -> name , maxarcp -> arc_count );
7231590Srgrimes    prev = &cyclehead;
7241590Srgrimes    for ( clp = cyclehead ; clp ; ) {
7251590Srgrimes	endlist = &clp -> list[ clp -> size ];
7261590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
7271590Srgrimes	    if ( (*arcpp) -> arc_flags & DEADARC )
7281590Srgrimes		break;
7291590Srgrimes	if ( arcpp == endlist ) {
7301590Srgrimes	    prev = &clp -> next;
7311590Srgrimes	    clp = clp -> next;
7321590Srgrimes	    continue;
7331590Srgrimes	}
7341590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
7351590Srgrimes	    (*arcpp) -> arc_cyclecnt--;
7361590Srgrimes	cyclecnt--;
7371590Srgrimes	*prev = clp -> next;
7381590Srgrimes	clp = clp -> next;
7391590Srgrimes	free( clp );
7401590Srgrimes    }
7411590Srgrimes}
7421590Srgrimes
7431590Srgrimes#ifdef DEBUG
744105243Scharniervoid
745246783Scharnierprintsubcycle(cltype *clp)
7461590Srgrimes{
7471590Srgrimes    arctype	**arcpp;
7481590Srgrimes    arctype	**endlist;
7491590Srgrimes
7501590Srgrimes    arcpp = clp -> list;
7511590Srgrimes    printf( "%s <cycle %d>\n" , (*arcpp) -> arc_parentp -> name ,
7521590Srgrimes	(*arcpp) -> arc_parentp -> cycleno ) ;
7531590Srgrimes    for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ )
75491018Sbde	printf( "\t(%ld) -> %s\n" , (*arcpp) -> arc_count ,
7551590Srgrimes	    (*arcpp) -> arc_childp -> name ) ;
7561590Srgrimes}
75797631Swollman#endif /* DEBUG */
7581590Srgrimes
759105243Scharniervoid
760246783Scharniercycletime(void)
7611590Srgrimes{
7621590Srgrimes    int			cycle;
7631590Srgrimes    nltype		*cyclenlp;
7641590Srgrimes    nltype		*childp;
7651590Srgrimes
7661590Srgrimes    for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
7671590Srgrimes	cyclenlp = &cyclenl[ cycle ];
7681590Srgrimes	for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
7691590Srgrimes	    if ( childp -> propfraction == 0.0 ) {
7701590Srgrimes		    /*
7711590Srgrimes		     * all members have the same propfraction except those
7721590Srgrimes		     *	that were excluded with -E
7731590Srgrimes		     */
7741590Srgrimes		continue;
7751590Srgrimes	    }
7761590Srgrimes	    cyclenlp -> time += childp -> time;
7771590Srgrimes	}
7781590Srgrimes	cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
7791590Srgrimes    }
7801590Srgrimes}
7811590Srgrimes
7821590Srgrimes    /*
7831590Srgrimes     *	in one top to bottom pass over the topologically sorted namelist
7841590Srgrimes     *	propagate:
7851590Srgrimes     *		printflag as the union of parents' printflags
7861590Srgrimes     *		propfraction as the sum of fractional parents' propfractions
7871590Srgrimes     *	and while we're here, sum time for functions.
7881590Srgrimes     */
789105243Scharniervoid
790246783Scharnierdoflags(void)
7911590Srgrimes{
7921590Srgrimes    int		index;
7931590Srgrimes    nltype	*childp;
7941590Srgrimes    nltype	*oldhead;
7951590Srgrimes
7961590Srgrimes    oldhead = 0;
7971590Srgrimes    for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
7981590Srgrimes	childp = topsortnlp[ index ];
7991590Srgrimes	    /*
8001590Srgrimes	     *	if we haven't done this function or cycle,
8011590Srgrimes	     *	inherit things from parent.
8021590Srgrimes	     *	this way, we are linear in the number of arcs
8031590Srgrimes	     *	since we do all members of a cycle (and the cycle itself)
8041590Srgrimes	     *	as we hit the first member of the cycle.
8051590Srgrimes	     */
8061590Srgrimes	if ( childp -> cyclehead != oldhead ) {
8071590Srgrimes	    oldhead = childp -> cyclehead;
8081590Srgrimes	    inheritflags( childp );
8091590Srgrimes	}
8101590Srgrimes#	ifdef DEBUG
8111590Srgrimes	    if ( debug & PROPDEBUG ) {
8121590Srgrimes		printf( "[doflags] " );
8131590Srgrimes		printname( childp );
8141590Srgrimes		printf( " inherits printflag %d and propfraction %f\n" ,
8151590Srgrimes			childp -> printflag , childp -> propfraction );
8161590Srgrimes	    }
81797631Swollman#	endif /* DEBUG */
8181590Srgrimes	if ( ! childp -> printflag ) {
8191590Srgrimes		/*
8201590Srgrimes		 *	printflag is off
8211590Srgrimes		 *	it gets turned on by
8221590Srgrimes		 *	being on -f list,
8231590Srgrimes		 *	or there not being any -f list and not being on -e list.
8241590Srgrimes		 */
8251590Srgrimes	    if (   onlist( flist , childp -> name )
8261590Srgrimes		|| ( !fflag && !onlist( elist , childp -> name ) ) ) {
8271590Srgrimes		childp -> printflag = TRUE;
8281590Srgrimes	    }
8291590Srgrimes	} else {
8301590Srgrimes		/*
8311590Srgrimes		 *	this function has printing parents:
8321590Srgrimes		 *	maybe someone wants to shut it up
8331590Srgrimes		 *	by putting it on -e list.  (but favor -f over -e)
8341590Srgrimes		 */
8351590Srgrimes	    if (  ( !onlist( flist , childp -> name ) )
8361590Srgrimes		&& onlist( elist , childp -> name ) ) {
8371590Srgrimes		childp -> printflag = FALSE;
8381590Srgrimes	    }
8391590Srgrimes	}
8401590Srgrimes	if ( childp -> propfraction == 0.0 ) {
8411590Srgrimes		/*
8421590Srgrimes		 *	no parents to pass time to.
8431590Srgrimes		 *	collect time from children if
8441590Srgrimes		 *	its on -F list,
8451590Srgrimes		 *	or there isn't any -F list and its not on -E list.
8461590Srgrimes		 */
8471590Srgrimes	    if ( onlist( Flist , childp -> name )
8481590Srgrimes		|| ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
8491590Srgrimes		    childp -> propfraction = 1.0;
8501590Srgrimes	    }
8511590Srgrimes	} else {
8521590Srgrimes		/*
8538874Srgrimes		 *	it has parents to pass time to,
8541590Srgrimes		 *	but maybe someone wants to shut it up
855105243Scharnier		 *	by putting it on -E list.  (but favor -F over -E)
8561590Srgrimes		 */
8571590Srgrimes	    if (  !onlist( Flist , childp -> name )
8581590Srgrimes		&& onlist( Elist , childp -> name ) ) {
8591590Srgrimes		childp -> propfraction = 0.0;
8601590Srgrimes	    }
8611590Srgrimes	}
8621590Srgrimes	childp -> propself = childp -> time * childp -> propfraction;
8631590Srgrimes	printtime += childp -> propself;
8641590Srgrimes#	ifdef DEBUG
8651590Srgrimes	    if ( debug & PROPDEBUG ) {
8661590Srgrimes		printf( "[doflags] " );
8671590Srgrimes		printname( childp );
8681590Srgrimes		printf( " ends up with printflag %d and propfraction %f\n" ,
8691590Srgrimes			childp -> printflag , childp -> propfraction );
8701590Srgrimes		printf( "time %f propself %f printtime %f\n" ,
8711590Srgrimes			childp -> time , childp -> propself , printtime );
8721590Srgrimes	    }
87397631Swollman#	endif /* DEBUG */
8741590Srgrimes    }
8751590Srgrimes}
8761590Srgrimes
8771590Srgrimes    /*
8781590Srgrimes     *	check if any parent of this child
8791590Srgrimes     *	(or outside parents of this cycle)
8808874Srgrimes     *	have their print flags on and set the
8811590Srgrimes     *	print flag of the child (cycle) appropriately.
8821590Srgrimes     *	similarly, deal with propagation fractions from parents.
8831590Srgrimes     */
884105243Scharniervoid
885246783Scharnierinheritflags(nltype *childp)
8861590Srgrimes{
8871590Srgrimes    nltype	*headp;
8881590Srgrimes    arctype	*arcp;
8891590Srgrimes    nltype	*parentp;
8901590Srgrimes    nltype	*memp;
8911590Srgrimes
8921590Srgrimes    headp = childp -> cyclehead;
8931590Srgrimes    if ( childp == headp ) {
8941590Srgrimes	    /*
8951590Srgrimes	     *	just a regular child, check its parents
8961590Srgrimes	     */
8971590Srgrimes	childp -> printflag = FALSE;
8981590Srgrimes	childp -> propfraction = 0.0;
8991590Srgrimes	for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
9001590Srgrimes	    parentp = arcp -> arc_parentp;
9011590Srgrimes	    if ( childp == parentp ) {
9021590Srgrimes		continue;
9031590Srgrimes	    }
9041590Srgrimes	    childp -> printflag |= parentp -> printflag;
9051590Srgrimes		/*
9061590Srgrimes		 *	if the child was never actually called
9071590Srgrimes		 *	(e.g. this arc is static (and all others are, too))
9081590Srgrimes		 *	no time propagates along this arc.
9091590Srgrimes		 */
9101590Srgrimes	    if ( arcp -> arc_flags & DEADARC ) {
9111590Srgrimes		continue;
9121590Srgrimes	    }
9131590Srgrimes	    if ( childp -> npropcall ) {
9141590Srgrimes		childp -> propfraction += parentp -> propfraction
9151590Srgrimes					* ( ( (double) arcp -> arc_count )
9161590Srgrimes					  / ( (double) childp -> npropcall ) );
9171590Srgrimes	    }
9181590Srgrimes	}
9191590Srgrimes    } else {
9201590Srgrimes	    /*
9218874Srgrimes	     *	its a member of a cycle, look at all parents from
9221590Srgrimes	     *	outside the cycle
9231590Srgrimes	     */
9241590Srgrimes	headp -> printflag = FALSE;
9251590Srgrimes	headp -> propfraction = 0.0;
9261590Srgrimes	for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
9271590Srgrimes	    for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
9281590Srgrimes		if ( arcp -> arc_parentp -> cyclehead == headp ) {
9291590Srgrimes		    continue;
9301590Srgrimes		}
9311590Srgrimes		parentp = arcp -> arc_parentp;
9321590Srgrimes		headp -> printflag |= parentp -> printflag;
9331590Srgrimes		    /*
9341590Srgrimes		     *	if the cycle was never actually called
9351590Srgrimes		     *	(e.g. this arc is static (and all others are, too))
9361590Srgrimes		     *	no time propagates along this arc.
9371590Srgrimes		     */
9381590Srgrimes		if ( arcp -> arc_flags & DEADARC ) {
9391590Srgrimes		    continue;
9401590Srgrimes		}
9411590Srgrimes		if ( headp -> npropcall ) {
9421590Srgrimes		    headp -> propfraction += parentp -> propfraction
9431590Srgrimes					* ( ( (double) arcp -> arc_count )
9441590Srgrimes					  / ( (double) headp -> npropcall ) );
9451590Srgrimes		}
9461590Srgrimes	    }
9471590Srgrimes	}
9481590Srgrimes	for ( memp = headp ; memp ; memp = memp -> cnext ) {
9491590Srgrimes	    memp -> printflag = headp -> printflag;
9501590Srgrimes	    memp -> propfraction = headp -> propfraction;
9511590Srgrimes	}
9521590Srgrimes    }
9531590Srgrimes}
954