xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 7172)
14508Speter #ifndef lint
2*7172Speter     static	char *sccsid = "@(#)arcs.c	1.7 (Berkeley) 06/14/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 
54*7172Speter     /*
55*7172Speter      *	the code below topologically sorts the graph (collapsing cycles),
56*7172Speter      *	and propagates time bottom up and flags top down.
57*7172Speter      */
58*7172Speter 
59*7172Speter     /*
60*7172Speter      *	the topologically sorted name list pointers
61*7172Speter      */
62*7172Speter nltype	**topsortnlp;
63*7172Speter 
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*7172Speter 	parentp -> printflag = FALSE;
934508Speter 	parentp -> toporder = 0;
944508Speter 	parentp -> cycleno = 0;
954508Speter 	parentp -> cyclehead = parentp;
964508Speter 	parentp -> cnext = 0;
97*7172Speter 	if ( cflag ) {
98*7172Speter 	    findcalls( parentp , parentp -> value , (parentp+1) -> value );
99*7172Speter 	}
1004508Speter     }
1014508Speter 	/*
102*7172Speter 	 *	time for functions which print is accumulated here.
103*7172Speter 	 */
104*7172Speter     printtime = 0.0;
105*7172Speter 	/*
1064508Speter 	 *	topologically order things
1074508Speter 	 *	from each of the roots of the call graph
1084508Speter 	 */
1094508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
1104508Speter 	if ( parentp -> parents == 0 ) {
1114508Speter 	    dfn( parentp );
1124508Speter 	}
1134508Speter     }
1144508Speter 	/*
1154508Speter 	 *	link together nodes on the same cycle
1164508Speter 	 */
1174508Speter     cyclelink();
1184508Speter 	/*
1194508Speter 	 *	Sort the symbol table in reverse topological order
1204508Speter 	 */
1214508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1224508Speter     if ( topsortnlp == (nltype **) 0 ) {
1234508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1244508Speter     }
1254508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1264508Speter 	topsortnlp[ index ] = &nl[ index ];
1274508Speter     }
1284508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1294508Speter #   ifdef DEBUG
1304508Speter 	if ( debug & DFNDEBUG ) {
1314508Speter 	    printf( "[doarcs] topological sort listing\n" );
1324508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1334508Speter 		printf( "[doarcs] " );
1344508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1354508Speter 		printname( topsortnlp[ index ] );
1364508Speter 		printf( "\n" );
1374508Speter 	    }
1384508Speter 	}
1394508Speter #   endif DEBUG
1404508Speter 	/*
1414508Speter 	 *	starting from the topological bottom,
142*7172Speter 	 *	propogate children times up to parents.
1434508Speter 	 */
144*7172Speter     dotime();
145*7172Speter 	/*
146*7172Speter 	 *	starting from the topological top,
147*7172Speter 	 *	propagate print flags to children.
148*7172Speter 	 */
149*7172Speter     doflags();
150*7172Speter     printgprof();
151*7172Speter }
152*7172Speter 
153*7172Speter dotime()
154*7172Speter {
155*7172Speter     int	index;
156*7172Speter 
157*7172Speter     cycletime();
1584508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
159*7172Speter 	timepropagate( topsortnlp[ index ] );
1607127Speter     }
1617127Speter }
1627127Speter 
163*7172Speter timepropagate( parentp )
1647127Speter     nltype	*parentp;
1657127Speter {
1667127Speter     arctype	*arcp;
1677127Speter     nltype	*childp;
1687127Speter     double	share;
1697127Speter 
1707127Speter 	/*
1717127Speter 	 *	gather time from children of this parent.
1727127Speter 	 */
173*7172Speter     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
1747127Speter 	childp = arcp -> arc_childp;
1757127Speter #	ifdef DEBUG
1767127Speter 	    if ( debug & ARCDEBUG ) {
1777127Speter 		printf( "[propagate] " );
1787127Speter 		printname( parentp );
1797127Speter 		printf( " calls " );
1807127Speter 		printname( childp );
1817127Speter 		printf( " %d (%d) times\n" ,
1827127Speter 			arcp -> arc_count , childp -> ncall );
1837127Speter 	    }
1847127Speter #	endif DEBUG
1857127Speter 	if ( arcp -> arc_count == 0 ) {
1867127Speter 	    continue;
1877127Speter 	}
1887127Speter 	if ( childp -> ncall == 0 ) {
1897127Speter 	    continue;
1907127Speter 	}
1917127Speter 	if ( childp == parentp ) {
1927127Speter 	    continue;
1937127Speter 	}
1947127Speter 	if ( childp -> cyclehead != childp ) {
1957127Speter 	    if ( parentp -> cycleno == childp -> cycleno ) {
1967127Speter 		continue;
1977127Speter 	    }
1984508Speter #	    ifdef DEBUG
1994508Speter 		if ( debug & ARCDEBUG ) {
2007127Speter 		    printf( "[propagate]\t it's a call into cycle %d\n" ,
2017127Speter 			    childp -> cycleno );
2024508Speter 		}
2034508Speter #	    endif DEBUG
2047127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2057127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2064508Speter 	    }
2077127Speter 	    childp = childp -> cyclehead;
2087127Speter 	} else {
2097127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
2107127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
2114508Speter 		continue;
2124508Speter 	    }
2137127Speter 	}
2147127Speter 	    /*
2157127Speter 	     *	distribute time for this arc
2167127Speter 	     */
2177127Speter 	arcp -> arc_time = childp -> time *
2187127Speter 			    ( ( (double) arcp -> arc_count ) /
2197127Speter 			    ( (double) childp -> ncall ) );
2207127Speter 	arcp -> arc_childtime = childp -> childtime *
2217127Speter 			    ( ( (double) arcp -> arc_count ) /
2227127Speter 			    ( (double) childp -> ncall ) );
2237127Speter 	share = arcp -> arc_time + arcp -> arc_childtime;
2247127Speter #	ifdef DEBUG
2257127Speter 	    if ( debug & ARCDEBUG ) {
2267127Speter 		printf( "[propagate]\t " );
2277127Speter 		printname( childp );
2287127Speter 		printf( " time %8.2f + childtime %8.2f\n" ,
2297127Speter 		    childp -> time , childp -> childtime );
2307127Speter 		printf( "[propagate]\t this is %d arcs of the %d calls\n",
2317127Speter 		    arcp -> arc_count , childp -> ncall );
2327127Speter 		printf( "[propagate]\t so this gives %8.2f+%8.2f to %s\n" ,
2337127Speter 		    arcp -> arc_time , arcp -> arc_childtime ,
2347127Speter 		    parentp -> name );
2354508Speter 	    }
2367127Speter #	endif DEBUG
2377127Speter 	parentp -> childtime += share;
2387127Speter 	    /*
2397127Speter 	     *	add this share to the cycle header, if any
2407127Speter 	     */
2417127Speter 	if ( parentp -> cyclehead != parentp ) {
2424508Speter #	    ifdef DEBUG
2434508Speter 		if ( debug & ARCDEBUG ) {
2447127Speter 		    printf( "[propagate]\t and to cycle %d\n" ,
2457127Speter 			    parentp -> cycleno );
2464508Speter 		}
2474508Speter #	    endif DEBUG
2487127Speter 	    parentp -> cyclehead -> childtime += share;
2494508Speter 	}
2504508Speter     }
2514508Speter }
2524508Speter 
2534508Speter cyclelink()
2544508Speter {
2554508Speter     register nltype	*nlp;
2564508Speter     register nltype	*cyclenlp;
2574508Speter     int			cycle;
258*7172Speter     nltype		*memberp;
2594508Speter 
2604508Speter 	/*
2614508Speter 	 *	Count the number of cycles, and initialze the cycle lists
2624508Speter 	 */
2637127Speter     ncycle = 0;
2644508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2654508Speter 	    /*
2664508Speter 	     *	this is how you find unattached cycles
2674508Speter 	     */
2684508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
2697127Speter 	    ncycle += 1;
2704508Speter 	}
2714508Speter     }
2727127Speter 	/*
2737127Speter 	 *	cyclenl is indexed by cycle number:
2747127Speter 	 *	i.e. it is origin 1, not origin 0.
2757127Speter 	 */
2767127Speter     cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
2777127Speter     if ( cyclenl == 0 ) {
2787127Speter 	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
2797127Speter 		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
2807127Speter 	done();
2814508Speter     }
2824508Speter 	/*
2834508Speter 	 *	now link cycles to true cycleheads,
2844508Speter 	 *	number them, accumulate the data for the cycle
2854508Speter 	 */
2864508Speter     cycle = 0;
2874508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2884508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
2894508Speter 	    continue;
2904508Speter 	}
2914508Speter 	cycle += 1;
2927127Speter 	cyclenlp = &cyclenl[cycle];
2934508Speter 	cyclenlp -> cycleno = cycle;
2944508Speter 	cyclenlp -> cyclehead = cyclenlp;
2954508Speter 	cyclenlp -> cnext = nlp;
2964508Speter #	ifdef DEBUG
2974508Speter 	    if ( debug & CYCLEDEBUG ) {
2984508Speter 		printf( "[cyclelink] " );
2994508Speter 		printname( nlp );
3004508Speter 		printf( " is the head of cycle %d\n" , cycle );
3014508Speter 	    }
3024508Speter #	endif DEBUG
303*7172Speter 	for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
304*7172Speter 	    memberp -> cycleno = cycle;
305*7172Speter 	    memberp -> cyclehead = cyclenlp;
306*7172Speter 	}
307*7172Speter     }
308*7172Speter }
309*7172Speter 
310*7172Speter cycletime()
311*7172Speter {
312*7172Speter     int			cycle;
313*7172Speter     nltype		*cyclenlp;
314*7172Speter     nltype		*parentp;
315*7172Speter     nltype		*childp;
316*7172Speter     arctype		*arcp;
317*7172Speter     long		ncall;
318*7172Speter     double		time;
319*7172Speter     long		callsamong;
320*7172Speter 
321*7172Speter     for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
322*7172Speter 	cyclenlp = &cyclenl[ cycle ];
3234508Speter 	    /*
3244508Speter 	     *	n-squaredly (in the size of the cycle)
3254508Speter 	     *	find all the call within the cycle
3264508Speter 	     *	(including self-recursive calls)
3274508Speter 	     *	and remove them, thus making the cycle into
3284508Speter 	     *	`node' with calls only from the outside.
3294508Speter 	     *	note: that this doesn't deal with
3304508Speter 	     *	self-recursive calls outside cycles (sigh).
3314508Speter 	     */
3324508Speter 	callsamong = 0;
333*7172Speter 	for ( parentp = cyclenlp->cnext; parentp; parentp = parentp->cnext ) {
334*7172Speter 	    for ( childp = cyclenlp->cnext; childp; childp = childp -> cnext ) {
3354508Speter 		if ( parentp == childp ) {
3364508Speter 		    continue;
3374508Speter 		}
3384508Speter 		arcp = arclookup( parentp , childp );
3394508Speter 		if ( arcp != 0 ) {
3404508Speter 		    callsamong += arcp -> arc_count;
3414508Speter #		    ifdef DEBUG
3424508Speter 			if ( debug & CYCLEDEBUG ) {
3434508Speter 			    printf("[cyclelink] %s calls sibling %s %d times\n",
3444508Speter 				parentp -> name , childp -> name ,
3454508Speter 				arcp -> arc_count );
3464508Speter 			}
3474508Speter #		    endif DEBUG
3484508Speter 		}
3494508Speter 	    }
3504508Speter 	}
3514508Speter 	    /*
3524508Speter 	     *	collect calls and time around the cycle,
3534508Speter 	     *	and save it in the cycle header.
3544508Speter 	     */
3554508Speter 	ncall = -callsamong;
3564508Speter 	time = 0.0;
357*7172Speter 	for ( parentp = cyclenlp->cnext; parentp; parentp = parentp->cnext ) {
3584508Speter 	    ncall += parentp -> ncall;
3594508Speter 	    time += parentp -> time;
3604508Speter 	}
3614508Speter #	ifdef DEBUG
3624508Speter 	    if ( debug & CYCLEDEBUG ) {
3634508Speter 		printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" ,
3644508Speter 			cycle , time , ncall , callsamong );
3654508Speter 	    }
3664508Speter #	endif DEBUG
3674508Speter 	cyclenlp -> ncall = ncall;
3684508Speter 	cyclenlp -> selfcalls = callsamong;
3694508Speter 	cyclenlp -> time = time;
3704508Speter 	cyclenlp -> childtime = 0.0;
3714508Speter     }
3724508Speter }
373*7172Speter 
374*7172Speter     /*
375*7172Speter      *	in one top to bottom pass over the topologically sorted namelist
376*7172Speter      *	set the print flags and sum up the time that will be shown in the
377*7172Speter      *	graph profile.
378*7172Speter      */
379*7172Speter doflags()
380*7172Speter {
381*7172Speter     int		index;
382*7172Speter     nltype	*childp;
383*7172Speter     nltype	*oldhead;
384*7172Speter 
385*7172Speter     oldhead = 0;
386*7172Speter     for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
387*7172Speter 	childp = topsortnlp[ index ];
388*7172Speter 	    /*
389*7172Speter 	     *	if we haven't done this function or cycle,
390*7172Speter 	     *	calculate its printflag.
391*7172Speter 	     *	this way, we are linear in the number of arcs
392*7172Speter 	     *	since we do all members of a cycle (and the cycle itself)
393*7172Speter 	     *	as we hit the first member of the cycle.
394*7172Speter 	     */
395*7172Speter 	if ( childp -> cyclehead != oldhead ) {
396*7172Speter 	    oldhead = childp -> cyclehead;
397*7172Speter 	    parentprint( childp );
398*7172Speter 	}
399*7172Speter 	if ( ! childp -> printflag ) {
400*7172Speter 		/*
401*7172Speter 		 *	-f function says print the sucker
402*7172Speter 		 *	-e function says don't print it (leave it non-printing)
403*7172Speter 		 *	no -f's at all says print everything
404*7172Speter 		 */
405*7172Speter 	    if ( fflag && onflist( childp -> name ) ) {
406*7172Speter 		childp -> printflag = TRUE;
407*7172Speter 		printtime += childp -> time + childp -> childtime;
408*7172Speter 		continue;
409*7172Speter 	    }
410*7172Speter 	    if ( eflag && onelist( childp -> name ) ) {
411*7172Speter 		continue;
412*7172Speter 	    }
413*7172Speter 	    if ( !fflag ) {
414*7172Speter 		childp -> printflag = TRUE;
415*7172Speter 		printtime += childp -> time + childp -> childtime;
416*7172Speter 		continue;
417*7172Speter 	    }
418*7172Speter 	    continue;
419*7172Speter 	}
420*7172Speter 	    /*
421*7172Speter 	     *	this function has printing parents:
422*7172Speter 	     *	maybe someone wants to shut it up.
423*7172Speter 	     */
424*7172Speter 	if ( eflag && onelist( childp -> name ) ) {
425*7172Speter 	    childp -> printflag = FALSE;
426*7172Speter 	    continue;
427*7172Speter 	}
428*7172Speter     }
429*7172Speter }
430*7172Speter 
431*7172Speter     /*
432*7172Speter      *	check if any parent of this child
433*7172Speter      *	(or outside parents of this cycle)
434*7172Speter      *	have their print flags on and set the
435*7172Speter      *	print flag of the child (cycle) appropriately.
436*7172Speter      */
437*7172Speter parentprint( childp )
438*7172Speter     nltype	*childp;
439*7172Speter {
440*7172Speter     nltype	*headp;
441*7172Speter     nltype	*memp;
442*7172Speter     arctype	*arcp;
443*7172Speter 
444*7172Speter     headp = childp -> cyclehead;
445*7172Speter     if ( childp == headp ) {
446*7172Speter 	    /*
447*7172Speter 	     *	just a regular child, check its parents
448*7172Speter 	     */
449*7172Speter 	for ( arcp = childp->parents ; arcp ; arcp = arcp->arc_parentlist ) {
450*7172Speter 	    if ( arcp -> arc_parentp -> printflag ) {
451*7172Speter 		childp -> printflag = TRUE;
452*7172Speter 		break;
453*7172Speter 	    }
454*7172Speter 	}
455*7172Speter 	return;
456*7172Speter     }
457*7172Speter 	/*
458*7172Speter 	 *	its a member of a cycle, look at all parents from
459*7172Speter 	 *	outside the cycle
460*7172Speter 	 */
461*7172Speter     for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
462*7172Speter 	for ( arcp = memp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
463*7172Speter 	    if ( arcp -> arc_parentp -> cyclehead == headp ) {
464*7172Speter 		continue;
465*7172Speter 	    }
466*7172Speter 	    if ( arcp -> arc_parentp -> printflag ) {
467*7172Speter 		goto set;
468*7172Speter 	    }
469*7172Speter 	}
470*7172Speter     }
471*7172Speter     return;
472*7172Speter 	/*
473*7172Speter 	 *	the cycle has a printing parent:  set the cycle
474*7172Speter 	 */
475*7172Speter set:
476*7172Speter     for ( memp = headp ; memp ; memp = memp -> cnext ) {
477*7172Speter 	memp -> printflag = TRUE;
478*7172Speter     }
479*7172Speter }
480