xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 7221)
14508Speter #ifndef lint
2*7221Speter     static	char *sccsid = "@(#)arcs.c	1.8 (Berkeley) 06/18/82";
34508Speter #endif lint
44508Speter 
54561Speter #include "gprof.h"
64508Speter 
74721Speter     /*
84721Speter      *	add (or just increment) an arc
94721Speter      */
104721Speter addarc( parentp , childp , count )
114721Speter     nltype	*parentp;
124721Speter     nltype	*childp;
134721Speter     long	count;
144721Speter {
154750Speter     arctype		*calloc();
164721Speter     arctype		*arcp;
174721Speter 
184721Speter #   ifdef DEBUG
194721Speter 	if ( debug & TALLYDEBUG ) {
204721Speter 	    printf( "[addarc] %d arcs from %s to %s\n" ,
214721Speter 		    count , parentp -> name , childp -> name );
224721Speter 	}
234721Speter #   endif DEBUG
244721Speter     arcp = arclookup( parentp , childp );
254721Speter     if ( arcp != 0 ) {
264721Speter 	    /*
274721Speter 	     *	a hit:  just increment the count.
284721Speter 	     */
294721Speter #	ifdef DEBUG
304721Speter 	    if ( debug & TALLYDEBUG ) {
314721Speter 		printf( "[tally] hit %d += %d\n" ,
324721Speter 			arcp -> arc_count , count );
334721Speter 	    }
344721Speter #	endif DEBUG
354721Speter 	arcp -> arc_count += count;
364721Speter 	return;
374721Speter     }
384750Speter     arcp = calloc( 1 , sizeof *arcp );
394721Speter     arcp -> arc_parentp = parentp;
404721Speter     arcp -> arc_childp = childp;
414721Speter     arcp -> arc_count = count;
424721Speter 	/*
434721Speter 	 *	prepend this child to the children of this parent
444721Speter 	 */
454721Speter     arcp -> arc_childlist = parentp -> children;
464721Speter     parentp -> children = arcp;
474721Speter 	/*
484721Speter 	 *	prepend this parent to the parents of this child
494721Speter 	 */
504721Speter     arcp -> arc_parentlist = childp -> parents;
514721Speter     childp -> parents = arcp;
524721Speter }
534721Speter 
547172Speter     /*
557172Speter      *	the code below topologically sorts the graph (collapsing cycles),
567172Speter      *	and propagates time bottom up and flags top down.
577172Speter      */
587172Speter 
597172Speter     /*
607172Speter      *	the topologically sorted name list pointers
617172Speter      */
627172Speter nltype	**topsortnlp;
637172Speter 
644508Speter topcmp( npp1 , npp2 )
654508Speter     nltype	**npp1;
664508Speter     nltype	**npp2;
674508Speter {
684508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
694508Speter }
704508Speter 
714508Speter doarcs()
724508Speter {
734508Speter     nltype	*parentp;
744508Speter     arctype	*arcp;
754508Speter     long	index;
764508Speter 
774508Speter 	/*
784508Speter 	 *	initialize various things:
794508Speter 	 *	    zero out child times.
804508Speter 	 *	    count self-recursive calls.
814508Speter 	 *	    indicate that nothing is on cycles.
824508Speter 	 */
834508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
844508Speter 	parentp -> childtime = 0.0;
854508Speter 	arcp = arclookup( parentp , parentp );
864508Speter 	if ( arcp != 0 ) {
874508Speter 	    parentp -> ncall -= arcp -> arc_count;
884508Speter 	    parentp -> selfcalls = arcp -> arc_count;
894508Speter 	} else {
904508Speter 	    parentp -> selfcalls = 0;
914508Speter 	}
92*7221Speter 	parentp -> propfraction = 0.0;
93*7221Speter 	parentp -> propself = 0.0;
94*7221Speter 	parentp -> propchild = 0.0;
957172Speter 	parentp -> printflag = FALSE;
964508Speter 	parentp -> toporder = 0;
974508Speter 	parentp -> cycleno = 0;
984508Speter 	parentp -> cyclehead = parentp;
994508Speter 	parentp -> cnext = 0;
1007172Speter 	if ( cflag ) {
1017172Speter 	    findcalls( parentp , parentp -> value , (parentp+1) -> value );
1027172Speter 	}
1034508Speter     }
1044508Speter 	/*
1054508Speter 	 *	topologically order things
1064508Speter 	 *	from each of the roots of the call graph
1074508Speter 	 */
1084508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
1094508Speter 	if ( parentp -> parents == 0 ) {
1104508Speter 	    dfn( parentp );
1114508Speter 	}
1124508Speter     }
1134508Speter 	/*
1144508Speter 	 *	link together nodes on the same cycle
1154508Speter 	 */
1164508Speter     cyclelink();
1174508Speter 	/*
1184508Speter 	 *	Sort the symbol table in reverse topological order
1194508Speter 	 */
1204508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1214508Speter     if ( topsortnlp == (nltype **) 0 ) {
1224508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1234508Speter     }
1244508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1254508Speter 	topsortnlp[ index ] = &nl[ index ];
1264508Speter     }
1274508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1284508Speter #   ifdef DEBUG
1294508Speter 	if ( debug & DFNDEBUG ) {
1304508Speter 	    printf( "[doarcs] topological sort listing\n" );
1314508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1324508Speter 		printf( "[doarcs] " );
1334508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1344508Speter 		printname( topsortnlp[ index ] );
1354508Speter 		printf( "\n" );
1364508Speter 	    }
1374508Speter 	}
1384508Speter #   endif DEBUG
1394508Speter 	/*
140*7221Speter 	 *	starting from the topological top,
141*7221Speter 	 *	propagate print flags to children.
142*7221Speter 	 *	also, calculate propagation fractions.
143*7221Speter 	 *	this happens before time propagation
144*7221Speter 	 *	since time propagation uses the fractions.
145*7221Speter 	 */
146*7221Speter     doflags();
147*7221Speter 	/*
1484508Speter 	 *	starting from the topological bottom,
1497172Speter 	 *	propogate children times up to parents.
1504508Speter 	 */
1517172Speter     dotime();
1527172Speter     printgprof();
1537172Speter }
1547172Speter 
1557172Speter dotime()
1567172Speter {
1577172Speter     int	index;
1587172Speter 
1597172Speter     cycletime();
1604508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1617172Speter 	timepropagate( topsortnlp[ index ] );
1627127Speter     }
1637127Speter }
1647127Speter 
1657172Speter timepropagate( parentp )
1667127Speter     nltype	*parentp;
1677127Speter {
1687127Speter     arctype	*arcp;
1697127Speter     nltype	*childp;
1707127Speter     double	share;
171*7221Speter     double	propshare;
1727127Speter 
173*7221Speter     if ( parentp -> propfraction == 0.0 ) {
174*7221Speter 	return;
175*7221Speter     }
1767127Speter 	/*
1777127Speter 	 *	gather time from children of this parent.
1787127Speter 	 */
1797172Speter     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
1807127Speter 	childp = arcp -> arc_childp;
1817127Speter 	if ( arcp -> arc_count == 0 ) {
1827127Speter 	    continue;
1837127Speter 	}
184*7221Speter 	if ( childp == parentp ) {
1857127Speter 	    continue;
1867127Speter 	}
187*7221Speter 	if ( childp -> propfraction == 0.0 ) {
1887127Speter 	    continue;
1897127Speter 	}
1907127Speter 	if ( childp -> cyclehead != childp ) {
1917127Speter 	    if ( parentp -> cycleno == childp -> cycleno ) {
1927127Speter 		continue;
1937127Speter 	    }
1947127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
1957127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
1964508Speter 	    }
1977127Speter 	    childp = childp -> cyclehead;
1987127Speter 	} else {
1997127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2007127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2014508Speter 		continue;
2024508Speter 	    }
2037127Speter 	}
204*7221Speter 	if ( childp -> ncall == 0 ) {
205*7221Speter 	    continue;
206*7221Speter 	}
2077127Speter 	    /*
2087127Speter 	     *	distribute time for this arc
2097127Speter 	     */
210*7221Speter 	arcp -> arc_time = childp -> time
211*7221Speter 			        * ( ( (double) arcp -> arc_count ) /
212*7221Speter 				    ( (double) childp -> ncall ) );
213*7221Speter 	arcp -> arc_childtime = childp -> childtime
214*7221Speter 			        * ( ( (double) arcp -> arc_count ) /
215*7221Speter 				    ( (double) childp -> ncall ) );
2167127Speter 	share = arcp -> arc_time + arcp -> arc_childtime;
2177127Speter 	parentp -> childtime += share;
2187127Speter 	    /*
219*7221Speter 	     *	( 1 - propfraction ) gets lost along the way
2207127Speter 	     */
221*7221Speter 	propshare = parentp -> propfraction * share;
222*7221Speter 	    /*
223*7221Speter 	     *	fix things for printing
224*7221Speter 	     */
225*7221Speter 	parentp -> propchild += propshare;
226*7221Speter 	arcp -> arc_time *= parentp -> propfraction;
227*7221Speter 	arcp -> arc_childtime *= parentp -> propfraction;
228*7221Speter 	    /*
229*7221Speter 	     *	add this share to the parent's cycle header, if any.
230*7221Speter 	     */
2317127Speter 	if ( parentp -> cyclehead != parentp ) {
2327127Speter 	    parentp -> cyclehead -> childtime += share;
233*7221Speter 	    parentp -> cyclehead -> propchild += propshare;
2344508Speter 	}
235*7221Speter #	ifdef DEBUG
236*7221Speter 	    if ( debug & PROPDEBUG ) {
237*7221Speter 		printf( "[dotime] child \t" );
238*7221Speter 		printname( childp );
239*7221Speter 		printf( " with %f %f %d/%d\n" ,
240*7221Speter 			childp -> time , childp -> childtime ,
241*7221Speter 			arcp -> arc_count , childp -> ncall );
242*7221Speter 		printf( "[dotime] parent\t" );
243*7221Speter 		printname( parentp );
244*7221Speter 		printf( "\n[dotime] share %f\n" , share );
245*7221Speter 	    }
246*7221Speter #	endif DEBUG
2474508Speter     }
2484508Speter }
2494508Speter 
2504508Speter cyclelink()
2514508Speter {
2524508Speter     register nltype	*nlp;
2534508Speter     register nltype	*cyclenlp;
2544508Speter     int			cycle;
2557172Speter     nltype		*memberp;
2564508Speter 
2574508Speter 	/*
2584508Speter 	 *	Count the number of cycles, and initialze the cycle lists
2594508Speter 	 */
2607127Speter     ncycle = 0;
2614508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2624508Speter 	    /*
2634508Speter 	     *	this is how you find unattached cycles
2644508Speter 	     */
2654508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
2667127Speter 	    ncycle += 1;
2674508Speter 	}
2684508Speter     }
2697127Speter 	/*
2707127Speter 	 *	cyclenl is indexed by cycle number:
2717127Speter 	 *	i.e. it is origin 1, not origin 0.
2727127Speter 	 */
2737127Speter     cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
2747127Speter     if ( cyclenl == 0 ) {
2757127Speter 	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
2767127Speter 		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
2777127Speter 	done();
2784508Speter     }
2794508Speter 	/*
2804508Speter 	 *	now link cycles to true cycleheads,
2814508Speter 	 *	number them, accumulate the data for the cycle
2824508Speter 	 */
2834508Speter     cycle = 0;
2844508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2854508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
2864508Speter 	    continue;
2874508Speter 	}
2884508Speter 	cycle += 1;
2897127Speter 	cyclenlp = &cyclenl[cycle];
290*7221Speter         cyclenlp -> name = "";		/* the name */
291*7221Speter         cyclenlp -> value = 0;		/* the pc entry point */
292*7221Speter         cyclenlp -> time = 0.0;		/* ticks in this routine */
293*7221Speter         cyclenlp -> childtime = 0.0;	/* cumulative ticks in children */
294*7221Speter 	cyclenlp -> ncall = 0;		/* how many times called */
295*7221Speter 	cyclenlp -> selfcalls = 0;	/* how many calls to self */
296*7221Speter 	cyclenlp -> propfraction = 0.0;	/* what % of time propagates */
297*7221Speter 	cyclenlp -> propself = 0.0;	/* how much self time propagates */
298*7221Speter 	cyclenlp -> propchild = 0.0;	/* how much child time propagates */
299*7221Speter 	cyclenlp -> printflag = TRUE;	/* should this be printed? */
300*7221Speter 	cyclenlp -> index = 0;		/* index in the graph list */
301*7221Speter 	cyclenlp -> toporder = 0;	/* graph call chain top-sort order */
302*7221Speter 	cyclenlp -> cycleno = cycle;	/* internal number of cycle on */
303*7221Speter 	cyclenlp -> cyclehead = cyclenlp;	/* pointer to head of cycle */
304*7221Speter 	cyclenlp -> cnext = nlp;	/* pointer to next member of cycle */
305*7221Speter 	cyclenlp -> parents = 0;	/* list of caller arcs */
306*7221Speter 	cyclenlp -> children = 0;	/* list of callee arcs */
3074508Speter #	ifdef DEBUG
3084508Speter 	    if ( debug & CYCLEDEBUG ) {
3094508Speter 		printf( "[cyclelink] " );
3104508Speter 		printname( nlp );
3114508Speter 		printf( " is the head of cycle %d\n" , cycle );
3124508Speter 	    }
3134508Speter #	endif DEBUG
3147172Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
3157172Speter 	    memberp -> cycleno = cycle;
3167172Speter 	    memberp -> cyclehead = cyclenlp;
3177172Speter 	}
3187172Speter     }
3197172Speter }
3207172Speter 
3217172Speter cycletime()
3227172Speter {
3237172Speter     int			cycle;
3247172Speter     nltype		*cyclenlp;
3257172Speter     nltype		*childp;
3267172Speter     arctype		*arcp;
327*7221Speter     nltype		*parentp;
3287172Speter 
3297172Speter     for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
3307172Speter 	cyclenlp = &cyclenl[ cycle ];
331*7221Speter 	for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
332*7221Speter 	    if ( childp -> propfraction == 0.0 ) {
333*7221Speter 		    /*
334*7221Speter 		     * all members have the same propfraction except those
335*7221Speter 		     *	that were excluded with -E
336*7221Speter 		     */
337*7221Speter 		continue;
338*7221Speter 	    }
339*7221Speter 	    cyclenlp -> time += childp -> time;
340*7221Speter 	    for ( arcp=childp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
341*7221Speter 		parentp = arcp -> arc_parentp;
3424508Speter 		if ( parentp == childp ) {
3434508Speter 		    continue;
3444508Speter 		}
345*7221Speter 		if ( parentp -> cyclehead == cyclenlp ) {
346*7221Speter 		    cyclenlp -> selfcalls += arcp -> arc_count;
347*7221Speter 		} else {
348*7221Speter 		    cyclenlp -> ncall += arcp -> arc_count;
3494508Speter 		}
3504508Speter 	    }
3514508Speter 	}
352*7221Speter 	cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
3534508Speter     }
3544508Speter }
3557172Speter 
3567172Speter     /*
3577172Speter      *	in one top to bottom pass over the topologically sorted namelist
358*7221Speter      *	propagate:
359*7221Speter      *		printflag as the union of parents' printflags
360*7221Speter      *		propfraction as the sum of fractional parents' propfractions
361*7221Speter      *	and while we're here, sum time for functions.
3627172Speter      */
3637172Speter doflags()
3647172Speter {
3657172Speter     int		index;
3667172Speter     nltype	*childp;
3677172Speter     nltype	*oldhead;
3687172Speter 
3697172Speter     oldhead = 0;
3707172Speter     for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
3717172Speter 	childp = topsortnlp[ index ];
3727172Speter 	    /*
3737172Speter 	     *	if we haven't done this function or cycle,
374*7221Speter 	     *	inherit things from parent.
3757172Speter 	     *	this way, we are linear in the number of arcs
3767172Speter 	     *	since we do all members of a cycle (and the cycle itself)
3777172Speter 	     *	as we hit the first member of the cycle.
3787172Speter 	     */
3797172Speter 	if ( childp -> cyclehead != oldhead ) {
3807172Speter 	    oldhead = childp -> cyclehead;
381*7221Speter 	    inheritflags( childp );
3827172Speter 	}
383*7221Speter #	ifdef DEBUG
384*7221Speter 	    if ( debug & PROPDEBUG ) {
385*7221Speter 		printf( "[doflags] " );
386*7221Speter 		printname( childp );
387*7221Speter 		printf( " inherits printflag %d and propfraction %f\n" ,
388*7221Speter 			childp -> printflag , childp -> propfraction );
389*7221Speter 	    }
390*7221Speter #	endif DEBUG
3917172Speter 	if ( ! childp -> printflag ) {
3927172Speter 		/*
393*7221Speter 		 *	printflag is off
394*7221Speter 		 *	it gets turned on by
395*7221Speter 		 *	being on -f list,
396*7221Speter 		 *	or there not being any -f list and not being on -e list.
3977172Speter 		 */
398*7221Speter 	    if (   onlist( flist , childp -> name )
399*7221Speter 		|| ( !fflag && !onlist( elist , childp -> name ) ) ) {
4007172Speter 		childp -> printflag = TRUE;
4017172Speter 	    }
402*7221Speter 	} else {
403*7221Speter 		/*
404*7221Speter 		 *	this function has printing parents:
405*7221Speter 		 *	maybe someone wants to shut it up
406*7221Speter 		 *	by putting it on -e list.  (but favor -f over -e)
407*7221Speter 		 */
408*7221Speter 	    if (  ( !onlist( flist , childp -> name ) )
409*7221Speter 		&& onlist( elist , childp -> name ) ) {
410*7221Speter 		childp -> printflag = FALSE;
4117172Speter 	    }
412*7221Speter 	}
413*7221Speter 	if ( childp -> propfraction == 0.0 ) {
414*7221Speter 		/*
415*7221Speter 		 *	no parents to pass time to.
416*7221Speter 		 *	collect time from children if
417*7221Speter 		 *	its on -F list,
418*7221Speter 		 *	or there isn't any -F list and its not on -E list.
419*7221Speter 		 */
420*7221Speter 	    if ( onlist( Flist , childp -> name )
421*7221Speter 		|| ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
422*7221Speter 		    childp -> propfraction = 1.0;
4237172Speter 	    }
424*7221Speter 	} else {
425*7221Speter 		/*
426*7221Speter 		 *	it has parents to pass time to,
427*7221Speter 		 *	but maybe someone wants to shut it up
428*7221Speter 		 *	by puttting it on -E list.  (but favor -F over -E)
429*7221Speter 		 */
430*7221Speter 	    if (  !onlist( Flist , childp -> name )
431*7221Speter 		&& onlist( Elist , childp -> name ) ) {
432*7221Speter 		childp -> propfraction = 0.0;
433*7221Speter 	    }
4347172Speter 	}
435*7221Speter 	childp -> propself = childp -> time * childp -> propfraction;
436*7221Speter 	printtime += childp -> propself;
437*7221Speter #	ifdef DEBUG
438*7221Speter 	    if ( debug & PROPDEBUG ) {
439*7221Speter 		printf( "[doflags] " );
440*7221Speter 		printname( childp );
441*7221Speter 		printf( " ends up with printflag %d and propfraction %f\n" ,
442*7221Speter 			childp -> printflag , childp -> propfraction );
443*7221Speter 		printf( "time %f propself %f\n" ,
444*7221Speter 			childp -> time , childp -> propself );
445*7221Speter 	    }
446*7221Speter #	endif DEBUG
4477172Speter     }
4487172Speter }
4497172Speter 
4507172Speter     /*
4517172Speter      *	check if any parent of this child
4527172Speter      *	(or outside parents of this cycle)
4537172Speter      *	have their print flags on and set the
4547172Speter      *	print flag of the child (cycle) appropriately.
455*7221Speter      *	similarly, deal with propagation fractions from parents.
4567172Speter      */
457*7221Speter inheritflags( childp )
4587172Speter     nltype	*childp;
4597172Speter {
4607172Speter     nltype	*headp;
461*7221Speter     arctype	*arcp;
462*7221Speter     nltype	*parentp;
4637172Speter     nltype	*memp;
4647172Speter 
4657172Speter     headp = childp -> cyclehead;
4667172Speter     if ( childp == headp ) {
4677172Speter 	    /*
4687172Speter 	     *	just a regular child, check its parents
4697172Speter 	     */
470*7221Speter 	childp -> printflag = FALSE;
471*7221Speter 	childp -> propfraction = 0.0;
472*7221Speter 	for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
473*7221Speter 	    parentp = arcp -> arc_parentp;
474*7221Speter 	    childp -> printflag |= parentp -> printflag;
475*7221Speter 	    childp -> propfraction += parentp -> propfraction
476*7221Speter 					* ( ( (double) arcp -> arc_count )
477*7221Speter 					  / ( (double) childp -> ncall) );
4787172Speter 	}
479*7221Speter     } else {
480*7221Speter 	    /*
481*7221Speter 	     *	its a member of a cycle, look at all parents from
482*7221Speter 	     *	outside the cycle
483*7221Speter 	     */
484*7221Speter 	headp -> printflag = FALSE;
485*7221Speter 	headp -> propfraction = 0.0;
486*7221Speter 	for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
487*7221Speter 	    for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
488*7221Speter 		if ( arcp -> arc_parentp -> cyclehead == headp ) {
489*7221Speter 		    continue;
490*7221Speter 		}
491*7221Speter 		parentp = arcp -> arc_parentp;
492*7221Speter 		headp -> printflag |= parentp -> printflag;
493*7221Speter 		headp -> propfraction += parentp -> propfraction *
494*7221Speter 					(arcp -> arc_count / headp -> ncall);
4957172Speter 	    }
4967172Speter 	}
497*7221Speter 	for ( memp = headp ; memp ; memp = memp -> cnext ) {
498*7221Speter 	    memp -> printflag = headp -> printflag;
499*7221Speter 	    memp -> propfraction = headp -> propfraction;
500*7221Speter 	}
5017172Speter     }
5027172Speter }
503