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