xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 62017)
121957Sdist /*
2*62017Sbostic  * Copyright (c) 1983, 1993
3*62017Sbostic  *	The Regents of the University of California.  All rights reserved.
434199Sbostic  *
542683Sbostic  * %sccs.include.redist.c%
621957Sdist  */
721957Sdist 
84508Speter #ifndef lint
9*62017Sbostic static char sccsid[] = "@(#)arcs.c	8.1 (Berkeley) 06/06/93";
1034199Sbostic #endif /* not lint */
114508Speter 
124561Speter #include "gprof.h"
134508Speter 
1452652Smckusick #ifdef DEBUG
1552652Smckusick int visited;
1652652Smckusick int viable;
1752652Smckusick int newcycle;
1852652Smckusick int oldcycle;
1952652Smckusick #endif DEBUG
2052652Smckusick 
214721Speter     /*
224721Speter      *	add (or just increment) an arc
234721Speter      */
addarc(parentp,childp,count)244721Speter addarc( parentp , childp , count )
254721Speter     nltype	*parentp;
264721Speter     nltype	*childp;
274721Speter     long	count;
284721Speter {
294721Speter     arctype		*arcp;
304721Speter 
314721Speter #   ifdef DEBUG
324721Speter 	if ( debug & TALLYDEBUG ) {
334721Speter 	    printf( "[addarc] %d arcs from %s to %s\n" ,
344721Speter 		    count , parentp -> name , childp -> name );
354721Speter 	}
364721Speter #   endif DEBUG
374721Speter     arcp = arclookup( parentp , childp );
384721Speter     if ( arcp != 0 ) {
394721Speter 	    /*
404721Speter 	     *	a hit:  just increment the count.
414721Speter 	     */
424721Speter #	ifdef DEBUG
434721Speter 	    if ( debug & TALLYDEBUG ) {
444721Speter 		printf( "[tally] hit %d += %d\n" ,
454721Speter 			arcp -> arc_count , count );
464721Speter 	    }
474721Speter #	endif DEBUG
484721Speter 	arcp -> arc_count += count;
494721Speter 	return;
504721Speter     }
5154805Storek     arcp = (arctype *)calloc( 1 , sizeof *arcp );
524721Speter     arcp -> arc_parentp = parentp;
534721Speter     arcp -> arc_childp = childp;
544721Speter     arcp -> arc_count = count;
554721Speter 	/*
564721Speter 	 *	prepend this child to the children of this parent
574721Speter 	 */
584721Speter     arcp -> arc_childlist = parentp -> children;
594721Speter     parentp -> children = arcp;
604721Speter 	/*
614721Speter 	 *	prepend this parent to the parents of this child
624721Speter 	 */
634721Speter     arcp -> arc_parentlist = childp -> parents;
644721Speter     childp -> parents = arcp;
654721Speter }
664721Speter 
677172Speter     /*
687172Speter      *	the code below topologically sorts the graph (collapsing cycles),
697172Speter      *	and propagates time bottom up and flags top down.
707172Speter      */
717172Speter 
727172Speter     /*
737172Speter      *	the topologically sorted name list pointers
747172Speter      */
757172Speter nltype	**topsortnlp;
767172Speter 
topcmp(npp1,npp2)774508Speter topcmp( npp1 , npp2 )
784508Speter     nltype	**npp1;
794508Speter     nltype	**npp2;
804508Speter {
814508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
824508Speter }
834508Speter 
8416850Smckusick nltype **
doarcs()854508Speter doarcs()
864508Speter {
8716850Smckusick     nltype	*parentp, **timesortnlp;
884508Speter     arctype	*arcp;
894508Speter     long	index;
9052652Smckusick     long	pass;
914508Speter 
924508Speter 	/*
934508Speter 	 *	initialize various things:
944508Speter 	 *	    zero out child times.
954508Speter 	 *	    count self-recursive calls.
964508Speter 	 *	    indicate that nothing is on cycles.
974508Speter 	 */
984508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
994508Speter 	parentp -> childtime = 0.0;
1004508Speter 	arcp = arclookup( parentp , parentp );
1014508Speter 	if ( arcp != 0 ) {
1024508Speter 	    parentp -> ncall -= arcp -> arc_count;
1034508Speter 	    parentp -> selfcalls = arcp -> arc_count;
1044508Speter 	} else {
1054508Speter 	    parentp -> selfcalls = 0;
1064508Speter 	}
10752652Smckusick 	parentp -> npropcall = parentp -> ncall;
1087221Speter 	parentp -> propfraction = 0.0;
1097221Speter 	parentp -> propself = 0.0;
1107221Speter 	parentp -> propchild = 0.0;
1117172Speter 	parentp -> printflag = FALSE;
11210284Speter 	parentp -> toporder = DFN_NAN;
1134508Speter 	parentp -> cycleno = 0;
1144508Speter 	parentp -> cyclehead = parentp;
1154508Speter 	parentp -> cnext = 0;
1167172Speter 	if ( cflag ) {
11725713Ssam 	    findcall( parentp , parentp -> value , (parentp+1) -> value );
1187172Speter 	}
1194508Speter     }
12052652Smckusick     for ( pass = 1 ; ; pass++ ) {
12152652Smckusick 	    /*
12252652Smckusick 	     *	topologically order things
12352652Smckusick 	     *	if any node is unnumbered,
12452652Smckusick 	     *	    number it and any of its descendents.
12552652Smckusick 	     */
12652652Smckusick 	for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) {
12752652Smckusick 	    if ( parentp -> toporder == DFN_NAN ) {
12852652Smckusick 		dfn( parentp );
12952652Smckusick 	    }
1304508Speter 	}
13152652Smckusick 	    /*
13252652Smckusick 	     *	link together nodes on the same cycle
13352652Smckusick 	     */
13452652Smckusick 	cyclelink();
13552652Smckusick 	    /*
13652652Smckusick 	     *	if no cycles to break up, proceed
13752652Smckusick 	     */
13852652Smckusick 	if ( ! Cflag )
13952652Smckusick 	    break;
14052652Smckusick 	    /*
14152652Smckusick 	     *	analyze cycles to determine breakup
14252652Smckusick 	     */
14352652Smckusick #	ifdef DEBUG
14452652Smckusick 	    if ( debug & BREAKCYCLE ) {
14552652Smckusick 		printf("[doarcs] pass %d, cycle(s) %d\n" , pass , ncycle );
14652652Smckusick 	    }
14752652Smckusick #	endif DEBUG
14852652Smckusick 	if ( pass == 1 ) {
14952652Smckusick 	    printf( "\n\n%s %s\n%s %d:\n" ,
15052652Smckusick 		"The following arcs were deleted" ,
15152652Smckusick 		"from the propagation calculation" ,
15252652Smckusick 		"to reduce the maximum cycle size to", cyclethreshold );
15352652Smckusick 	}
15452652Smckusick 	if ( cycleanalyze() )
15552652Smckusick 	    break;
15652652Smckusick 	free ( cyclenl );
15752652Smckusick 	ncycle = 0;
15852652Smckusick 	for ( parentp = nl ; parentp < npe ; parentp++ ) {
15952652Smckusick 	    parentp -> toporder = DFN_NAN;
16052652Smckusick 	    parentp -> cycleno = 0;
16152652Smckusick 	    parentp -> cyclehead = parentp;
16252652Smckusick 	    parentp -> cnext = 0;
16352652Smckusick 	}
1644508Speter     }
16552652Smckusick     if ( pass > 1 ) {
16652652Smckusick 	printf( "\f\n" );
16752652Smckusick     } else {
16852652Smckusick 	printf( "\tNone\n\n" );
16952652Smckusick     }
1704508Speter 	/*
1714508Speter 	 *	Sort the symbol table in reverse topological order
1724508Speter 	 */
1734508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1744508Speter     if ( topsortnlp == (nltype **) 0 ) {
1754508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1764508Speter     }
1774508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1784508Speter 	topsortnlp[ index ] = &nl[ index ];
1794508Speter     }
1804508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1814508Speter #   ifdef DEBUG
1824508Speter 	if ( debug & DFNDEBUG ) {
1834508Speter 	    printf( "[doarcs] topological sort listing\n" );
1844508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1854508Speter 		printf( "[doarcs] " );
1864508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1874508Speter 		printname( topsortnlp[ index ] );
1884508Speter 		printf( "\n" );
1894508Speter 	    }
1904508Speter 	}
1914508Speter #   endif DEBUG
1924508Speter 	/*
1937221Speter 	 *	starting from the topological top,
1947221Speter 	 *	propagate print flags to children.
1957221Speter 	 *	also, calculate propagation fractions.
1967221Speter 	 *	this happens before time propagation
1977221Speter 	 *	since time propagation uses the fractions.
1987221Speter 	 */
1997221Speter     doflags();
2007221Speter 	/*
2014508Speter 	 *	starting from the topological bottom,
2027172Speter 	 *	propogate children times up to parents.
2034508Speter 	 */
2047172Speter     dotime();
20516850Smckusick 	/*
20616850Smckusick 	 *	Now, sort by propself + propchild.
20716850Smckusick 	 *	sorting both the regular function names
20816850Smckusick 	 *	and cycle headers.
20916850Smckusick 	 */
21016850Smckusick     timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
21116850Smckusick     if ( timesortnlp == (nltype **) 0 ) {
21216850Smckusick 	fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
21316850Smckusick     }
21416850Smckusick     for ( index = 0 ; index < nname ; index++ ) {
21516850Smckusick 	timesortnlp[index] = &nl[index];
21616850Smckusick     }
21716850Smckusick     for ( index = 1 ; index <= ncycle ; index++ ) {
21816850Smckusick 	timesortnlp[nname+index-1] = &cyclenl[index];
21916850Smckusick     }
22016850Smckusick     qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
22116850Smckusick     for ( index = 0 ; index < nname + ncycle ; index++ ) {
22216850Smckusick 	timesortnlp[ index ] -> index = index + 1;
22316850Smckusick     }
22416850Smckusick     return( timesortnlp );
2257172Speter }
2267172Speter 
dotime()2277172Speter dotime()
2287172Speter {
2297172Speter     int	index;
2307172Speter 
2317172Speter     cycletime();
2324508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
2337172Speter 	timepropagate( topsortnlp[ index ] );
2347127Speter     }
2357127Speter }
2367127Speter 
timepropagate(parentp)2377172Speter timepropagate( parentp )
2387127Speter     nltype	*parentp;
2397127Speter {
2407127Speter     arctype	*arcp;
2417127Speter     nltype	*childp;
2427127Speter     double	share;
2437221Speter     double	propshare;
2447127Speter 
2457221Speter     if ( parentp -> propfraction == 0.0 ) {
2467221Speter 	return;
2477221Speter     }
2487127Speter 	/*
2497127Speter 	 *	gather time from children of this parent.
2507127Speter 	 */
2517172Speter     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
2527127Speter 	childp = arcp -> arc_childp;
25352652Smckusick 	if ( arcp -> arc_flags & DEADARC ) {
25452652Smckusick 	    continue;
25552652Smckusick 	}
2567127Speter 	if ( arcp -> arc_count == 0 ) {
2577127Speter 	    continue;
2587127Speter 	}
2597221Speter 	if ( childp == parentp ) {
2607127Speter 	    continue;
2617127Speter 	}
2627221Speter 	if ( childp -> propfraction == 0.0 ) {
2637127Speter 	    continue;
2647127Speter 	}
2657127Speter 	if ( childp -> cyclehead != childp ) {
2667127Speter 	    if ( parentp -> cycleno == childp -> cycleno ) {
2677127Speter 		continue;
2687127Speter 	    }
2697127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2707127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2714508Speter 	    }
2727127Speter 	    childp = childp -> cyclehead;
2737127Speter 	} else {
2747127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2757127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2764508Speter 		continue;
2774508Speter 	    }
2787127Speter 	}
27952652Smckusick 	if ( childp -> npropcall == 0 ) {
2807221Speter 	    continue;
2817221Speter 	}
2827127Speter 	    /*
2837127Speter 	     *	distribute time for this arc
2847127Speter 	     */
2857221Speter 	arcp -> arc_time = childp -> time
2867221Speter 			        * ( ( (double) arcp -> arc_count ) /
28752652Smckusick 				    ( (double) childp -> npropcall ) );
2887221Speter 	arcp -> arc_childtime = childp -> childtime
2897221Speter 			        * ( ( (double) arcp -> arc_count ) /
29052652Smckusick 				    ( (double) childp -> npropcall ) );
2917127Speter 	share = arcp -> arc_time + arcp -> arc_childtime;
2927127Speter 	parentp -> childtime += share;
2937127Speter 	    /*
2947221Speter 	     *	( 1 - propfraction ) gets lost along the way
2957127Speter 	     */
2967221Speter 	propshare = parentp -> propfraction * share;
2977221Speter 	    /*
2987221Speter 	     *	fix things for printing
2997221Speter 	     */
3007221Speter 	parentp -> propchild += propshare;
3017221Speter 	arcp -> arc_time *= parentp -> propfraction;
3027221Speter 	arcp -> arc_childtime *= parentp -> propfraction;
3037221Speter 	    /*
3047221Speter 	     *	add this share to the parent's cycle header, if any.
3057221Speter 	     */
3067127Speter 	if ( parentp -> cyclehead != parentp ) {
3077127Speter 	    parentp -> cyclehead -> childtime += share;
3087221Speter 	    parentp -> cyclehead -> propchild += propshare;
3094508Speter 	}
3107221Speter #	ifdef DEBUG
3117221Speter 	    if ( debug & PROPDEBUG ) {
3127221Speter 		printf( "[dotime] child \t" );
3137221Speter 		printname( childp );
3147221Speter 		printf( " with %f %f %d/%d\n" ,
3157221Speter 			childp -> time , childp -> childtime ,
31652652Smckusick 			arcp -> arc_count , childp -> npropcall );
3177221Speter 		printf( "[dotime] parent\t" );
3187221Speter 		printname( parentp );
3197221Speter 		printf( "\n[dotime] share %f\n" , share );
3207221Speter 	    }
3217221Speter #	endif DEBUG
3224508Speter     }
3234508Speter }
3244508Speter 
cyclelink()3254508Speter cyclelink()
3264508Speter {
3274508Speter     register nltype	*nlp;
3284508Speter     register nltype	*cyclenlp;
3294508Speter     int			cycle;
3307172Speter     nltype		*memberp;
3317248Speter     arctype		*arcp;
3324508Speter 
3334508Speter 	/*
3344508Speter 	 *	Count the number of cycles, and initialze the cycle lists
3354508Speter 	 */
3367127Speter     ncycle = 0;
3374508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
3384508Speter 	    /*
3394508Speter 	     *	this is how you find unattached cycles
3404508Speter 	     */
3414508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
3427127Speter 	    ncycle += 1;
3434508Speter 	}
3444508Speter     }
3457127Speter 	/*
3467127Speter 	 *	cyclenl is indexed by cycle number:
3477127Speter 	 *	i.e. it is origin 1, not origin 0.
3487127Speter 	 */
3497127Speter     cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
3507127Speter     if ( cyclenl == 0 ) {
3517127Speter 	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
3527127Speter 		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
3537127Speter 	done();
3544508Speter     }
3554508Speter 	/*
3564508Speter 	 *	now link cycles to true cycleheads,
3574508Speter 	 *	number them, accumulate the data for the cycle
3584508Speter 	 */
3594508Speter     cycle = 0;
3604508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
36110284Speter 	if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) {
3624508Speter 	    continue;
3634508Speter 	}
3644508Speter 	cycle += 1;
3657127Speter 	cyclenlp = &cyclenl[cycle];
3667249Speter         cyclenlp -> name = 0;		/* the name */
3677221Speter         cyclenlp -> value = 0;		/* the pc entry point */
3687221Speter         cyclenlp -> time = 0.0;		/* ticks in this routine */
3697221Speter         cyclenlp -> childtime = 0.0;	/* cumulative ticks in children */
3707221Speter 	cyclenlp -> ncall = 0;		/* how many times called */
3717221Speter 	cyclenlp -> selfcalls = 0;	/* how many calls to self */
3727221Speter 	cyclenlp -> propfraction = 0.0;	/* what % of time propagates */
3737221Speter 	cyclenlp -> propself = 0.0;	/* how much self time propagates */
3747221Speter 	cyclenlp -> propchild = 0.0;	/* how much child time propagates */
3757221Speter 	cyclenlp -> printflag = TRUE;	/* should this be printed? */
3767221Speter 	cyclenlp -> index = 0;		/* index in the graph list */
37710284Speter 	cyclenlp -> toporder = DFN_NAN;	/* graph call chain top-sort order */
3787221Speter 	cyclenlp -> cycleno = cycle;	/* internal number of cycle on */
3797221Speter 	cyclenlp -> cyclehead = cyclenlp;	/* pointer to head of cycle */
3807221Speter 	cyclenlp -> cnext = nlp;	/* pointer to next member of cycle */
3817221Speter 	cyclenlp -> parents = 0;	/* list of caller arcs */
3827221Speter 	cyclenlp -> children = 0;	/* list of callee arcs */
3834508Speter #	ifdef DEBUG
3844508Speter 	    if ( debug & CYCLEDEBUG ) {
3854508Speter 		printf( "[cyclelink] " );
3864508Speter 		printname( nlp );
3874508Speter 		printf( " is the head of cycle %d\n" , cycle );
3884508Speter 	    }
3894508Speter #	endif DEBUG
3907248Speter 	    /*
3917248Speter 	     *	link members to cycle header
3927248Speter 	     */
3937172Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
3947172Speter 	    memberp -> cycleno = cycle;
3957172Speter 	    memberp -> cyclehead = cyclenlp;
3967172Speter 	}
3977248Speter 	    /*
3987248Speter 	     *	count calls from outside the cycle
3997248Speter 	     *	and those among cycle members
4007248Speter 	     */
4017248Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4027248Speter 	    for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
4037248Speter 		if ( arcp -> arc_parentp == memberp ) {
4047248Speter 		    continue;
4057248Speter 		}
4067248Speter 		if ( arcp -> arc_parentp -> cycleno == cycle ) {
4077248Speter 		    cyclenlp -> selfcalls += arcp -> arc_count;
4087248Speter 		} else {
40952652Smckusick 		    cyclenlp -> npropcall += arcp -> arc_count;
4107248Speter 		}
4117248Speter 	    }
4127248Speter 	}
4137172Speter     }
4147172Speter }
4157172Speter 
41652652Smckusick     /*
41752652Smckusick      *	analyze cycles to determine breakup
41852652Smckusick      */
cycleanalyze()41952652Smckusick cycleanalyze()
42052652Smckusick {
42152652Smckusick     arctype	**cyclestack;
42252652Smckusick     arctype	**stkp;
42352652Smckusick     arctype	**arcpp;
42452652Smckusick     arctype	**endlist;
42552652Smckusick     arctype	*arcp;
42652652Smckusick     nltype	*nlp;
42752652Smckusick     cltype	*clp;
42852652Smckusick     bool	ret;
42952652Smckusick     bool	done;
43052652Smckusick     int		size;
43152652Smckusick     int		cycleno;
43252652Smckusick 
43352652Smckusick 	/*
43452652Smckusick 	 *	calculate the size of the cycle, and find nodes that
43552652Smckusick 	 *	exit the cycle as they are desirable targets to cut
43652652Smckusick 	 *	some of their parents
43752652Smckusick 	 */
43852652Smckusick     for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) {
43952652Smckusick 	size = 0;
44052652Smckusick 	for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) {
44152652Smckusick 	    size += 1;
44252652Smckusick 	    nlp -> parentcnt = 0;
44352652Smckusick 	    nlp -> flags &= ~HASCYCLEXIT;
44452652Smckusick 	    for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) {
44552652Smckusick 		nlp -> parentcnt += 1;
44652652Smckusick 		if ( arcp -> arc_parentp -> cycleno != cycleno )
44752652Smckusick 		    nlp -> flags |= HASCYCLEXIT;
44852652Smckusick 	    }
44952652Smckusick 	}
45052652Smckusick 	if ( size <= cyclethreshold )
45152652Smckusick 	    continue;
45252652Smckusick 	done = FALSE;
45352652Smckusick         cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) );
45452652Smckusick 	if ( cyclestack == 0 ) {
45552652Smckusick 	    fprintf( stderr , "%s: No room for %d bytes of cycle stack\n" ,
45652652Smckusick 		whoami , ( size + 1 ) * sizeof( arctype * ) );
45752652Smckusick 	    return;
45852652Smckusick 	}
45952652Smckusick #	ifdef DEBUG
46052652Smckusick 	    if ( debug & BREAKCYCLE ) {
46152652Smckusick 		printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" ,
46252652Smckusick 		    cycleno , ncycle , size );
46352652Smckusick 	    }
46452652Smckusick #	endif DEBUG
46552652Smckusick 	for ( nlp = cyclenl[ cycleno ] . cnext ; nlp ; nlp = nlp -> cnext ) {
46652652Smckusick 	    stkp = &cyclestack[0];
46752652Smckusick 	    nlp -> flags |= CYCLEHEAD;
46852652Smckusick 	    ret = descend ( nlp , cyclestack , stkp );
46952652Smckusick 	    nlp -> flags &= ~CYCLEHEAD;
47052652Smckusick 	    if ( ret == FALSE )
47152652Smckusick 		break;
47252652Smckusick 	}
47352652Smckusick 	free( cyclestack );
47452652Smckusick 	if ( cyclecnt > 0 ) {
47552652Smckusick 	    compresslist();
47652652Smckusick 	    for ( clp = cyclehead ; clp ; ) {
47752652Smckusick 		endlist = &clp -> list[ clp -> size ];
47852652Smckusick 		for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
47952652Smckusick 		    (*arcpp) -> arc_cyclecnt--;
48052652Smckusick 		cyclecnt--;
48152652Smckusick 		clp = clp -> next;
48252652Smckusick 		free( clp );
48352652Smckusick 	    }
48452652Smckusick 	    cyclehead = 0;
48552652Smckusick 	}
48652652Smckusick     }
48752652Smckusick #   ifdef DEBUG
48852652Smckusick 	if ( debug & BREAKCYCLE ) {
48952652Smckusick 	    printf("%s visited %d, viable %d, newcycle %d, oldcycle %d\n",
49052652Smckusick 		"[doarcs]" , visited , viable , newcycle , oldcycle);
49152652Smckusick 	}
49252652Smckusick #   endif DEBUG
49352652Smckusick     return( done );
49452652Smckusick }
49552652Smckusick 
descend(node,stkstart,stkp)49652652Smckusick descend( node , stkstart , stkp )
49752652Smckusick     nltype	*node;
49852652Smckusick     arctype	**stkstart;
49952652Smckusick     arctype	**stkp;
50052652Smckusick {
50152652Smckusick     arctype	*arcp;
50252652Smckusick     bool	ret;
50352652Smckusick 
50452652Smckusick     for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) {
50552652Smckusick #	ifdef DEBUG
50652652Smckusick 	    visited++;
50752652Smckusick #	endif DEBUG
50852652Smckusick 	if ( arcp -> arc_childp -> cycleno != node -> cycleno
50952652Smckusick 	    || ( arcp -> arc_childp -> flags & VISITED )
51052652Smckusick 	    || ( arcp -> arc_flags & DEADARC ) )
51152652Smckusick 	    continue;
51252652Smckusick #	ifdef DEBUG
51352652Smckusick 	    viable++;
51452652Smckusick #	endif DEBUG
51552652Smckusick 	*stkp = arcp;
51652652Smckusick 	if ( arcp -> arc_childp -> flags & CYCLEHEAD ) {
51752652Smckusick 	    if ( addcycle( stkstart , stkp ) == FALSE )
51852652Smckusick 		return( FALSE );
51952652Smckusick 	    continue;
52052652Smckusick 	}
52152652Smckusick 	arcp -> arc_childp -> flags |= VISITED;
52252652Smckusick 	ret = descend( arcp -> arc_childp , stkstart , stkp + 1 );
52352652Smckusick 	arcp -> arc_childp -> flags &= ~VISITED;
52452652Smckusick 	if ( ret == FALSE )
52552652Smckusick 	    return( FALSE );
52652652Smckusick     }
52752652Smckusick }
52852652Smckusick 
addcycle(stkstart,stkend)52952652Smckusick addcycle( stkstart , stkend )
53052652Smckusick     arctype	**stkstart;
53152652Smckusick     arctype	**stkend;
53252652Smckusick {
53352652Smckusick     arctype	**arcpp;
53452652Smckusick     arctype	**stkloc;
53552652Smckusick     arctype	**stkp;
53652652Smckusick     arctype	**endlist;
53752652Smckusick     arctype	*minarc;
53852652Smckusick     arctype	*arcp;
53952652Smckusick     cltype	*clp;
54052652Smckusick     int		size;
54152652Smckusick 
54252652Smckusick     size = stkend - stkstart + 1;
54352652Smckusick     if ( size <= 1 )
54452652Smckusick 	return( TRUE );
54552652Smckusick     for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) {
54652652Smckusick 	if ( *arcpp > minarc )
54752652Smckusick 	    continue;
54852652Smckusick 	minarc = *arcpp;
54952652Smckusick 	stkloc = arcpp;
55052652Smckusick     }
55152652Smckusick     for ( clp = cyclehead ; clp ; clp = clp -> next ) {
55252652Smckusick 	if ( clp -> size != size )
55352652Smckusick 	    continue;
55452652Smckusick 	stkp = stkloc;
55552652Smckusick 	endlist = &clp -> list[ size ];
55652652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
55752652Smckusick 	    if ( *stkp++ != *arcpp )
55852652Smckusick 		break;
55952652Smckusick 	    if ( stkp > stkend )
56052652Smckusick 		stkp = stkstart;
56152652Smckusick 	}
56252652Smckusick 	if ( arcpp == endlist ) {
56352652Smckusick #	    ifdef DEBUG
56452652Smckusick 		oldcycle++;
56552652Smckusick #	    endif DEBUG
56652652Smckusick 	    return( TRUE );
56752652Smckusick 	}
56852652Smckusick     }
56952652Smckusick     clp = (cltype *)
57052652Smckusick 	calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
57152652Smckusick     if ( clp == 0 ) {
57252652Smckusick 	fprintf( stderr , "%s: No room for %d bytes of subcycle storage\n" ,
57352652Smckusick 	    whoami , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
57452652Smckusick 	return( FALSE );
57552652Smckusick     }
57652652Smckusick     stkp = stkloc;
57752652Smckusick     endlist = &clp -> list[ size ];
57852652Smckusick     for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
57952652Smckusick 	arcp = *arcpp = *stkp++;
58052652Smckusick 	if ( stkp > stkend )
58152652Smckusick 	    stkp = stkstart;
58252652Smckusick 	arcp -> arc_cyclecnt++;
58352652Smckusick 	if ( ( arcp -> arc_flags & ONLIST ) == 0 ) {
58452652Smckusick 	    arcp -> arc_flags |= ONLIST;
58552652Smckusick 	    arcp -> arc_next = archead;
58652652Smckusick 	    archead = arcp;
58752652Smckusick 	}
58852652Smckusick     }
58952652Smckusick     clp -> size = size;
59052652Smckusick     clp -> next = cyclehead;
59152652Smckusick     cyclehead = clp;
59252652Smckusick #   ifdef DEBUG
59352652Smckusick 	newcycle++;
59452652Smckusick 	if ( debug & SUBCYCLELIST ) {
59552652Smckusick 	    printsubcycle( clp );
59652652Smckusick 	}
59752652Smckusick #   endif DEBUG
59852652Smckusick     cyclecnt++;
59952652Smckusick     if ( cyclecnt >= CYCLEMAX )
60052652Smckusick 	return( FALSE );
60152652Smckusick     return( TRUE );
60252652Smckusick }
60352652Smckusick 
compresslist()60452652Smckusick compresslist()
60552652Smckusick {
60652652Smckusick     cltype	*clp;
60752652Smckusick     cltype	**prev;
60852652Smckusick     arctype	**arcpp;
60952652Smckusick     arctype	**endlist;
61052652Smckusick     arctype	*arcp;
61152652Smckusick     arctype	*maxarcp;
61252652Smckusick     arctype	*maxexitarcp;
61352652Smckusick     arctype	*maxwithparentarcp;
61452652Smckusick     arctype	*maxnoparentarcp;
61552652Smckusick     int		maxexitcnt;
61652652Smckusick     int		maxwithparentcnt;
61752652Smckusick     int		maxnoparentcnt;
61852652Smckusick     char	*type;
61952652Smckusick 
62052652Smckusick     maxexitcnt = 0;
62152652Smckusick     maxwithparentcnt = 0;
62252652Smckusick     maxnoparentcnt = 0;
62352652Smckusick     for ( endlist = &archead , arcp = archead ; arcp ; ) {
62452652Smckusick 	if ( arcp -> arc_cyclecnt == 0 ) {
62552652Smckusick 	    arcp -> arc_flags &= ~ONLIST;
62652652Smckusick 	    *endlist = arcp -> arc_next;
62752652Smckusick 	    arcp -> arc_next = 0;
62852652Smckusick 	    arcp = *endlist;
62952652Smckusick 	    continue;
63052652Smckusick 	}
63152652Smckusick 	if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) {
63252652Smckusick 	    if ( arcp -> arc_cyclecnt > maxexitcnt ||
63352652Smckusick 		( arcp -> arc_cyclecnt == maxexitcnt &&
63452652Smckusick 		arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) {
63552652Smckusick 		maxexitcnt = arcp -> arc_cyclecnt;
63652652Smckusick 		maxexitarcp = arcp;
63752652Smckusick 	    }
63852652Smckusick 	} else if ( arcp -> arc_childp -> parentcnt > 1 ) {
63952652Smckusick 	    if ( arcp -> arc_cyclecnt > maxwithparentcnt ||
64052652Smckusick 		( arcp -> arc_cyclecnt == maxwithparentcnt &&
64152652Smckusick 		arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) {
64252652Smckusick 		maxwithparentcnt = arcp -> arc_cyclecnt;
64352652Smckusick 		maxwithparentarcp = arcp;
64452652Smckusick 	    }
64552652Smckusick 	} else {
64652652Smckusick 	    if ( arcp -> arc_cyclecnt > maxnoparentcnt ||
64752652Smckusick 		( arcp -> arc_cyclecnt == maxnoparentcnt &&
64852652Smckusick 		arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) {
64952652Smckusick 		maxnoparentcnt = arcp -> arc_cyclecnt;
65052652Smckusick 		maxnoparentarcp = arcp;
65152652Smckusick 	    }
65252652Smckusick 	}
65352652Smckusick 	endlist = &arcp -> arc_next;
65452652Smckusick 	arcp = arcp -> arc_next;
65552652Smckusick     }
65652652Smckusick     if ( maxexitcnt > 0 ) {
65752652Smckusick 	/*
65852652Smckusick 	 *	first choice is edge leading to node with out-of-cycle parent
65952652Smckusick 	 */
66052652Smckusick 	maxarcp = maxexitarcp;
66152652Smckusick #	ifdef DEBUG
66252652Smckusick 	    type = "exit";
66352652Smckusick #	endif DEBUG
66452652Smckusick     } else if ( maxwithparentcnt > 0 ) {
66552652Smckusick 	/*
66652652Smckusick 	 *	second choice is edge leading to node with at least one
66752652Smckusick 	 *	other in-cycle parent
66852652Smckusick 	 */
66952652Smckusick 	maxarcp = maxwithparentarcp;
67052652Smckusick #	ifdef DEBUG
67152652Smckusick 	    type = "internal";
67252652Smckusick #	endif DEBUG
67352652Smckusick     } else {
67452652Smckusick 	/*
67552652Smckusick 	 *	last choice is edge leading to node with only this arc as
67652652Smckusick 	 *	a parent (as it will now be orphaned)
67752652Smckusick 	 */
67852652Smckusick 	maxarcp = maxnoparentarcp;
67952652Smckusick #	ifdef DEBUG
68052652Smckusick 	    type = "orphan";
68152652Smckusick #	endif DEBUG
68252652Smckusick     }
68352652Smckusick     maxarcp -> arc_flags |= DEADARC;
68452652Smckusick     maxarcp -> arc_childp -> parentcnt -= 1;
68552652Smckusick     maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count;
68652652Smckusick #   ifdef DEBUG
68752652Smckusick 	if ( debug & BREAKCYCLE ) {
68852652Smckusick 	    printf( "%s delete %s arc: %s (%d) -> %s from %d cycle(s)\n" ,
68952652Smckusick 		"[compresslist]" , type , maxarcp -> arc_parentp -> name ,
69052652Smckusick 		maxarcp -> arc_count , maxarcp -> arc_childp -> name ,
69152652Smckusick 		maxarcp -> arc_cyclecnt );
69252652Smckusick 	}
69352652Smckusick #   endif DEBUG
69452652Smckusick     printf( "\t%s to %s with %d calls\n" , maxarcp -> arc_parentp -> name ,
69552652Smckusick 	maxarcp -> arc_childp -> name , maxarcp -> arc_count );
69652652Smckusick     prev = &cyclehead;
69752652Smckusick     for ( clp = cyclehead ; clp ; ) {
69852652Smckusick 	endlist = &clp -> list[ clp -> size ];
69952652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
70052652Smckusick 	    if ( (*arcpp) -> arc_flags & DEADARC )
70152652Smckusick 		break;
70252652Smckusick 	if ( arcpp == endlist ) {
70352652Smckusick 	    prev = &clp -> next;
70452652Smckusick 	    clp = clp -> next;
70552652Smckusick 	    continue;
70652652Smckusick 	}
70752652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
70852652Smckusick 	    (*arcpp) -> arc_cyclecnt--;
70952652Smckusick 	cyclecnt--;
71052652Smckusick 	*prev = clp -> next;
71152652Smckusick 	clp = clp -> next;
71252652Smckusick 	free( clp );
71352652Smckusick     }
71452652Smckusick }
71552652Smckusick 
71652652Smckusick #ifdef DEBUG
printsubcycle(clp)71752652Smckusick printsubcycle( clp )
71852652Smckusick     cltype	*clp;
71952652Smckusick {
72052652Smckusick     arctype	**arcpp;
72152652Smckusick     arctype	**endlist;
72252652Smckusick 
72352652Smckusick     arcpp = clp -> list;
72452652Smckusick     printf( "%s <cycle %d>\n" , (*arcpp) -> arc_parentp -> name ,
72552652Smckusick 	(*arcpp) -> arc_parentp -> cycleno ) ;
72652652Smckusick     for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ )
72752652Smckusick 	printf( "\t(%d) -> %s\n" , (*arcpp) -> arc_count ,
72852652Smckusick 	    (*arcpp) -> arc_childp -> name ) ;
72952652Smckusick }
73052652Smckusick #endif DEBUG
73152652Smckusick 
cycletime()7327172Speter cycletime()
7337172Speter {
7347172Speter     int			cycle;
7357172Speter     nltype		*cyclenlp;
7367172Speter     nltype		*childp;
7377172Speter 
7387172Speter     for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
7397172Speter 	cyclenlp = &cyclenl[ cycle ];
7407221Speter 	for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
7417221Speter 	    if ( childp -> propfraction == 0.0 ) {
7427221Speter 		    /*
7437221Speter 		     * all members have the same propfraction except those
7447221Speter 		     *	that were excluded with -E
7457221Speter 		     */
7467221Speter 		continue;
7477221Speter 	    }
7487221Speter 	    cyclenlp -> time += childp -> time;
7494508Speter 	}
7507221Speter 	cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
7514508Speter     }
7524508Speter }
7537172Speter 
7547172Speter     /*
7557172Speter      *	in one top to bottom pass over the topologically sorted namelist
7567221Speter      *	propagate:
7577221Speter      *		printflag as the union of parents' printflags
7587221Speter      *		propfraction as the sum of fractional parents' propfractions
7597221Speter      *	and while we're here, sum time for functions.
7607172Speter      */
doflags()7617172Speter doflags()
7627172Speter {
7637172Speter     int		index;
7647172Speter     nltype	*childp;
7657172Speter     nltype	*oldhead;
7667172Speter 
7677172Speter     oldhead = 0;
7687172Speter     for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
7697172Speter 	childp = topsortnlp[ index ];
7707172Speter 	    /*
7717172Speter 	     *	if we haven't done this function or cycle,
7727221Speter 	     *	inherit things from parent.
7737172Speter 	     *	this way, we are linear in the number of arcs
7747172Speter 	     *	since we do all members of a cycle (and the cycle itself)
7757172Speter 	     *	as we hit the first member of the cycle.
7767172Speter 	     */
7777172Speter 	if ( childp -> cyclehead != oldhead ) {
7787172Speter 	    oldhead = childp -> cyclehead;
7797221Speter 	    inheritflags( childp );
7807172Speter 	}
7817221Speter #	ifdef DEBUG
7827221Speter 	    if ( debug & PROPDEBUG ) {
7837221Speter 		printf( "[doflags] " );
7847221Speter 		printname( childp );
7857221Speter 		printf( " inherits printflag %d and propfraction %f\n" ,
7867221Speter 			childp -> printflag , childp -> propfraction );
7877221Speter 	    }
7887221Speter #	endif DEBUG
7897172Speter 	if ( ! childp -> printflag ) {
7907172Speter 		/*
7917221Speter 		 *	printflag is off
7927221Speter 		 *	it gets turned on by
7937221Speter 		 *	being on -f list,
7947221Speter 		 *	or there not being any -f list and not being on -e list.
7957172Speter 		 */
7967221Speter 	    if (   onlist( flist , childp -> name )
7977221Speter 		|| ( !fflag && !onlist( elist , childp -> name ) ) ) {
7987172Speter 		childp -> printflag = TRUE;
7997172Speter 	    }
8007221Speter 	} else {
8017221Speter 		/*
8027221Speter 		 *	this function has printing parents:
8037221Speter 		 *	maybe someone wants to shut it up
8047221Speter 		 *	by putting it on -e list.  (but favor -f over -e)
8057221Speter 		 */
8067221Speter 	    if (  ( !onlist( flist , childp -> name ) )
8077221Speter 		&& onlist( elist , childp -> name ) ) {
8087221Speter 		childp -> printflag = FALSE;
8097172Speter 	    }
8107221Speter 	}
8117221Speter 	if ( childp -> propfraction == 0.0 ) {
8127221Speter 		/*
8137221Speter 		 *	no parents to pass time to.
8147221Speter 		 *	collect time from children if
8157221Speter 		 *	its on -F list,
8167221Speter 		 *	or there isn't any -F list and its not on -E list.
8177221Speter 		 */
8187221Speter 	    if ( onlist( Flist , childp -> name )
8197221Speter 		|| ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
8207221Speter 		    childp -> propfraction = 1.0;
8217172Speter 	    }
8227221Speter 	} else {
8237221Speter 		/*
8247221Speter 		 *	it has parents to pass time to,
8257221Speter 		 *	but maybe someone wants to shut it up
8267221Speter 		 *	by puttting it on -E list.  (but favor -F over -E)
8277221Speter 		 */
8287221Speter 	    if (  !onlist( Flist , childp -> name )
8297221Speter 		&& onlist( Elist , childp -> name ) ) {
8307221Speter 		childp -> propfraction = 0.0;
8317221Speter 	    }
8327172Speter 	}
8337221Speter 	childp -> propself = childp -> time * childp -> propfraction;
8347221Speter 	printtime += childp -> propself;
8357221Speter #	ifdef DEBUG
8367221Speter 	    if ( debug & PROPDEBUG ) {
8377221Speter 		printf( "[doflags] " );
8387221Speter 		printname( childp );
8397221Speter 		printf( " ends up with printflag %d and propfraction %f\n" ,
8407221Speter 			childp -> printflag , childp -> propfraction );
8418908Speter 		printf( "time %f propself %f printtime %f\n" ,
8428908Speter 			childp -> time , childp -> propself , printtime );
8437221Speter 	    }
8447221Speter #	endif DEBUG
8457172Speter     }
8467172Speter }
8477172Speter 
8487172Speter     /*
8497172Speter      *	check if any parent of this child
8507172Speter      *	(or outside parents of this cycle)
8517172Speter      *	have their print flags on and set the
8527172Speter      *	print flag of the child (cycle) appropriately.
8537221Speter      *	similarly, deal with propagation fractions from parents.
8547172Speter      */
inheritflags(childp)8557221Speter inheritflags( childp )
8567172Speter     nltype	*childp;
8577172Speter {
8587172Speter     nltype	*headp;
8597221Speter     arctype	*arcp;
8607221Speter     nltype	*parentp;
8617172Speter     nltype	*memp;
8627172Speter 
8637172Speter     headp = childp -> cyclehead;
8647172Speter     if ( childp == headp ) {
8657172Speter 	    /*
8667172Speter 	     *	just a regular child, check its parents
8677172Speter 	     */
8687221Speter 	childp -> printflag = FALSE;
8697221Speter 	childp -> propfraction = 0.0;
8707221Speter 	for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
8717221Speter 	    parentp = arcp -> arc_parentp;
8728908Speter 	    if ( childp == parentp ) {
8738908Speter 		continue;
8748908Speter 	    }
8757221Speter 	    childp -> printflag |= parentp -> printflag;
87614140Speter 		/*
87714140Speter 		 *	if the child was never actually called
87814140Speter 		 *	(e.g. this arc is static (and all others are, too))
87914140Speter 		 *	no time propagates along this arc.
88014140Speter 		 */
88152652Smckusick 	    if ( arcp -> arc_flags & DEADARC ) {
88252652Smckusick 		continue;
88352652Smckusick 	    }
88452652Smckusick 	    if ( childp -> npropcall ) {
88514140Speter 		childp -> propfraction += parentp -> propfraction
88652652Smckusick 					* ( ( (double) arcp -> arc_count )
88752652Smckusick 					  / ( (double) childp -> npropcall ) );
88814140Speter 	    }
8897172Speter 	}
8907221Speter     } else {
8917221Speter 	    /*
8927221Speter 	     *	its a member of a cycle, look at all parents from
8937221Speter 	     *	outside the cycle
8947221Speter 	     */
8957221Speter 	headp -> printflag = FALSE;
8967221Speter 	headp -> propfraction = 0.0;
8977221Speter 	for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
8987221Speter 	    for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
8997221Speter 		if ( arcp -> arc_parentp -> cyclehead == headp ) {
9007221Speter 		    continue;
9017221Speter 		}
9027221Speter 		parentp = arcp -> arc_parentp;
9037221Speter 		headp -> printflag |= parentp -> printflag;
90414140Speter 		    /*
90514140Speter 		     *	if the cycle was never actually called
90614140Speter 		     *	(e.g. this arc is static (and all others are, too))
90714140Speter 		     *	no time propagates along this arc.
90814140Speter 		     */
90952652Smckusick 		if ( arcp -> arc_flags & DEADARC ) {
91052652Smckusick 		    continue;
91152652Smckusick 		}
91252652Smckusick 		if ( headp -> npropcall ) {
91314140Speter 		    headp -> propfraction += parentp -> propfraction
91452652Smckusick 					* ( ( (double) arcp -> arc_count )
91552652Smckusick 					  / ( (double) headp -> npropcall ) );
91614140Speter 		}
9177172Speter 	    }
9187172Speter 	}
9197221Speter 	for ( memp = headp ; memp ; memp = memp -> cnext ) {
9207221Speter 	    memp -> printflag = headp -> printflag;
9217221Speter 	    memp -> propfraction = headp -> propfraction;
9227221Speter 	}
9237172Speter     }
9247172Speter }
925