xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 52652)
121957Sdist /*
221957Sdist  * Copyright (c) 1983 Regents of the University of California.
334199Sbostic  * All rights reserved.
434199Sbostic  *
542683Sbostic  * %sccs.include.redist.c%
621957Sdist  */
721957Sdist 
84508Speter #ifndef lint
9*52652Smckusick static char sccsid[] = "@(#)arcs.c	5.7 (Berkeley) 02/24/92";
1034199Sbostic #endif /* not lint */
114508Speter 
124561Speter #include "gprof.h"
134508Speter 
14*52652Smckusick #ifdef DEBUG
15*52652Smckusick int visited;
16*52652Smckusick int viable;
17*52652Smckusick int newcycle;
18*52652Smckusick int oldcycle;
19*52652Smckusick #endif DEBUG
20*52652Smckusick 
214721Speter     /*
224721Speter      *	add (or just increment) an arc
234721Speter      */
244721Speter addarc( parentp , childp , count )
254721Speter     nltype	*parentp;
264721Speter     nltype	*childp;
274721Speter     long	count;
284721Speter {
294750Speter     arctype		*calloc();
304721Speter     arctype		*arcp;
314721Speter 
324721Speter #   ifdef DEBUG
334721Speter 	if ( debug & TALLYDEBUG ) {
344721Speter 	    printf( "[addarc] %d arcs from %s to %s\n" ,
354721Speter 		    count , parentp -> name , childp -> name );
364721Speter 	}
374721Speter #   endif DEBUG
384721Speter     arcp = arclookup( parentp , childp );
394721Speter     if ( arcp != 0 ) {
404721Speter 	    /*
414721Speter 	     *	a hit:  just increment the count.
424721Speter 	     */
434721Speter #	ifdef DEBUG
444721Speter 	    if ( debug & TALLYDEBUG ) {
454721Speter 		printf( "[tally] hit %d += %d\n" ,
464721Speter 			arcp -> arc_count , count );
474721Speter 	    }
484721Speter #	endif DEBUG
494721Speter 	arcp -> arc_count += count;
504721Speter 	return;
514721Speter     }
524750Speter     arcp = calloc( 1 , sizeof *arcp );
534721Speter     arcp -> arc_parentp = parentp;
544721Speter     arcp -> arc_childp = childp;
554721Speter     arcp -> arc_count = count;
564721Speter 	/*
574721Speter 	 *	prepend this child to the children of this parent
584721Speter 	 */
594721Speter     arcp -> arc_childlist = parentp -> children;
604721Speter     parentp -> children = arcp;
614721Speter 	/*
624721Speter 	 *	prepend this parent to the parents of this child
634721Speter 	 */
644721Speter     arcp -> arc_parentlist = childp -> parents;
654721Speter     childp -> parents = arcp;
664721Speter }
674721Speter 
687172Speter     /*
697172Speter      *	the code below topologically sorts the graph (collapsing cycles),
707172Speter      *	and propagates time bottom up and flags top down.
717172Speter      */
727172Speter 
737172Speter     /*
747172Speter      *	the topologically sorted name list pointers
757172Speter      */
767172Speter nltype	**topsortnlp;
777172Speter 
784508Speter topcmp( npp1 , npp2 )
794508Speter     nltype	**npp1;
804508Speter     nltype	**npp2;
814508Speter {
824508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
834508Speter }
844508Speter 
8516850Smckusick nltype **
864508Speter doarcs()
874508Speter {
8816850Smckusick     nltype	*parentp, **timesortnlp;
894508Speter     arctype	*arcp;
904508Speter     long	index;
91*52652Smckusick     long	pass;
924508Speter 
934508Speter 	/*
944508Speter 	 *	initialize various things:
954508Speter 	 *	    zero out child times.
964508Speter 	 *	    count self-recursive calls.
974508Speter 	 *	    indicate that nothing is on cycles.
984508Speter 	 */
994508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
1004508Speter 	parentp -> childtime = 0.0;
1014508Speter 	arcp = arclookup( parentp , parentp );
1024508Speter 	if ( arcp != 0 ) {
1034508Speter 	    parentp -> ncall -= arcp -> arc_count;
1044508Speter 	    parentp -> selfcalls = arcp -> arc_count;
1054508Speter 	} else {
1064508Speter 	    parentp -> selfcalls = 0;
1074508Speter 	}
108*52652Smckusick 	parentp -> npropcall = parentp -> ncall;
1097221Speter 	parentp -> propfraction = 0.0;
1107221Speter 	parentp -> propself = 0.0;
1117221Speter 	parentp -> propchild = 0.0;
1127172Speter 	parentp -> printflag = FALSE;
11310284Speter 	parentp -> toporder = DFN_NAN;
1144508Speter 	parentp -> cycleno = 0;
1154508Speter 	parentp -> cyclehead = parentp;
1164508Speter 	parentp -> cnext = 0;
1177172Speter 	if ( cflag ) {
11825713Ssam 	    findcall( parentp , parentp -> value , (parentp+1) -> value );
1197172Speter 	}
1204508Speter     }
121*52652Smckusick     for ( pass = 1 ; ; pass++ ) {
122*52652Smckusick 	    /*
123*52652Smckusick 	     *	topologically order things
124*52652Smckusick 	     *	if any node is unnumbered,
125*52652Smckusick 	     *	    number it and any of its descendents.
126*52652Smckusick 	     */
127*52652Smckusick 	for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) {
128*52652Smckusick 	    if ( parentp -> toporder == DFN_NAN ) {
129*52652Smckusick 		dfn( parentp );
130*52652Smckusick 	    }
1314508Speter 	}
132*52652Smckusick 	    /*
133*52652Smckusick 	     *	link together nodes on the same cycle
134*52652Smckusick 	     */
135*52652Smckusick 	cyclelink();
136*52652Smckusick 	    /*
137*52652Smckusick 	     *	if no cycles to break up, proceed
138*52652Smckusick 	     */
139*52652Smckusick 	if ( ! Cflag )
140*52652Smckusick 	    break;
141*52652Smckusick 	    /*
142*52652Smckusick 	     *	analyze cycles to determine breakup
143*52652Smckusick 	     */
144*52652Smckusick #	ifdef DEBUG
145*52652Smckusick 	    if ( debug & BREAKCYCLE ) {
146*52652Smckusick 		printf("[doarcs] pass %d, cycle(s) %d\n" , pass , ncycle );
147*52652Smckusick 	    }
148*52652Smckusick #	endif DEBUG
149*52652Smckusick 	if ( pass == 1 ) {
150*52652Smckusick 	    printf( "\n\n%s %s\n%s %d:\n" ,
151*52652Smckusick 		"The following arcs were deleted" ,
152*52652Smckusick 		"from the propagation calculation" ,
153*52652Smckusick 		"to reduce the maximum cycle size to", cyclethreshold );
154*52652Smckusick 	}
155*52652Smckusick 	if ( cycleanalyze() )
156*52652Smckusick 	    break;
157*52652Smckusick 	free ( cyclenl );
158*52652Smckusick 	ncycle = 0;
159*52652Smckusick 	for ( parentp = nl ; parentp < npe ; parentp++ ) {
160*52652Smckusick 	    parentp -> toporder = DFN_NAN;
161*52652Smckusick 	    parentp -> cycleno = 0;
162*52652Smckusick 	    parentp -> cyclehead = parentp;
163*52652Smckusick 	    parentp -> cnext = 0;
164*52652Smckusick 	}
1654508Speter     }
166*52652Smckusick     if ( pass > 1 ) {
167*52652Smckusick 	printf( "\f\n" );
168*52652Smckusick     } else {
169*52652Smckusick 	printf( "\tNone\n\n" );
170*52652Smckusick     }
1714508Speter 	/*
1724508Speter 	 *	Sort the symbol table in reverse topological order
1734508Speter 	 */
1744508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1754508Speter     if ( topsortnlp == (nltype **) 0 ) {
1764508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1774508Speter     }
1784508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1794508Speter 	topsortnlp[ index ] = &nl[ index ];
1804508Speter     }
1814508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1824508Speter #   ifdef DEBUG
1834508Speter 	if ( debug & DFNDEBUG ) {
1844508Speter 	    printf( "[doarcs] topological sort listing\n" );
1854508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1864508Speter 		printf( "[doarcs] " );
1874508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1884508Speter 		printname( topsortnlp[ index ] );
1894508Speter 		printf( "\n" );
1904508Speter 	    }
1914508Speter 	}
1924508Speter #   endif DEBUG
1934508Speter 	/*
1947221Speter 	 *	starting from the topological top,
1957221Speter 	 *	propagate print flags to children.
1967221Speter 	 *	also, calculate propagation fractions.
1977221Speter 	 *	this happens before time propagation
1987221Speter 	 *	since time propagation uses the fractions.
1997221Speter 	 */
2007221Speter     doflags();
2017221Speter 	/*
2024508Speter 	 *	starting from the topological bottom,
2037172Speter 	 *	propogate children times up to parents.
2044508Speter 	 */
2057172Speter     dotime();
20616850Smckusick 	/*
20716850Smckusick 	 *	Now, sort by propself + propchild.
20816850Smckusick 	 *	sorting both the regular function names
20916850Smckusick 	 *	and cycle headers.
21016850Smckusick 	 */
21116850Smckusick     timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
21216850Smckusick     if ( timesortnlp == (nltype **) 0 ) {
21316850Smckusick 	fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
21416850Smckusick     }
21516850Smckusick     for ( index = 0 ; index < nname ; index++ ) {
21616850Smckusick 	timesortnlp[index] = &nl[index];
21716850Smckusick     }
21816850Smckusick     for ( index = 1 ; index <= ncycle ; index++ ) {
21916850Smckusick 	timesortnlp[nname+index-1] = &cyclenl[index];
22016850Smckusick     }
22116850Smckusick     qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
22216850Smckusick     for ( index = 0 ; index < nname + ncycle ; index++ ) {
22316850Smckusick 	timesortnlp[ index ] -> index = index + 1;
22416850Smckusick     }
22516850Smckusick     return( timesortnlp );
2267172Speter }
2277172Speter 
2287172Speter dotime()
2297172Speter {
2307172Speter     int	index;
2317172Speter 
2327172Speter     cycletime();
2334508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
2347172Speter 	timepropagate( topsortnlp[ index ] );
2357127Speter     }
2367127Speter }
2377127Speter 
2387172Speter timepropagate( parentp )
2397127Speter     nltype	*parentp;
2407127Speter {
2417127Speter     arctype	*arcp;
2427127Speter     nltype	*childp;
2437127Speter     double	share;
2447221Speter     double	propshare;
2457127Speter 
2467221Speter     if ( parentp -> propfraction == 0.0 ) {
2477221Speter 	return;
2487221Speter     }
2497127Speter 	/*
2507127Speter 	 *	gather time from children of this parent.
2517127Speter 	 */
2527172Speter     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
2537127Speter 	childp = arcp -> arc_childp;
254*52652Smckusick 	if ( arcp -> arc_flags & DEADARC ) {
255*52652Smckusick 	    continue;
256*52652Smckusick 	}
2577127Speter 	if ( arcp -> arc_count == 0 ) {
2587127Speter 	    continue;
2597127Speter 	}
2607221Speter 	if ( childp == parentp ) {
2617127Speter 	    continue;
2627127Speter 	}
2637221Speter 	if ( childp -> propfraction == 0.0 ) {
2647127Speter 	    continue;
2657127Speter 	}
2667127Speter 	if ( childp -> cyclehead != childp ) {
2677127Speter 	    if ( parentp -> cycleno == childp -> cycleno ) {
2687127Speter 		continue;
2697127Speter 	    }
2707127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2717127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2724508Speter 	    }
2737127Speter 	    childp = childp -> cyclehead;
2747127Speter 	} else {
2757127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2767127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2774508Speter 		continue;
2784508Speter 	    }
2797127Speter 	}
280*52652Smckusick 	if ( childp -> npropcall == 0 ) {
2817221Speter 	    continue;
2827221Speter 	}
2837127Speter 	    /*
2847127Speter 	     *	distribute time for this arc
2857127Speter 	     */
2867221Speter 	arcp -> arc_time = childp -> time
2877221Speter 			        * ( ( (double) arcp -> arc_count ) /
288*52652Smckusick 				    ( (double) childp -> npropcall ) );
2897221Speter 	arcp -> arc_childtime = childp -> childtime
2907221Speter 			        * ( ( (double) arcp -> arc_count ) /
291*52652Smckusick 				    ( (double) childp -> npropcall ) );
2927127Speter 	share = arcp -> arc_time + arcp -> arc_childtime;
2937127Speter 	parentp -> childtime += share;
2947127Speter 	    /*
2957221Speter 	     *	( 1 - propfraction ) gets lost along the way
2967127Speter 	     */
2977221Speter 	propshare = parentp -> propfraction * share;
2987221Speter 	    /*
2997221Speter 	     *	fix things for printing
3007221Speter 	     */
3017221Speter 	parentp -> propchild += propshare;
3027221Speter 	arcp -> arc_time *= parentp -> propfraction;
3037221Speter 	arcp -> arc_childtime *= parentp -> propfraction;
3047221Speter 	    /*
3057221Speter 	     *	add this share to the parent's cycle header, if any.
3067221Speter 	     */
3077127Speter 	if ( parentp -> cyclehead != parentp ) {
3087127Speter 	    parentp -> cyclehead -> childtime += share;
3097221Speter 	    parentp -> cyclehead -> propchild += propshare;
3104508Speter 	}
3117221Speter #	ifdef DEBUG
3127221Speter 	    if ( debug & PROPDEBUG ) {
3137221Speter 		printf( "[dotime] child \t" );
3147221Speter 		printname( childp );
3157221Speter 		printf( " with %f %f %d/%d\n" ,
3167221Speter 			childp -> time , childp -> childtime ,
317*52652Smckusick 			arcp -> arc_count , childp -> npropcall );
3187221Speter 		printf( "[dotime] parent\t" );
3197221Speter 		printname( parentp );
3207221Speter 		printf( "\n[dotime] share %f\n" , share );
3217221Speter 	    }
3227221Speter #	endif DEBUG
3234508Speter     }
3244508Speter }
3254508Speter 
3264508Speter cyclelink()
3274508Speter {
3284508Speter     register nltype	*nlp;
3294508Speter     register nltype	*cyclenlp;
3304508Speter     int			cycle;
3317172Speter     nltype		*memberp;
3327248Speter     arctype		*arcp;
3334508Speter 
3344508Speter 	/*
3354508Speter 	 *	Count the number of cycles, and initialze the cycle lists
3364508Speter 	 */
3377127Speter     ncycle = 0;
3384508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
3394508Speter 	    /*
3404508Speter 	     *	this is how you find unattached cycles
3414508Speter 	     */
3424508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
3437127Speter 	    ncycle += 1;
3444508Speter 	}
3454508Speter     }
3467127Speter 	/*
3477127Speter 	 *	cyclenl is indexed by cycle number:
3487127Speter 	 *	i.e. it is origin 1, not origin 0.
3497127Speter 	 */
3507127Speter     cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
3517127Speter     if ( cyclenl == 0 ) {
3527127Speter 	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
3537127Speter 		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
3547127Speter 	done();
3554508Speter     }
3564508Speter 	/*
3574508Speter 	 *	now link cycles to true cycleheads,
3584508Speter 	 *	number them, accumulate the data for the cycle
3594508Speter 	 */
3604508Speter     cycle = 0;
3614508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
36210284Speter 	if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) {
3634508Speter 	    continue;
3644508Speter 	}
3654508Speter 	cycle += 1;
3667127Speter 	cyclenlp = &cyclenl[cycle];
3677249Speter         cyclenlp -> name = 0;		/* the name */
3687221Speter         cyclenlp -> value = 0;		/* the pc entry point */
3697221Speter         cyclenlp -> time = 0.0;		/* ticks in this routine */
3707221Speter         cyclenlp -> childtime = 0.0;	/* cumulative ticks in children */
3717221Speter 	cyclenlp -> ncall = 0;		/* how many times called */
3727221Speter 	cyclenlp -> selfcalls = 0;	/* how many calls to self */
3737221Speter 	cyclenlp -> propfraction = 0.0;	/* what % of time propagates */
3747221Speter 	cyclenlp -> propself = 0.0;	/* how much self time propagates */
3757221Speter 	cyclenlp -> propchild = 0.0;	/* how much child time propagates */
3767221Speter 	cyclenlp -> printflag = TRUE;	/* should this be printed? */
3777221Speter 	cyclenlp -> index = 0;		/* index in the graph list */
37810284Speter 	cyclenlp -> toporder = DFN_NAN;	/* graph call chain top-sort order */
3797221Speter 	cyclenlp -> cycleno = cycle;	/* internal number of cycle on */
3807221Speter 	cyclenlp -> cyclehead = cyclenlp;	/* pointer to head of cycle */
3817221Speter 	cyclenlp -> cnext = nlp;	/* pointer to next member of cycle */
3827221Speter 	cyclenlp -> parents = 0;	/* list of caller arcs */
3837221Speter 	cyclenlp -> children = 0;	/* list of callee arcs */
3844508Speter #	ifdef DEBUG
3854508Speter 	    if ( debug & CYCLEDEBUG ) {
3864508Speter 		printf( "[cyclelink] " );
3874508Speter 		printname( nlp );
3884508Speter 		printf( " is the head of cycle %d\n" , cycle );
3894508Speter 	    }
3904508Speter #	endif DEBUG
3917248Speter 	    /*
3927248Speter 	     *	link members to cycle header
3937248Speter 	     */
3947172Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
3957172Speter 	    memberp -> cycleno = cycle;
3967172Speter 	    memberp -> cyclehead = cyclenlp;
3977172Speter 	}
3987248Speter 	    /*
3997248Speter 	     *	count calls from outside the cycle
4007248Speter 	     *	and those among cycle members
4017248Speter 	     */
4027248Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
4037248Speter 	    for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
4047248Speter 		if ( arcp -> arc_parentp == memberp ) {
4057248Speter 		    continue;
4067248Speter 		}
4077248Speter 		if ( arcp -> arc_parentp -> cycleno == cycle ) {
4087248Speter 		    cyclenlp -> selfcalls += arcp -> arc_count;
4097248Speter 		} else {
410*52652Smckusick 		    cyclenlp -> npropcall += arcp -> arc_count;
4117248Speter 		}
4127248Speter 	    }
4137248Speter 	}
4147172Speter     }
4157172Speter }
4167172Speter 
417*52652Smckusick     /*
418*52652Smckusick      *	analyze cycles to determine breakup
419*52652Smckusick      */
420*52652Smckusick cycleanalyze()
421*52652Smckusick {
422*52652Smckusick     arctype	**cyclestack;
423*52652Smckusick     arctype	**stkp;
424*52652Smckusick     arctype	**arcpp;
425*52652Smckusick     arctype	**endlist;
426*52652Smckusick     arctype	*arcp;
427*52652Smckusick     nltype	*nlp;
428*52652Smckusick     cltype	*clp;
429*52652Smckusick     bool	ret;
430*52652Smckusick     bool	done;
431*52652Smckusick     int		size;
432*52652Smckusick     int		cycleno;
433*52652Smckusick 
434*52652Smckusick 	/*
435*52652Smckusick 	 *	calculate the size of the cycle, and find nodes that
436*52652Smckusick 	 *	exit the cycle as they are desirable targets to cut
437*52652Smckusick 	 *	some of their parents
438*52652Smckusick 	 */
439*52652Smckusick     for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) {
440*52652Smckusick 	size = 0;
441*52652Smckusick 	for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) {
442*52652Smckusick 	    size += 1;
443*52652Smckusick 	    nlp -> parentcnt = 0;
444*52652Smckusick 	    nlp -> flags &= ~HASCYCLEXIT;
445*52652Smckusick 	    for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) {
446*52652Smckusick 		nlp -> parentcnt += 1;
447*52652Smckusick 		if ( arcp -> arc_parentp -> cycleno != cycleno )
448*52652Smckusick 		    nlp -> flags |= HASCYCLEXIT;
449*52652Smckusick 	    }
450*52652Smckusick 	}
451*52652Smckusick 	if ( size <= cyclethreshold )
452*52652Smckusick 	    continue;
453*52652Smckusick 	done = FALSE;
454*52652Smckusick         cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) );
455*52652Smckusick 	if ( cyclestack == 0 ) {
456*52652Smckusick 	    fprintf( stderr , "%s: No room for %d bytes of cycle stack\n" ,
457*52652Smckusick 		whoami , ( size + 1 ) * sizeof( arctype * ) );
458*52652Smckusick 	    return;
459*52652Smckusick 	}
460*52652Smckusick #	ifdef DEBUG
461*52652Smckusick 	    if ( debug & BREAKCYCLE ) {
462*52652Smckusick 		printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" ,
463*52652Smckusick 		    cycleno , ncycle , size );
464*52652Smckusick 	    }
465*52652Smckusick #	endif DEBUG
466*52652Smckusick 	for ( nlp = cyclenl[ cycleno ] . cnext ; nlp ; nlp = nlp -> cnext ) {
467*52652Smckusick 	    stkp = &cyclestack[0];
468*52652Smckusick 	    nlp -> flags |= CYCLEHEAD;
469*52652Smckusick 	    ret = descend ( nlp , cyclestack , stkp );
470*52652Smckusick 	    nlp -> flags &= ~CYCLEHEAD;
471*52652Smckusick 	    if ( ret == FALSE )
472*52652Smckusick 		break;
473*52652Smckusick 	}
474*52652Smckusick 	free( cyclestack );
475*52652Smckusick 	if ( cyclecnt > 0 ) {
476*52652Smckusick 	    compresslist();
477*52652Smckusick 	    for ( clp = cyclehead ; clp ; ) {
478*52652Smckusick 		endlist = &clp -> list[ clp -> size ];
479*52652Smckusick 		for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
480*52652Smckusick 		    (*arcpp) -> arc_cyclecnt--;
481*52652Smckusick 		cyclecnt--;
482*52652Smckusick 		clp = clp -> next;
483*52652Smckusick 		free( clp );
484*52652Smckusick 	    }
485*52652Smckusick 	    cyclehead = 0;
486*52652Smckusick 	}
487*52652Smckusick     }
488*52652Smckusick #   ifdef DEBUG
489*52652Smckusick 	if ( debug & BREAKCYCLE ) {
490*52652Smckusick 	    printf("%s visited %d, viable %d, newcycle %d, oldcycle %d\n",
491*52652Smckusick 		"[doarcs]" , visited , viable , newcycle , oldcycle);
492*52652Smckusick 	}
493*52652Smckusick #   endif DEBUG
494*52652Smckusick     return( done );
495*52652Smckusick }
496*52652Smckusick 
497*52652Smckusick descend( node , stkstart , stkp )
498*52652Smckusick     nltype	*node;
499*52652Smckusick     arctype	**stkstart;
500*52652Smckusick     arctype	**stkp;
501*52652Smckusick {
502*52652Smckusick     arctype	*arcp;
503*52652Smckusick     bool	ret;
504*52652Smckusick 
505*52652Smckusick     for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) {
506*52652Smckusick #	ifdef DEBUG
507*52652Smckusick 	    visited++;
508*52652Smckusick #	endif DEBUG
509*52652Smckusick 	if ( arcp -> arc_childp -> cycleno != node -> cycleno
510*52652Smckusick 	    || ( arcp -> arc_childp -> flags & VISITED )
511*52652Smckusick 	    || ( arcp -> arc_flags & DEADARC ) )
512*52652Smckusick 	    continue;
513*52652Smckusick #	ifdef DEBUG
514*52652Smckusick 	    viable++;
515*52652Smckusick #	endif DEBUG
516*52652Smckusick 	*stkp = arcp;
517*52652Smckusick 	if ( arcp -> arc_childp -> flags & CYCLEHEAD ) {
518*52652Smckusick 	    if ( addcycle( stkstart , stkp ) == FALSE )
519*52652Smckusick 		return( FALSE );
520*52652Smckusick 	    continue;
521*52652Smckusick 	}
522*52652Smckusick 	arcp -> arc_childp -> flags |= VISITED;
523*52652Smckusick 	ret = descend( arcp -> arc_childp , stkstart , stkp + 1 );
524*52652Smckusick 	arcp -> arc_childp -> flags &= ~VISITED;
525*52652Smckusick 	if ( ret == FALSE )
526*52652Smckusick 	    return( FALSE );
527*52652Smckusick     }
528*52652Smckusick }
529*52652Smckusick 
530*52652Smckusick addcycle( stkstart , stkend )
531*52652Smckusick     arctype	**stkstart;
532*52652Smckusick     arctype	**stkend;
533*52652Smckusick {
534*52652Smckusick     arctype	**arcpp;
535*52652Smckusick     arctype	**stkloc;
536*52652Smckusick     arctype	**stkp;
537*52652Smckusick     arctype	**endlist;
538*52652Smckusick     arctype	*minarc;
539*52652Smckusick     arctype	*arcp;
540*52652Smckusick     cltype	*clp;
541*52652Smckusick     int		size;
542*52652Smckusick 
543*52652Smckusick     size = stkend - stkstart + 1;
544*52652Smckusick     if ( size <= 1 )
545*52652Smckusick 	return( TRUE );
546*52652Smckusick     for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) {
547*52652Smckusick 	if ( *arcpp > minarc )
548*52652Smckusick 	    continue;
549*52652Smckusick 	minarc = *arcpp;
550*52652Smckusick 	stkloc = arcpp;
551*52652Smckusick     }
552*52652Smckusick     for ( clp = cyclehead ; clp ; clp = clp -> next ) {
553*52652Smckusick 	if ( clp -> size != size )
554*52652Smckusick 	    continue;
555*52652Smckusick 	stkp = stkloc;
556*52652Smckusick 	endlist = &clp -> list[ size ];
557*52652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
558*52652Smckusick 	    if ( *stkp++ != *arcpp )
559*52652Smckusick 		break;
560*52652Smckusick 	    if ( stkp > stkend )
561*52652Smckusick 		stkp = stkstart;
562*52652Smckusick 	}
563*52652Smckusick 	if ( arcpp == endlist ) {
564*52652Smckusick #	    ifdef DEBUG
565*52652Smckusick 		oldcycle++;
566*52652Smckusick #	    endif DEBUG
567*52652Smckusick 	    return( TRUE );
568*52652Smckusick 	}
569*52652Smckusick     }
570*52652Smckusick     clp = (cltype *)
571*52652Smckusick 	calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
572*52652Smckusick     if ( clp == 0 ) {
573*52652Smckusick 	fprintf( stderr , "%s: No room for %d bytes of subcycle storage\n" ,
574*52652Smckusick 	    whoami , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
575*52652Smckusick 	return( FALSE );
576*52652Smckusick     }
577*52652Smckusick     stkp = stkloc;
578*52652Smckusick     endlist = &clp -> list[ size ];
579*52652Smckusick     for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
580*52652Smckusick 	arcp = *arcpp = *stkp++;
581*52652Smckusick 	if ( stkp > stkend )
582*52652Smckusick 	    stkp = stkstart;
583*52652Smckusick 	arcp -> arc_cyclecnt++;
584*52652Smckusick 	if ( ( arcp -> arc_flags & ONLIST ) == 0 ) {
585*52652Smckusick 	    arcp -> arc_flags |= ONLIST;
586*52652Smckusick 	    arcp -> arc_next = archead;
587*52652Smckusick 	    archead = arcp;
588*52652Smckusick 	}
589*52652Smckusick     }
590*52652Smckusick     clp -> size = size;
591*52652Smckusick     clp -> next = cyclehead;
592*52652Smckusick     cyclehead = clp;
593*52652Smckusick #   ifdef DEBUG
594*52652Smckusick 	newcycle++;
595*52652Smckusick 	if ( debug & SUBCYCLELIST ) {
596*52652Smckusick 	    printsubcycle( clp );
597*52652Smckusick 	}
598*52652Smckusick #   endif DEBUG
599*52652Smckusick     cyclecnt++;
600*52652Smckusick     if ( cyclecnt >= CYCLEMAX )
601*52652Smckusick 	return( FALSE );
602*52652Smckusick     return( TRUE );
603*52652Smckusick }
604*52652Smckusick 
605*52652Smckusick compresslist()
606*52652Smckusick {
607*52652Smckusick     cltype	*clp;
608*52652Smckusick     cltype	**prev;
609*52652Smckusick     arctype	**arcpp;
610*52652Smckusick     arctype	**endlist;
611*52652Smckusick     arctype	*arcp;
612*52652Smckusick     arctype	*maxarcp;
613*52652Smckusick     arctype	*maxexitarcp;
614*52652Smckusick     arctype	*maxwithparentarcp;
615*52652Smckusick     arctype	*maxnoparentarcp;
616*52652Smckusick     int		maxexitcnt;
617*52652Smckusick     int		maxwithparentcnt;
618*52652Smckusick     int		maxnoparentcnt;
619*52652Smckusick     char	*type;
620*52652Smckusick 
621*52652Smckusick     maxexitcnt = 0;
622*52652Smckusick     maxwithparentcnt = 0;
623*52652Smckusick     maxnoparentcnt = 0;
624*52652Smckusick     for ( endlist = &archead , arcp = archead ; arcp ; ) {
625*52652Smckusick 	if ( arcp -> arc_cyclecnt == 0 ) {
626*52652Smckusick 	    arcp -> arc_flags &= ~ONLIST;
627*52652Smckusick 	    *endlist = arcp -> arc_next;
628*52652Smckusick 	    arcp -> arc_next = 0;
629*52652Smckusick 	    arcp = *endlist;
630*52652Smckusick 	    continue;
631*52652Smckusick 	}
632*52652Smckusick 	if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) {
633*52652Smckusick 	    if ( arcp -> arc_cyclecnt > maxexitcnt ||
634*52652Smckusick 		( arcp -> arc_cyclecnt == maxexitcnt &&
635*52652Smckusick 		arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) {
636*52652Smckusick 		maxexitcnt = arcp -> arc_cyclecnt;
637*52652Smckusick 		maxexitarcp = arcp;
638*52652Smckusick 	    }
639*52652Smckusick 	} else if ( arcp -> arc_childp -> parentcnt > 1 ) {
640*52652Smckusick 	    if ( arcp -> arc_cyclecnt > maxwithparentcnt ||
641*52652Smckusick 		( arcp -> arc_cyclecnt == maxwithparentcnt &&
642*52652Smckusick 		arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) {
643*52652Smckusick 		maxwithparentcnt = arcp -> arc_cyclecnt;
644*52652Smckusick 		maxwithparentarcp = arcp;
645*52652Smckusick 	    }
646*52652Smckusick 	} else {
647*52652Smckusick 	    if ( arcp -> arc_cyclecnt > maxnoparentcnt ||
648*52652Smckusick 		( arcp -> arc_cyclecnt == maxnoparentcnt &&
649*52652Smckusick 		arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) {
650*52652Smckusick 		maxnoparentcnt = arcp -> arc_cyclecnt;
651*52652Smckusick 		maxnoparentarcp = arcp;
652*52652Smckusick 	    }
653*52652Smckusick 	}
654*52652Smckusick 	endlist = &arcp -> arc_next;
655*52652Smckusick 	arcp = arcp -> arc_next;
656*52652Smckusick     }
657*52652Smckusick     if ( maxexitcnt > 0 ) {
658*52652Smckusick 	/*
659*52652Smckusick 	 *	first choice is edge leading to node with out-of-cycle parent
660*52652Smckusick 	 */
661*52652Smckusick 	maxarcp = maxexitarcp;
662*52652Smckusick #	ifdef DEBUG
663*52652Smckusick 	    type = "exit";
664*52652Smckusick #	endif DEBUG
665*52652Smckusick     } else if ( maxwithparentcnt > 0 ) {
666*52652Smckusick 	/*
667*52652Smckusick 	 *	second choice is edge leading to node with at least one
668*52652Smckusick 	 *	other in-cycle parent
669*52652Smckusick 	 */
670*52652Smckusick 	maxarcp = maxwithparentarcp;
671*52652Smckusick #	ifdef DEBUG
672*52652Smckusick 	    type = "internal";
673*52652Smckusick #	endif DEBUG
674*52652Smckusick     } else {
675*52652Smckusick 	/*
676*52652Smckusick 	 *	last choice is edge leading to node with only this arc as
677*52652Smckusick 	 *	a parent (as it will now be orphaned)
678*52652Smckusick 	 */
679*52652Smckusick 	maxarcp = maxnoparentarcp;
680*52652Smckusick #	ifdef DEBUG
681*52652Smckusick 	    type = "orphan";
682*52652Smckusick #	endif DEBUG
683*52652Smckusick     }
684*52652Smckusick     maxarcp -> arc_flags |= DEADARC;
685*52652Smckusick     maxarcp -> arc_childp -> parentcnt -= 1;
686*52652Smckusick     maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count;
687*52652Smckusick #   ifdef DEBUG
688*52652Smckusick 	if ( debug & BREAKCYCLE ) {
689*52652Smckusick 	    printf( "%s delete %s arc: %s (%d) -> %s from %d cycle(s)\n" ,
690*52652Smckusick 		"[compresslist]" , type , maxarcp -> arc_parentp -> name ,
691*52652Smckusick 		maxarcp -> arc_count , maxarcp -> arc_childp -> name ,
692*52652Smckusick 		maxarcp -> arc_cyclecnt );
693*52652Smckusick 	}
694*52652Smckusick #   endif DEBUG
695*52652Smckusick     printf( "\t%s to %s with %d calls\n" , maxarcp -> arc_parentp -> name ,
696*52652Smckusick 	maxarcp -> arc_childp -> name , maxarcp -> arc_count );
697*52652Smckusick     prev = &cyclehead;
698*52652Smckusick     for ( clp = cyclehead ; clp ; ) {
699*52652Smckusick 	endlist = &clp -> list[ clp -> size ];
700*52652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
701*52652Smckusick 	    if ( (*arcpp) -> arc_flags & DEADARC )
702*52652Smckusick 		break;
703*52652Smckusick 	if ( arcpp == endlist ) {
704*52652Smckusick 	    prev = &clp -> next;
705*52652Smckusick 	    clp = clp -> next;
706*52652Smckusick 	    continue;
707*52652Smckusick 	}
708*52652Smckusick 	for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
709*52652Smckusick 	    (*arcpp) -> arc_cyclecnt--;
710*52652Smckusick 	cyclecnt--;
711*52652Smckusick 	*prev = clp -> next;
712*52652Smckusick 	clp = clp -> next;
713*52652Smckusick 	free( clp );
714*52652Smckusick     }
715*52652Smckusick }
716*52652Smckusick 
717*52652Smckusick #ifdef DEBUG
718*52652Smckusick printsubcycle( clp )
719*52652Smckusick     cltype	*clp;
720*52652Smckusick {
721*52652Smckusick     arctype	**arcpp;
722*52652Smckusick     arctype	**endlist;
723*52652Smckusick 
724*52652Smckusick     arcpp = clp -> list;
725*52652Smckusick     printf( "%s <cycle %d>\n" , (*arcpp) -> arc_parentp -> name ,
726*52652Smckusick 	(*arcpp) -> arc_parentp -> cycleno ) ;
727*52652Smckusick     for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ )
728*52652Smckusick 	printf( "\t(%d) -> %s\n" , (*arcpp) -> arc_count ,
729*52652Smckusick 	    (*arcpp) -> arc_childp -> name ) ;
730*52652Smckusick }
731*52652Smckusick #endif DEBUG
732*52652Smckusick 
7337172Speter cycletime()
7347172Speter {
7357172Speter     int			cycle;
7367172Speter     nltype		*cyclenlp;
7377172Speter     nltype		*childp;
7387172Speter 
7397172Speter     for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
7407172Speter 	cyclenlp = &cyclenl[ cycle ];
7417221Speter 	for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
7427221Speter 	    if ( childp -> propfraction == 0.0 ) {
7437221Speter 		    /*
7447221Speter 		     * all members have the same propfraction except those
7457221Speter 		     *	that were excluded with -E
7467221Speter 		     */
7477221Speter 		continue;
7487221Speter 	    }
7497221Speter 	    cyclenlp -> time += childp -> time;
7504508Speter 	}
7517221Speter 	cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
7524508Speter     }
7534508Speter }
7547172Speter 
7557172Speter     /*
7567172Speter      *	in one top to bottom pass over the topologically sorted namelist
7577221Speter      *	propagate:
7587221Speter      *		printflag as the union of parents' printflags
7597221Speter      *		propfraction as the sum of fractional parents' propfractions
7607221Speter      *	and while we're here, sum time for functions.
7617172Speter      */
7627172Speter doflags()
7637172Speter {
7647172Speter     int		index;
7657172Speter     nltype	*childp;
7667172Speter     nltype	*oldhead;
7677172Speter 
7687172Speter     oldhead = 0;
7697172Speter     for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
7707172Speter 	childp = topsortnlp[ index ];
7717172Speter 	    /*
7727172Speter 	     *	if we haven't done this function or cycle,
7737221Speter 	     *	inherit things from parent.
7747172Speter 	     *	this way, we are linear in the number of arcs
7757172Speter 	     *	since we do all members of a cycle (and the cycle itself)
7767172Speter 	     *	as we hit the first member of the cycle.
7777172Speter 	     */
7787172Speter 	if ( childp -> cyclehead != oldhead ) {
7797172Speter 	    oldhead = childp -> cyclehead;
7807221Speter 	    inheritflags( childp );
7817172Speter 	}
7827221Speter #	ifdef DEBUG
7837221Speter 	    if ( debug & PROPDEBUG ) {
7847221Speter 		printf( "[doflags] " );
7857221Speter 		printname( childp );
7867221Speter 		printf( " inherits printflag %d and propfraction %f\n" ,
7877221Speter 			childp -> printflag , childp -> propfraction );
7887221Speter 	    }
7897221Speter #	endif DEBUG
7907172Speter 	if ( ! childp -> printflag ) {
7917172Speter 		/*
7927221Speter 		 *	printflag is off
7937221Speter 		 *	it gets turned on by
7947221Speter 		 *	being on -f list,
7957221Speter 		 *	or there not being any -f list and not being on -e list.
7967172Speter 		 */
7977221Speter 	    if (   onlist( flist , childp -> name )
7987221Speter 		|| ( !fflag && !onlist( elist , childp -> name ) ) ) {
7997172Speter 		childp -> printflag = TRUE;
8007172Speter 	    }
8017221Speter 	} else {
8027221Speter 		/*
8037221Speter 		 *	this function has printing parents:
8047221Speter 		 *	maybe someone wants to shut it up
8057221Speter 		 *	by putting it on -e list.  (but favor -f over -e)
8067221Speter 		 */
8077221Speter 	    if (  ( !onlist( flist , childp -> name ) )
8087221Speter 		&& onlist( elist , childp -> name ) ) {
8097221Speter 		childp -> printflag = FALSE;
8107172Speter 	    }
8117221Speter 	}
8127221Speter 	if ( childp -> propfraction == 0.0 ) {
8137221Speter 		/*
8147221Speter 		 *	no parents to pass time to.
8157221Speter 		 *	collect time from children if
8167221Speter 		 *	its on -F list,
8177221Speter 		 *	or there isn't any -F list and its not on -E list.
8187221Speter 		 */
8197221Speter 	    if ( onlist( Flist , childp -> name )
8207221Speter 		|| ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
8217221Speter 		    childp -> propfraction = 1.0;
8227172Speter 	    }
8237221Speter 	} else {
8247221Speter 		/*
8257221Speter 		 *	it has parents to pass time to,
8267221Speter 		 *	but maybe someone wants to shut it up
8277221Speter 		 *	by puttting it on -E list.  (but favor -F over -E)
8287221Speter 		 */
8297221Speter 	    if (  !onlist( Flist , childp -> name )
8307221Speter 		&& onlist( Elist , childp -> name ) ) {
8317221Speter 		childp -> propfraction = 0.0;
8327221Speter 	    }
8337172Speter 	}
8347221Speter 	childp -> propself = childp -> time * childp -> propfraction;
8357221Speter 	printtime += childp -> propself;
8367221Speter #	ifdef DEBUG
8377221Speter 	    if ( debug & PROPDEBUG ) {
8387221Speter 		printf( "[doflags] " );
8397221Speter 		printname( childp );
8407221Speter 		printf( " ends up with printflag %d and propfraction %f\n" ,
8417221Speter 			childp -> printflag , childp -> propfraction );
8428908Speter 		printf( "time %f propself %f printtime %f\n" ,
8438908Speter 			childp -> time , childp -> propself , printtime );
8447221Speter 	    }
8457221Speter #	endif DEBUG
8467172Speter     }
8477172Speter }
8487172Speter 
8497172Speter     /*
8507172Speter      *	check if any parent of this child
8517172Speter      *	(or outside parents of this cycle)
8527172Speter      *	have their print flags on and set the
8537172Speter      *	print flag of the child (cycle) appropriately.
8547221Speter      *	similarly, deal with propagation fractions from parents.
8557172Speter      */
8567221Speter inheritflags( childp )
8577172Speter     nltype	*childp;
8587172Speter {
8597172Speter     nltype	*headp;
8607221Speter     arctype	*arcp;
8617221Speter     nltype	*parentp;
8627172Speter     nltype	*memp;
8637172Speter 
8647172Speter     headp = childp -> cyclehead;
8657172Speter     if ( childp == headp ) {
8667172Speter 	    /*
8677172Speter 	     *	just a regular child, check its parents
8687172Speter 	     */
8697221Speter 	childp -> printflag = FALSE;
8707221Speter 	childp -> propfraction = 0.0;
8717221Speter 	for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
8727221Speter 	    parentp = arcp -> arc_parentp;
8738908Speter 	    if ( childp == parentp ) {
8748908Speter 		continue;
8758908Speter 	    }
8767221Speter 	    childp -> printflag |= parentp -> printflag;
87714140Speter 		/*
87814140Speter 		 *	if the child was never actually called
87914140Speter 		 *	(e.g. this arc is static (and all others are, too))
88014140Speter 		 *	no time propagates along this arc.
88114140Speter 		 */
882*52652Smckusick 	    if ( arcp -> arc_flags & DEADARC ) {
883*52652Smckusick 		continue;
884*52652Smckusick 	    }
885*52652Smckusick 	    if ( childp -> npropcall ) {
88614140Speter 		childp -> propfraction += parentp -> propfraction
887*52652Smckusick 					* ( ( (double) arcp -> arc_count )
888*52652Smckusick 					  / ( (double) childp -> npropcall ) );
88914140Speter 	    }
8907172Speter 	}
8917221Speter     } else {
8927221Speter 	    /*
8937221Speter 	     *	its a member of a cycle, look at all parents from
8947221Speter 	     *	outside the cycle
8957221Speter 	     */
8967221Speter 	headp -> printflag = FALSE;
8977221Speter 	headp -> propfraction = 0.0;
8987221Speter 	for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
8997221Speter 	    for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
9007221Speter 		if ( arcp -> arc_parentp -> cyclehead == headp ) {
9017221Speter 		    continue;
9027221Speter 		}
9037221Speter 		parentp = arcp -> arc_parentp;
9047221Speter 		headp -> printflag |= parentp -> printflag;
90514140Speter 		    /*
90614140Speter 		     *	if the cycle was never actually called
90714140Speter 		     *	(e.g. this arc is static (and all others are, too))
90814140Speter 		     *	no time propagates along this arc.
90914140Speter 		     */
910*52652Smckusick 		if ( arcp -> arc_flags & DEADARC ) {
911*52652Smckusick 		    continue;
912*52652Smckusick 		}
913*52652Smckusick 		if ( headp -> npropcall ) {
91414140Speter 		    headp -> propfraction += parentp -> propfraction
915*52652Smckusick 					* ( ( (double) arcp -> arc_count )
916*52652Smckusick 					  / ( (double) headp -> npropcall ) );
91714140Speter 		}
9187172Speter 	    }
9197172Speter 	}
9207221Speter 	for ( memp = headp ; memp ; memp = memp -> cnext ) {
9217221Speter 	    memp -> printflag = headp -> printflag;
9227221Speter 	    memp -> propfraction = headp -> propfraction;
9237221Speter 	}
9247172Speter     }
9257172Speter }
926