arcs.c revision 1590
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 * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char sccsid[] = "@(#)arcs.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes#include "gprof.h"
391590Srgrimes
401590Srgrimes#ifdef DEBUG
411590Srgrimesint visited;
421590Srgrimesint viable;
431590Srgrimesint newcycle;
441590Srgrimesint oldcycle;
451590Srgrimes#endif DEBUG
461590Srgrimes
471590Srgrimes    /*
481590Srgrimes     *	add (or just increment) an arc
491590Srgrimes     */
501590Srgrimesaddarc( parentp , childp , count )
511590Srgrimes    nltype	*parentp;
521590Srgrimes    nltype	*childp;
531590Srgrimes    long	count;
541590Srgrimes{
551590Srgrimes    arctype		*arcp;
561590Srgrimes
571590Srgrimes#   ifdef DEBUG
581590Srgrimes	if ( debug & TALLYDEBUG ) {
591590Srgrimes	    printf( "[addarc] %d arcs from %s to %s\n" ,
601590Srgrimes		    count , parentp -> name , childp -> name );
611590Srgrimes	}
621590Srgrimes#   endif DEBUG
631590Srgrimes    arcp = arclookup( parentp , childp );
641590Srgrimes    if ( arcp != 0 ) {
651590Srgrimes	    /*
661590Srgrimes	     *	a hit:  just increment the count.
671590Srgrimes	     */
681590Srgrimes#	ifdef DEBUG
691590Srgrimes	    if ( debug & TALLYDEBUG ) {
701590Srgrimes		printf( "[tally] hit %d += %d\n" ,
711590Srgrimes			arcp -> arc_count , count );
721590Srgrimes	    }
731590Srgrimes#	endif DEBUG
741590Srgrimes	arcp -> arc_count += count;
751590Srgrimes	return;
761590Srgrimes    }
771590Srgrimes    arcp = (arctype *)calloc( 1 , sizeof *arcp );
781590Srgrimes    arcp -> arc_parentp = parentp;
791590Srgrimes    arcp -> arc_childp = childp;
801590Srgrimes    arcp -> arc_count = count;
811590Srgrimes	/*
821590Srgrimes	 *	prepend this child to the children of this parent
831590Srgrimes	 */
841590Srgrimes    arcp -> arc_childlist = parentp -> children;
851590Srgrimes    parentp -> children = arcp;
861590Srgrimes	/*
871590Srgrimes	 *	prepend this parent to the parents of this child
881590Srgrimes	 */
891590Srgrimes    arcp -> arc_parentlist = childp -> parents;
901590Srgrimes    childp -> parents = arcp;
911590Srgrimes}
921590Srgrimes
931590Srgrimes    /*
941590Srgrimes     *	the code below topologically sorts the graph (collapsing cycles),
951590Srgrimes     *	and propagates time bottom up and flags top down.
961590Srgrimes     */
971590Srgrimes
981590Srgrimes    /*
991590Srgrimes     *	the topologically sorted name list pointers
1001590Srgrimes     */
1011590Srgrimesnltype	**topsortnlp;
1021590Srgrimes
1031590Srgrimestopcmp( npp1 , npp2 )
1041590Srgrimes    nltype	**npp1;
1051590Srgrimes    nltype	**npp2;
1061590Srgrimes{
1071590Srgrimes    return (*npp1) -> toporder - (*npp2) -> toporder;
1081590Srgrimes}
1091590Srgrimes
1101590Srgrimesnltype **
1111590Srgrimesdoarcs()
1121590Srgrimes{
1131590Srgrimes    nltype	*parentp, **timesortnlp;
1141590Srgrimes    arctype	*arcp;
1151590Srgrimes    long	index;
1161590Srgrimes    long	pass;
1171590Srgrimes
1181590Srgrimes	/*
1191590Srgrimes	 *	initialize various things:
1201590Srgrimes	 *	    zero out child times.
1211590Srgrimes	 *	    count self-recursive calls.
1221590Srgrimes	 *	    indicate that nothing is on cycles.
1231590Srgrimes	 */
1241590Srgrimes    for ( parentp = nl ; parentp < npe ; parentp++ ) {
1251590Srgrimes	parentp -> childtime = 0.0;
1261590Srgrimes	arcp = arclookup( parentp , parentp );
1271590Srgrimes	if ( arcp != 0 ) {
1281590Srgrimes	    parentp -> ncall -= arcp -> arc_count;
1291590Srgrimes	    parentp -> selfcalls = arcp -> arc_count;
1301590Srgrimes	} else {
1311590Srgrimes	    parentp -> selfcalls = 0;
1321590Srgrimes	}
1331590Srgrimes	parentp -> npropcall = parentp -> ncall;
1341590Srgrimes	parentp -> propfraction = 0.0;
1351590Srgrimes	parentp -> propself = 0.0;
1361590Srgrimes	parentp -> propchild = 0.0;
1371590Srgrimes	parentp -> printflag = FALSE;
1381590Srgrimes	parentp -> toporder = DFN_NAN;
1391590Srgrimes	parentp -> cycleno = 0;
1401590Srgrimes	parentp -> cyclehead = parentp;
1411590Srgrimes	parentp -> cnext = 0;
1421590Srgrimes	if ( cflag ) {
1431590Srgrimes	    findcall( parentp , parentp -> value , (parentp+1) -> value );
1441590Srgrimes	}
1451590Srgrimes    }
1461590Srgrimes    for ( pass = 1 ; ; pass++ ) {
1471590Srgrimes	    /*
1481590Srgrimes	     *	topologically order things
1491590Srgrimes	     *	if any node is unnumbered,
1501590Srgrimes	     *	    number it and any of its descendents.
1511590Srgrimes	     */
1521590Srgrimes	for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) {
1531590Srgrimes	    if ( parentp -> toporder == DFN_NAN ) {
1541590Srgrimes		dfn( parentp );
1551590Srgrimes	    }
1561590Srgrimes	}
1571590Srgrimes	    /*
1581590Srgrimes	     *	link together nodes on the same cycle
1591590Srgrimes	     */
1601590Srgrimes	cyclelink();
1611590Srgrimes	    /*
1621590Srgrimes	     *	if no cycles to break up, proceed
1631590Srgrimes	     */
1641590Srgrimes	if ( ! Cflag )
1651590Srgrimes	    break;
1661590Srgrimes	    /*
1671590Srgrimes	     *	analyze cycles to determine breakup
1681590Srgrimes	     */
1691590Srgrimes#	ifdef DEBUG
1701590Srgrimes	    if ( debug & BREAKCYCLE ) {
1711590Srgrimes		printf("[doarcs] pass %d, cycle(s) %d\n" , pass , ncycle );
1721590Srgrimes	    }
1731590Srgrimes#	endif DEBUG
1741590Srgrimes	if ( pass == 1 ) {
1751590Srgrimes	    printf( "\n\n%s %s\n%s %d:\n" ,
1761590Srgrimes		"The following arcs were deleted" ,
1771590Srgrimes		"from the propagation calculation" ,
1781590Srgrimes		"to reduce the maximum cycle size to", cyclethreshold );
1791590Srgrimes	}
1801590Srgrimes	if ( cycleanalyze() )
1811590Srgrimes	    break;
1821590Srgrimes	free ( cyclenl );
1831590Srgrimes	ncycle = 0;
1841590Srgrimes	for ( parentp = nl ; parentp < npe ; parentp++ ) {
1851590Srgrimes	    parentp -> toporder = DFN_NAN;
1861590Srgrimes	    parentp -> cycleno = 0;
1871590Srgrimes	    parentp -> cyclehead = parentp;
1881590Srgrimes	    parentp -> cnext = 0;
1891590Srgrimes	}
1901590Srgrimes    }
1911590Srgrimes    if ( pass > 1 ) {
1921590Srgrimes	printf( "\f\n" );
1931590Srgrimes    } else {
1941590Srgrimes	printf( "\tNone\n\n" );
1951590Srgrimes    }
1961590Srgrimes	/*
1971590Srgrimes	 *	Sort the symbol table in reverse topological order
1981590Srgrimes	 */
1991590Srgrimes    topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
2001590Srgrimes    if ( topsortnlp == (nltype **) 0 ) {
2011590Srgrimes	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
2021590Srgrimes    }
2031590Srgrimes    for ( index = 0 ; index < nname ; index += 1 ) {
2041590Srgrimes	topsortnlp[ index ] = &nl[ index ];
2051590Srgrimes    }
2061590Srgrimes    qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
2071590Srgrimes#   ifdef DEBUG
2081590Srgrimes	if ( debug & DFNDEBUG ) {
2091590Srgrimes	    printf( "[doarcs] topological sort listing\n" );
2101590Srgrimes	    for ( index = 0 ; index < nname ; index += 1 ) {
2111590Srgrimes		printf( "[doarcs] " );
2121590Srgrimes		printf( "%d:" , topsortnlp[ index ] -> toporder );
2131590Srgrimes		printname( topsortnlp[ index ] );
2141590Srgrimes		printf( "\n" );
2151590Srgrimes	    }
2161590Srgrimes	}
2171590Srgrimes#   endif DEBUG
2181590Srgrimes	/*
2191590Srgrimes	 *	starting from the topological top,
2201590Srgrimes	 *	propagate print flags to children.
2211590Srgrimes	 *	also, calculate propagation fractions.
2221590Srgrimes	 *	this happens before time propagation
2231590Srgrimes	 *	since time propagation uses the fractions.
2241590Srgrimes	 */
2251590Srgrimes    doflags();
2261590Srgrimes	/*
2271590Srgrimes	 *	starting from the topological bottom,
2281590Srgrimes	 *	propogate children times up to parents.
2291590Srgrimes	 */
2301590Srgrimes    dotime();
2311590Srgrimes	/*
2321590Srgrimes	 *	Now, sort by propself + propchild.
2331590Srgrimes	 *	sorting both the regular function names
2341590Srgrimes	 *	and cycle headers.
2351590Srgrimes	 */
2361590Srgrimes    timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
2371590Srgrimes    if ( timesortnlp == (nltype **) 0 ) {
2381590Srgrimes	fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
2391590Srgrimes    }
2401590Srgrimes    for ( index = 0 ; index < nname ; index++ ) {
2411590Srgrimes	timesortnlp[index] = &nl[index];
2421590Srgrimes    }
2431590Srgrimes    for ( index = 1 ; index <= ncycle ; index++ ) {
2441590Srgrimes	timesortnlp[nname+index-1] = &cyclenl[index];
2451590Srgrimes    }
2461590Srgrimes    qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
2471590Srgrimes    for ( index = 0 ; index < nname + ncycle ; index++ ) {
2481590Srgrimes	timesortnlp[ index ] -> index = index + 1;
2491590Srgrimes    }
2501590Srgrimes    return( timesortnlp );
2511590Srgrimes}
2521590Srgrimes
2531590Srgrimesdotime()
2541590Srgrimes{
2551590Srgrimes    int	index;
2561590Srgrimes
2571590Srgrimes    cycletime();
2581590Srgrimes    for ( index = 0 ; index < nname ; index += 1 ) {
2591590Srgrimes	timepropagate( topsortnlp[ index ] );
2601590Srgrimes    }
2611590Srgrimes}
2621590Srgrimes
2631590Srgrimestimepropagate( parentp )
2641590Srgrimes    nltype	*parentp;
2651590Srgrimes{
2661590Srgrimes    arctype	*arcp;
2671590Srgrimes    nltype	*childp;
2681590Srgrimes    double	share;
2691590Srgrimes    double	propshare;
2701590Srgrimes
2711590Srgrimes    if ( parentp -> propfraction == 0.0 ) {
2721590Srgrimes	return;
2731590Srgrimes    }
2741590Srgrimes	/*
2751590Srgrimes	 *	gather time from children of this parent.
2761590Srgrimes	 */
2771590Srgrimes    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
2781590Srgrimes	childp = arcp -> arc_childp;
2791590Srgrimes	if ( arcp -> arc_flags & DEADARC ) {
2801590Srgrimes	    continue;
2811590Srgrimes	}
2821590Srgrimes	if ( arcp -> arc_count == 0 ) {
2831590Srgrimes	    continue;
2841590Srgrimes	}
2851590Srgrimes	if ( childp == parentp ) {
2861590Srgrimes	    continue;
2871590Srgrimes	}
2881590Srgrimes	if ( childp -> propfraction == 0.0 ) {
2891590Srgrimes	    continue;
2901590Srgrimes	}
2911590Srgrimes	if ( childp -> cyclehead != childp ) {
2921590Srgrimes	    if ( parentp -> cycleno == childp -> cycleno ) {
2931590Srgrimes		continue;
2941590Srgrimes	    }
2951590Srgrimes	    if ( parentp -> toporder <= childp -> toporder ) {
2961590Srgrimes		fprintf( stderr , "[propagate] toporder botches\n" );
2971590Srgrimes	    }
2981590Srgrimes	    childp = childp -> cyclehead;
2991590Srgrimes	} else {
3001590Srgrimes	    if ( parentp -> toporder <= childp -> toporder ) {
3011590Srgrimes		fprintf( stderr , "[propagate] toporder botches\n" );
3021590Srgrimes		continue;
3031590Srgrimes	    }
3041590Srgrimes	}
3051590Srgrimes	if ( childp -> npropcall == 0 ) {
3061590Srgrimes	    continue;
3071590Srgrimes	}
3081590Srgrimes	    /*
3091590Srgrimes	     *	distribute time for this arc
3101590Srgrimes	     */
3111590Srgrimes	arcp -> arc_time = childp -> time
3121590Srgrimes			        * ( ( (double) arcp -> arc_count ) /
3131590Srgrimes				    ( (double) childp -> npropcall ) );
3141590Srgrimes	arcp -> arc_childtime = childp -> childtime
3151590Srgrimes			        * ( ( (double) arcp -> arc_count ) /
3161590Srgrimes				    ( (double) childp -> npropcall ) );
3171590Srgrimes	share = arcp -> arc_time + arcp -> arc_childtime;
3181590Srgrimes	parentp -> childtime += share;
3191590Srgrimes	    /*
3201590Srgrimes	     *	( 1 - propfraction ) gets lost along the way
3211590Srgrimes	     */
3221590Srgrimes	propshare = parentp -> propfraction * share;
3231590Srgrimes	    /*
3241590Srgrimes	     *	fix things for printing
3251590Srgrimes	     */
3261590Srgrimes	parentp -> propchild += propshare;
3271590Srgrimes	arcp -> arc_time *= parentp -> propfraction;
3281590Srgrimes	arcp -> arc_childtime *= parentp -> propfraction;
3291590Srgrimes	    /*
3301590Srgrimes	     *	add this share to the parent's cycle header, if any.
3311590Srgrimes	     */
3321590Srgrimes	if ( parentp -> cyclehead != parentp ) {
3331590Srgrimes	    parentp -> cyclehead -> childtime += share;
3341590Srgrimes	    parentp -> cyclehead -> propchild += propshare;
3351590Srgrimes	}
3361590Srgrimes#	ifdef DEBUG
3371590Srgrimes	    if ( debug & PROPDEBUG ) {
3381590Srgrimes		printf( "[dotime] child \t" );
3391590Srgrimes		printname( childp );
3401590Srgrimes		printf( " with %f %f %d/%d\n" ,
3411590Srgrimes			childp -> time , childp -> childtime ,
3421590Srgrimes			arcp -> arc_count , childp -> npropcall );
3431590Srgrimes		printf( "[dotime] parent\t" );
3441590Srgrimes		printname( parentp );
3451590Srgrimes		printf( "\n[dotime] share %f\n" , share );
3461590Srgrimes	    }
3471590Srgrimes#	endif DEBUG
3481590Srgrimes    }
3491590Srgrimes}
3501590Srgrimes
3511590Srgrimescyclelink()
3521590Srgrimes{
3531590Srgrimes    register nltype	*nlp;
3541590Srgrimes    register nltype	*cyclenlp;
3551590Srgrimes    int			cycle;
3561590Srgrimes    nltype		*memberp;
3571590Srgrimes    arctype		*arcp;
3581590Srgrimes
3591590Srgrimes	/*
3601590Srgrimes	 *	Count the number of cycles, and initialze the cycle lists
3611590Srgrimes	 */
3621590Srgrimes    ncycle = 0;
3631590Srgrimes    for ( nlp = nl ; nlp < npe ; nlp++ ) {
3641590Srgrimes	    /*
3651590Srgrimes	     *	this is how you find unattached cycles
3661590Srgrimes	     */
3671590Srgrimes	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
3681590Srgrimes	    ncycle += 1;
3691590Srgrimes	}
3701590Srgrimes    }
3711590Srgrimes	/*
3721590Srgrimes	 *	cyclenl is indexed by cycle number:
3731590Srgrimes	 *	i.e. it is origin 1, not origin 0.
3741590Srgrimes	 */
3751590Srgrimes    cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
3761590Srgrimes    if ( cyclenl == 0 ) {
3771590Srgrimes	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
3781590Srgrimes		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
3791590Srgrimes	done();
3801590Srgrimes    }
3811590Srgrimes	/*
3821590Srgrimes	 *	now link cycles to true cycleheads,
3831590Srgrimes	 *	number them, accumulate the data for the cycle
3841590Srgrimes	 */
3851590Srgrimes    cycle = 0;
3861590Srgrimes    for ( nlp = nl ; nlp < npe ; nlp++ ) {
3871590Srgrimes	if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) {
3881590Srgrimes	    continue;
3891590Srgrimes	}
3901590Srgrimes	cycle += 1;
3911590Srgrimes	cyclenlp = &cyclenl[cycle];
3921590Srgrimes        cyclenlp -> name = 0;		/* the name */
3931590Srgrimes        cyclenlp -> value = 0;		/* the pc entry point */
3941590Srgrimes        cyclenlp -> time = 0.0;		/* ticks in this routine */
3951590Srgrimes        cyclenlp -> childtime = 0.0;	/* cumulative ticks in children */
3961590Srgrimes	cyclenlp -> ncall = 0;		/* how many times called */
3971590Srgrimes	cyclenlp -> selfcalls = 0;	/* how many calls to self */
3981590Srgrimes	cyclenlp -> propfraction = 0.0;	/* what % of time propagates */
3991590Srgrimes	cyclenlp -> propself = 0.0;	/* how much self time propagates */
4001590Srgrimes	cyclenlp -> propchild = 0.0;	/* how much child time propagates */
4011590Srgrimes	cyclenlp -> printflag = TRUE;	/* should this be printed? */
4021590Srgrimes	cyclenlp -> index = 0;		/* index in the graph list */
4031590Srgrimes	cyclenlp -> toporder = DFN_NAN;	/* graph call chain top-sort order */
4041590Srgrimes	cyclenlp -> cycleno = cycle;	/* internal number of cycle on */
4051590Srgrimes	cyclenlp -> cyclehead = cyclenlp;	/* pointer to head of cycle */
4061590Srgrimes	cyclenlp -> cnext = nlp;	/* pointer to next member of cycle */
4071590Srgrimes	cyclenlp -> parents = 0;	/* list of caller arcs */
4081590Srgrimes	cyclenlp -> children = 0;	/* list of callee arcs */
4091590Srgrimes#	ifdef DEBUG
4101590Srgrimes	    if ( debug & CYCLEDEBUG ) {
4111590Srgrimes		printf( "[cyclelink] " );
4121590Srgrimes		printname( nlp );
4131590Srgrimes		printf( " is the head of cycle %d\n" , cycle );
4141590Srgrimes	    }
4151590Srgrimes#	endif DEBUG
4161590Srgrimes	    /*
4171590Srgrimes	     *	link members to cycle header
4181590Srgrimes	     */
4191590Srgrimes	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4201590Srgrimes	    memberp -> cycleno = cycle;
4211590Srgrimes	    memberp -> cyclehead = cyclenlp;
4221590Srgrimes	}
4231590Srgrimes	    /*
4241590Srgrimes	     *	count calls from outside the cycle
4251590Srgrimes	     *	and those among cycle members
4261590Srgrimes	     */
4271590Srgrimes	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4281590Srgrimes	    for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
4291590Srgrimes		if ( arcp -> arc_parentp == memberp ) {
4301590Srgrimes		    continue;
4311590Srgrimes		}
4321590Srgrimes		if ( arcp -> arc_parentp -> cycleno == cycle ) {
4331590Srgrimes		    cyclenlp -> selfcalls += arcp -> arc_count;
4341590Srgrimes		} else {
4351590Srgrimes		    cyclenlp -> npropcall += arcp -> arc_count;
4361590Srgrimes		}
4371590Srgrimes	    }
4381590Srgrimes	}
4391590Srgrimes    }
4401590Srgrimes}
4411590Srgrimes
4421590Srgrimes    /*
4431590Srgrimes     *	analyze cycles to determine breakup
4441590Srgrimes     */
4451590Srgrimescycleanalyze()
4461590Srgrimes{
4471590Srgrimes    arctype	**cyclestack;
4481590Srgrimes    arctype	**stkp;
4491590Srgrimes    arctype	**arcpp;
4501590Srgrimes    arctype	**endlist;
4511590Srgrimes    arctype	*arcp;
4521590Srgrimes    nltype	*nlp;
4531590Srgrimes    cltype	*clp;
4541590Srgrimes    bool	ret;
4551590Srgrimes    bool	done;
4561590Srgrimes    int		size;
4571590Srgrimes    int		cycleno;
4581590Srgrimes
4591590Srgrimes	/*
4601590Srgrimes	 *	calculate the size of the cycle, and find nodes that
4611590Srgrimes	 *	exit the cycle as they are desirable targets to cut
4621590Srgrimes	 *	some of their parents
4631590Srgrimes	 */
4641590Srgrimes    for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) {
4651590Srgrimes	size = 0;
4661590Srgrimes	for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) {
4671590Srgrimes	    size += 1;
4681590Srgrimes	    nlp -> parentcnt = 0;
4691590Srgrimes	    nlp -> flags &= ~HASCYCLEXIT;
4701590Srgrimes	    for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) {
4711590Srgrimes		nlp -> parentcnt += 1;
4721590Srgrimes		if ( arcp -> arc_parentp -> cycleno != cycleno )
4731590Srgrimes		    nlp -> flags |= HASCYCLEXIT;
4741590Srgrimes	    }
4751590Srgrimes	}
4761590Srgrimes	if ( size <= cyclethreshold )
4771590Srgrimes	    continue;
4781590Srgrimes	done = FALSE;
4791590Srgrimes        cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) );
4801590Srgrimes	if ( cyclestack == 0 ) {
4811590Srgrimes	    fprintf( stderr , "%s: No room for %d bytes of cycle stack\n" ,
4821590Srgrimes		whoami , ( size + 1 ) * sizeof( arctype * ) );
4831590Srgrimes	    return;
4841590Srgrimes	}
4851590Srgrimes#	ifdef DEBUG
4861590Srgrimes	    if ( debug & BREAKCYCLE ) {
4871590Srgrimes		printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" ,
4881590Srgrimes		    cycleno , ncycle , size );
4891590Srgrimes	    }
4901590Srgrimes#	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	}
5181590Srgrimes#   endif DEBUG
5191590Srgrimes    return( done );
5201590Srgrimes}
5211590Srgrimes
5221590Srgrimesdescend( node , stkstart , stkp )
5231590Srgrimes    nltype	*node;
5241590Srgrimes    arctype	**stkstart;
5251590Srgrimes    arctype	**stkp;
5261590Srgrimes{
5271590Srgrimes    arctype	*arcp;
5281590Srgrimes    bool	ret;
5291590Srgrimes
5301590Srgrimes    for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) {
5311590Srgrimes#	ifdef DEBUG
5321590Srgrimes	    visited++;
5331590Srgrimes#	endif DEBUG
5341590Srgrimes	if ( arcp -> arc_childp -> cycleno != node -> cycleno
5351590Srgrimes	    || ( arcp -> arc_childp -> flags & VISITED )
5361590Srgrimes	    || ( arcp -> arc_flags & DEADARC ) )
5371590Srgrimes	    continue;
5381590Srgrimes#	ifdef DEBUG
5391590Srgrimes	    viable++;
5401590Srgrimes#	endif DEBUG
5411590Srgrimes	*stkp = arcp;
5421590Srgrimes	if ( arcp -> arc_childp -> flags & CYCLEHEAD ) {
5431590Srgrimes	    if ( addcycle( stkstart , stkp ) == FALSE )
5441590Srgrimes		return( FALSE );
5451590Srgrimes	    continue;
5461590Srgrimes	}
5471590Srgrimes	arcp -> arc_childp -> flags |= VISITED;
5481590Srgrimes	ret = descend( arcp -> arc_childp , stkstart , stkp + 1 );
5491590Srgrimes	arcp -> arc_childp -> flags &= ~VISITED;
5501590Srgrimes	if ( ret == FALSE )
5511590Srgrimes	    return( FALSE );
5521590Srgrimes    }
5531590Srgrimes}
5541590Srgrimes
5551590Srgrimesaddcycle( stkstart , stkend )
5561590Srgrimes    arctype	**stkstart;
5571590Srgrimes    arctype	**stkend;
5581590Srgrimes{
5591590Srgrimes    arctype	**arcpp;
5601590Srgrimes    arctype	**stkloc;
5611590Srgrimes    arctype	**stkp;
5621590Srgrimes    arctype	**endlist;
5631590Srgrimes    arctype	*minarc;
5641590Srgrimes    arctype	*arcp;
5651590Srgrimes    cltype	*clp;
5661590Srgrimes    int		size;
5671590Srgrimes
5681590Srgrimes    size = stkend - stkstart + 1;
5691590Srgrimes    if ( size <= 1 )
5701590Srgrimes	return( TRUE );
5711590Srgrimes    for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) {
5721590Srgrimes	if ( *arcpp > minarc )
5731590Srgrimes	    continue;
5741590Srgrimes	minarc = *arcpp;
5751590Srgrimes	stkloc = arcpp;
5761590Srgrimes    }
5771590Srgrimes    for ( clp = cyclehead ; clp ; clp = clp -> next ) {
5781590Srgrimes	if ( clp -> size != size )
5791590Srgrimes	    continue;
5801590Srgrimes	stkp = stkloc;
5811590Srgrimes	endlist = &clp -> list[ size ];
5821590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
5831590Srgrimes	    if ( *stkp++ != *arcpp )
5841590Srgrimes		break;
5851590Srgrimes	    if ( stkp > stkend )
5861590Srgrimes		stkp = stkstart;
5871590Srgrimes	}
5881590Srgrimes	if ( arcpp == endlist ) {
5891590Srgrimes#	    ifdef DEBUG
5901590Srgrimes		oldcycle++;
5911590Srgrimes#	    endif DEBUG
5921590Srgrimes	    return( TRUE );
5931590Srgrimes	}
5941590Srgrimes    }
5951590Srgrimes    clp = (cltype *)
5961590Srgrimes	calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
5971590Srgrimes    if ( clp == 0 ) {
5981590Srgrimes	fprintf( stderr , "%s: No room for %d bytes of subcycle storage\n" ,
5991590Srgrimes	    whoami , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
6001590Srgrimes	return( FALSE );
6011590Srgrimes    }
6021590Srgrimes    stkp = stkloc;
6031590Srgrimes    endlist = &clp -> list[ size ];
6041590Srgrimes    for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
6051590Srgrimes	arcp = *arcpp = *stkp++;
6061590Srgrimes	if ( stkp > stkend )
6071590Srgrimes	    stkp = stkstart;
6081590Srgrimes	arcp -> arc_cyclecnt++;
6091590Srgrimes	if ( ( arcp -> arc_flags & ONLIST ) == 0 ) {
6101590Srgrimes	    arcp -> arc_flags |= ONLIST;
6111590Srgrimes	    arcp -> arc_next = archead;
6121590Srgrimes	    archead = arcp;
6131590Srgrimes	}
6141590Srgrimes    }
6151590Srgrimes    clp -> size = size;
6161590Srgrimes    clp -> next = cyclehead;
6171590Srgrimes    cyclehead = clp;
6181590Srgrimes#   ifdef DEBUG
6191590Srgrimes	newcycle++;
6201590Srgrimes	if ( debug & SUBCYCLELIST ) {
6211590Srgrimes	    printsubcycle( clp );
6221590Srgrimes	}
6231590Srgrimes#   endif DEBUG
6241590Srgrimes    cyclecnt++;
6251590Srgrimes    if ( cyclecnt >= CYCLEMAX )
6261590Srgrimes	return( FALSE );
6271590Srgrimes    return( TRUE );
6281590Srgrimes}
6291590Srgrimes
6301590Srgrimescompresslist()
6311590Srgrimes{
6321590Srgrimes    cltype	*clp;
6331590Srgrimes    cltype	**prev;
6341590Srgrimes    arctype	**arcpp;
6351590Srgrimes    arctype	**endlist;
6361590Srgrimes    arctype	*arcp;
6371590Srgrimes    arctype	*maxarcp;
6381590Srgrimes    arctype	*maxexitarcp;
6391590Srgrimes    arctype	*maxwithparentarcp;
6401590Srgrimes    arctype	*maxnoparentarcp;
6411590Srgrimes    int		maxexitcnt;
6421590Srgrimes    int		maxwithparentcnt;
6431590Srgrimes    int		maxnoparentcnt;
6441590Srgrimes    char	*type;
6451590Srgrimes
6461590Srgrimes    maxexitcnt = 0;
6471590Srgrimes    maxwithparentcnt = 0;
6481590Srgrimes    maxnoparentcnt = 0;
6491590Srgrimes    for ( endlist = &archead , arcp = archead ; arcp ; ) {
6501590Srgrimes	if ( arcp -> arc_cyclecnt == 0 ) {
6511590Srgrimes	    arcp -> arc_flags &= ~ONLIST;
6521590Srgrimes	    *endlist = arcp -> arc_next;
6531590Srgrimes	    arcp -> arc_next = 0;
6541590Srgrimes	    arcp = *endlist;
6551590Srgrimes	    continue;
6561590Srgrimes	}
6571590Srgrimes	if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) {
6581590Srgrimes	    if ( arcp -> arc_cyclecnt > maxexitcnt ||
6591590Srgrimes		( arcp -> arc_cyclecnt == maxexitcnt &&
6601590Srgrimes		arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) {
6611590Srgrimes		maxexitcnt = arcp -> arc_cyclecnt;
6621590Srgrimes		maxexitarcp = arcp;
6631590Srgrimes	    }
6641590Srgrimes	} else if ( arcp -> arc_childp -> parentcnt > 1 ) {
6651590Srgrimes	    if ( arcp -> arc_cyclecnt > maxwithparentcnt ||
6661590Srgrimes		( arcp -> arc_cyclecnt == maxwithparentcnt &&
6671590Srgrimes		arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) {
6681590Srgrimes		maxwithparentcnt = arcp -> arc_cyclecnt;
6691590Srgrimes		maxwithparentarcp = arcp;
6701590Srgrimes	    }
6711590Srgrimes	} else {
6721590Srgrimes	    if ( arcp -> arc_cyclecnt > maxnoparentcnt ||
6731590Srgrimes		( arcp -> arc_cyclecnt == maxnoparentcnt &&
6741590Srgrimes		arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) {
6751590Srgrimes		maxnoparentcnt = arcp -> arc_cyclecnt;
6761590Srgrimes		maxnoparentarcp = arcp;
6771590Srgrimes	    }
6781590Srgrimes	}
6791590Srgrimes	endlist = &arcp -> arc_next;
6801590Srgrimes	arcp = arcp -> arc_next;
6811590Srgrimes    }
6821590Srgrimes    if ( maxexitcnt > 0 ) {
6831590Srgrimes	/*
6841590Srgrimes	 *	first choice is edge leading to node with out-of-cycle parent
6851590Srgrimes	 */
6861590Srgrimes	maxarcp = maxexitarcp;
6871590Srgrimes#	ifdef DEBUG
6881590Srgrimes	    type = "exit";
6891590Srgrimes#	endif DEBUG
6901590Srgrimes    } else if ( maxwithparentcnt > 0 ) {
6911590Srgrimes	/*
6921590Srgrimes	 *	second choice is edge leading to node with at least one
6931590Srgrimes	 *	other in-cycle parent
6941590Srgrimes	 */
6951590Srgrimes	maxarcp = maxwithparentarcp;
6961590Srgrimes#	ifdef DEBUG
6971590Srgrimes	    type = "internal";
6981590Srgrimes#	endif DEBUG
6991590Srgrimes    } else {
7001590Srgrimes	/*
7011590Srgrimes	 *	last choice is edge leading to node with only this arc as
7021590Srgrimes	 *	a parent (as it will now be orphaned)
7031590Srgrimes	 */
7041590Srgrimes	maxarcp = maxnoparentarcp;
7051590Srgrimes#	ifdef DEBUG
7061590Srgrimes	    type = "orphan";
7071590Srgrimes#	endif DEBUG
7081590Srgrimes    }
7091590Srgrimes    maxarcp -> arc_flags |= DEADARC;
7101590Srgrimes    maxarcp -> arc_childp -> parentcnt -= 1;
7111590Srgrimes    maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count;
7121590Srgrimes#   ifdef DEBUG
7131590Srgrimes	if ( debug & BREAKCYCLE ) {
7141590Srgrimes	    printf( "%s delete %s arc: %s (%d) -> %s from %d cycle(s)\n" ,
7151590Srgrimes		"[compresslist]" , type , maxarcp -> arc_parentp -> name ,
7161590Srgrimes		maxarcp -> arc_count , maxarcp -> arc_childp -> name ,
7171590Srgrimes		maxarcp -> arc_cyclecnt );
7181590Srgrimes	}
7191590Srgrimes#   endif DEBUG
7201590Srgrimes    printf( "\t%s to %s with %d calls\n" , maxarcp -> arc_parentp -> name ,
7211590Srgrimes	maxarcp -> arc_childp -> name , maxarcp -> arc_count );
7221590Srgrimes    prev = &cyclehead;
7231590Srgrimes    for ( clp = cyclehead ; clp ; ) {
7241590Srgrimes	endlist = &clp -> list[ clp -> size ];
7251590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
7261590Srgrimes	    if ( (*arcpp) -> arc_flags & DEADARC )
7271590Srgrimes		break;
7281590Srgrimes	if ( arcpp == endlist ) {
7291590Srgrimes	    prev = &clp -> next;
7301590Srgrimes	    clp = clp -> next;
7311590Srgrimes	    continue;
7321590Srgrimes	}
7331590Srgrimes	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
7341590Srgrimes	    (*arcpp) -> arc_cyclecnt--;
7351590Srgrimes	cyclecnt--;
7361590Srgrimes	*prev = clp -> next;
7371590Srgrimes	clp = clp -> next;
7381590Srgrimes	free( clp );
7391590Srgrimes    }
7401590Srgrimes}
7411590Srgrimes
7421590Srgrimes#ifdef DEBUG
7431590Srgrimesprintsubcycle( clp )
7441590Srgrimes    cltype	*clp;
7451590Srgrimes{
7461590Srgrimes    arctype	**arcpp;
7471590Srgrimes    arctype	**endlist;
7481590Srgrimes
7491590Srgrimes    arcpp = clp -> list;
7501590Srgrimes    printf( "%s <cycle %d>\n" , (*arcpp) -> arc_parentp -> name ,
7511590Srgrimes	(*arcpp) -> arc_parentp -> cycleno ) ;
7521590Srgrimes    for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ )
7531590Srgrimes	printf( "\t(%d) -> %s\n" , (*arcpp) -> arc_count ,
7541590Srgrimes	    (*arcpp) -> arc_childp -> name ) ;
7551590Srgrimes}
7561590Srgrimes#endif DEBUG
7571590Srgrimes
7581590Srgrimescycletime()
7591590Srgrimes{
7601590Srgrimes    int			cycle;
7611590Srgrimes    nltype		*cyclenlp;
7621590Srgrimes    nltype		*childp;
7631590Srgrimes
7641590Srgrimes    for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
7651590Srgrimes	cyclenlp = &cyclenl[ cycle ];
7661590Srgrimes	for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
7671590Srgrimes	    if ( childp -> propfraction == 0.0 ) {
7681590Srgrimes		    /*
7691590Srgrimes		     * all members have the same propfraction except those
7701590Srgrimes		     *	that were excluded with -E
7711590Srgrimes		     */
7721590Srgrimes		continue;
7731590Srgrimes	    }
7741590Srgrimes	    cyclenlp -> time += childp -> time;
7751590Srgrimes	}
7761590Srgrimes	cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
7771590Srgrimes    }
7781590Srgrimes}
7791590Srgrimes
7801590Srgrimes    /*
7811590Srgrimes     *	in one top to bottom pass over the topologically sorted namelist
7821590Srgrimes     *	propagate:
7831590Srgrimes     *		printflag as the union of parents' printflags
7841590Srgrimes     *		propfraction as the sum of fractional parents' propfractions
7851590Srgrimes     *	and while we're here, sum time for functions.
7861590Srgrimes     */
7871590Srgrimesdoflags()
7881590Srgrimes{
7891590Srgrimes    int		index;
7901590Srgrimes    nltype	*childp;
7911590Srgrimes    nltype	*oldhead;
7921590Srgrimes
7931590Srgrimes    oldhead = 0;
7941590Srgrimes    for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
7951590Srgrimes	childp = topsortnlp[ index ];
7961590Srgrimes	    /*
7971590Srgrimes	     *	if we haven't done this function or cycle,
7981590Srgrimes	     *	inherit things from parent.
7991590Srgrimes	     *	this way, we are linear in the number of arcs
8001590Srgrimes	     *	since we do all members of a cycle (and the cycle itself)
8011590Srgrimes	     *	as we hit the first member of the cycle.
8021590Srgrimes	     */
8031590Srgrimes	if ( childp -> cyclehead != oldhead ) {
8041590Srgrimes	    oldhead = childp -> cyclehead;
8051590Srgrimes	    inheritflags( childp );
8061590Srgrimes	}
8071590Srgrimes#	ifdef DEBUG
8081590Srgrimes	    if ( debug & PROPDEBUG ) {
8091590Srgrimes		printf( "[doflags] " );
8101590Srgrimes		printname( childp );
8111590Srgrimes		printf( " inherits printflag %d and propfraction %f\n" ,
8121590Srgrimes			childp -> printflag , childp -> propfraction );
8131590Srgrimes	    }
8141590Srgrimes#	endif DEBUG
8151590Srgrimes	if ( ! childp -> printflag ) {
8161590Srgrimes		/*
8171590Srgrimes		 *	printflag is off
8181590Srgrimes		 *	it gets turned on by
8191590Srgrimes		 *	being on -f list,
8201590Srgrimes		 *	or there not being any -f list and not being on -e list.
8211590Srgrimes		 */
8221590Srgrimes	    if (   onlist( flist , childp -> name )
8231590Srgrimes		|| ( !fflag && !onlist( elist , childp -> name ) ) ) {
8241590Srgrimes		childp -> printflag = TRUE;
8251590Srgrimes	    }
8261590Srgrimes	} else {
8271590Srgrimes		/*
8281590Srgrimes		 *	this function has printing parents:
8291590Srgrimes		 *	maybe someone wants to shut it up
8301590Srgrimes		 *	by putting it on -e list.  (but favor -f over -e)
8311590Srgrimes		 */
8321590Srgrimes	    if (  ( !onlist( flist , childp -> name ) )
8331590Srgrimes		&& onlist( elist , childp -> name ) ) {
8341590Srgrimes		childp -> printflag = FALSE;
8351590Srgrimes	    }
8361590Srgrimes	}
8371590Srgrimes	if ( childp -> propfraction == 0.0 ) {
8381590Srgrimes		/*
8391590Srgrimes		 *	no parents to pass time to.
8401590Srgrimes		 *	collect time from children if
8411590Srgrimes		 *	its on -F list,
8421590Srgrimes		 *	or there isn't any -F list and its not on -E list.
8431590Srgrimes		 */
8441590Srgrimes	    if ( onlist( Flist , childp -> name )
8451590Srgrimes		|| ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
8461590Srgrimes		    childp -> propfraction = 1.0;
8471590Srgrimes	    }
8481590Srgrimes	} else {
8491590Srgrimes		/*
8501590Srgrimes		 *	it has parents to pass time to,
8511590Srgrimes		 *	but maybe someone wants to shut it up
8521590Srgrimes		 *	by puttting it on -E list.  (but favor -F over -E)
8531590Srgrimes		 */
8541590Srgrimes	    if (  !onlist( Flist , childp -> name )
8551590Srgrimes		&& onlist( Elist , childp -> name ) ) {
8561590Srgrimes		childp -> propfraction = 0.0;
8571590Srgrimes	    }
8581590Srgrimes	}
8591590Srgrimes	childp -> propself = childp -> time * childp -> propfraction;
8601590Srgrimes	printtime += childp -> propself;
8611590Srgrimes#	ifdef DEBUG
8621590Srgrimes	    if ( debug & PROPDEBUG ) {
8631590Srgrimes		printf( "[doflags] " );
8641590Srgrimes		printname( childp );
8651590Srgrimes		printf( " ends up with printflag %d and propfraction %f\n" ,
8661590Srgrimes			childp -> printflag , childp -> propfraction );
8671590Srgrimes		printf( "time %f propself %f printtime %f\n" ,
8681590Srgrimes			childp -> time , childp -> propself , printtime );
8691590Srgrimes	    }
8701590Srgrimes#	endif DEBUG
8711590Srgrimes    }
8721590Srgrimes}
8731590Srgrimes
8741590Srgrimes    /*
8751590Srgrimes     *	check if any parent of this child
8761590Srgrimes     *	(or outside parents of this cycle)
8771590Srgrimes     *	have their print flags on and set the
8781590Srgrimes     *	print flag of the child (cycle) appropriately.
8791590Srgrimes     *	similarly, deal with propagation fractions from parents.
8801590Srgrimes     */
8811590Srgrimesinheritflags( childp )
8821590Srgrimes    nltype	*childp;
8831590Srgrimes{
8841590Srgrimes    nltype	*headp;
8851590Srgrimes    arctype	*arcp;
8861590Srgrimes    nltype	*parentp;
8871590Srgrimes    nltype	*memp;
8881590Srgrimes
8891590Srgrimes    headp = childp -> cyclehead;
8901590Srgrimes    if ( childp == headp ) {
8911590Srgrimes	    /*
8921590Srgrimes	     *	just a regular child, check its parents
8931590Srgrimes	     */
8941590Srgrimes	childp -> printflag = FALSE;
8951590Srgrimes	childp -> propfraction = 0.0;
8961590Srgrimes	for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
8971590Srgrimes	    parentp = arcp -> arc_parentp;
8981590Srgrimes	    if ( childp == parentp ) {
8991590Srgrimes		continue;
9001590Srgrimes	    }
9011590Srgrimes	    childp -> printflag |= parentp -> printflag;
9021590Srgrimes		/*
9031590Srgrimes		 *	if the child was never actually called
9041590Srgrimes		 *	(e.g. this arc is static (and all others are, too))
9051590Srgrimes		 *	no time propagates along this arc.
9061590Srgrimes		 */
9071590Srgrimes	    if ( arcp -> arc_flags & DEADARC ) {
9081590Srgrimes		continue;
9091590Srgrimes	    }
9101590Srgrimes	    if ( childp -> npropcall ) {
9111590Srgrimes		childp -> propfraction += parentp -> propfraction
9121590Srgrimes					* ( ( (double) arcp -> arc_count )
9131590Srgrimes					  / ( (double) childp -> npropcall ) );
9141590Srgrimes	    }
9151590Srgrimes	}
9161590Srgrimes    } else {
9171590Srgrimes	    /*
9181590Srgrimes	     *	its a member of a cycle, look at all parents from
9191590Srgrimes	     *	outside the cycle
9201590Srgrimes	     */
9211590Srgrimes	headp -> printflag = FALSE;
9221590Srgrimes	headp -> propfraction = 0.0;
9231590Srgrimes	for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
9241590Srgrimes	    for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
9251590Srgrimes		if ( arcp -> arc_parentp -> cyclehead == headp ) {
9261590Srgrimes		    continue;
9271590Srgrimes		}
9281590Srgrimes		parentp = arcp -> arc_parentp;
9291590Srgrimes		headp -> printflag |= parentp -> printflag;
9301590Srgrimes		    /*
9311590Srgrimes		     *	if the cycle was never actually called
9321590Srgrimes		     *	(e.g. this arc is static (and all others are, too))
9331590Srgrimes		     *	no time propagates along this arc.
9341590Srgrimes		     */
9351590Srgrimes		if ( arcp -> arc_flags & DEADARC ) {
9361590Srgrimes		    continue;
9371590Srgrimes		}
9381590Srgrimes		if ( headp -> npropcall ) {
9391590Srgrimes		    headp -> propfraction += parentp -> propfraction
9401590Srgrimes					* ( ( (double) arcp -> arc_count )
9411590Srgrimes					  / ( (double) headp -> npropcall ) );
9421590Srgrimes		}
9431590Srgrimes	    }
9441590Srgrimes	}
9451590Srgrimes	for ( memp = headp ; memp ; memp = memp -> cnext ) {
9461590Srgrimes	    memp -> printflag = headp -> printflag;
9471590Srgrimes	    memp -> propfraction = headp -> propfraction;
9481590Srgrimes	}
9491590Srgrimes    }
9501590Srgrimes}
951