xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 7127)
14508Speter #ifndef lint
2*7127Speter     static	char *sccsid = "@(#)arcs.c	1.6 (Berkeley) 06/08/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 
544508Speter topcmp( npp1 , npp2 )
554508Speter     nltype	**npp1;
564508Speter     nltype	**npp2;
574508Speter {
584508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
594508Speter }
604508Speter 
614508Speter 
624508Speter doarcs()
634508Speter {
644508Speter     nltype	*parentp;
654508Speter     arctype	*arcp;
664508Speter     nltype	**topsortnlp;
674508Speter     long	index;
684508Speter 
694508Speter 	/*
704508Speter 	 *	initialize various things:
714508Speter 	 *	    zero out child times.
724508Speter 	 *	    count self-recursive calls.
734508Speter 	 *	    indicate that nothing is on cycles.
744508Speter 	 */
754508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
764508Speter 	parentp -> childtime = 0.0;
774508Speter 	arcp = arclookup( parentp , parentp );
784508Speter 	if ( arcp != 0 ) {
794508Speter 	    parentp -> ncall -= arcp -> arc_count;
804508Speter 	    parentp -> selfcalls = arcp -> arc_count;
814508Speter 	} else {
824508Speter 	    parentp -> selfcalls = 0;
834508Speter 	}
844721Speter 	if ( cflag ) {
854721Speter 	    findcalls( parentp , parentp -> value , (parentp+1) -> value );
864721Speter 	}
874508Speter 	parentp -> toporder = 0;
884508Speter 	parentp -> cycleno = 0;
894508Speter 	parentp -> cyclehead = parentp;
904508Speter 	parentp -> cnext = 0;
914508Speter     }
924508Speter 	/*
934508Speter 	 *	topologically order things
944508Speter 	 *	from each of the roots of the call graph
954508Speter 	 */
964508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
974508Speter 	if ( parentp -> parents == 0 ) {
984508Speter 	    dfn( parentp );
994508Speter 	}
1004508Speter     }
1014508Speter 	/*
1024508Speter 	 *	link together nodes on the same cycle
1034508Speter 	 */
1044508Speter     cyclelink();
1054508Speter 	/*
1064508Speter 	 *	Sort the symbol table in reverse topological order
1074508Speter 	 */
1084508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1094508Speter     if ( topsortnlp == (nltype **) 0 ) {
1104508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1114508Speter     }
1124508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1134508Speter 	topsortnlp[ index ] = &nl[ index ];
1144508Speter     }
1154508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1164508Speter #   ifdef DEBUG
1174508Speter 	if ( debug & DFNDEBUG ) {
1184508Speter 	    printf( "[doarcs] topological sort listing\n" );
1194508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1204508Speter 		printf( "[doarcs] " );
1214508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1224508Speter 		printname( topsortnlp[ index ] );
1234508Speter 		printf( "\n" );
1244508Speter 	    }
1254508Speter 	}
1264508Speter #   endif DEBUG
1274508Speter 	/*
1284508Speter 	 *	starting from the topological bottom,
1294508Speter 	 *	propogate children times
1304508Speter 	 */
1314508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
132*7127Speter 	propagate( topsortnlp[ index ] );
133*7127Speter     }
134*7127Speter     printgprof();
135*7127Speter }
136*7127Speter 
137*7127Speter propagate( parentp )
138*7127Speter     nltype	*parentp;
139*7127Speter {
140*7127Speter     arctype	*arcp;
141*7127Speter     nltype	*childp;
142*7127Speter     double	share;
143*7127Speter 
144*7127Speter 	/*
145*7127Speter 	 *	gather time from children of this parent.
146*7127Speter 	 */
147*7127Speter     for ( arcp = parentp->children ; arcp ; arcp = arcp->arc_childlist ) {
148*7127Speter 	childp = arcp -> arc_childp;
149*7127Speter #	ifdef DEBUG
150*7127Speter 	    if ( debug & ARCDEBUG ) {
151*7127Speter 		printf( "[propagate] " );
152*7127Speter 		printname( parentp );
153*7127Speter 		printf( " calls " );
154*7127Speter 		printname( childp );
155*7127Speter 		printf( " %d (%d) times\n" ,
156*7127Speter 			arcp -> arc_count , childp -> ncall );
157*7127Speter 	    }
158*7127Speter #	endif DEBUG
159*7127Speter 	if ( arcp -> arc_count == 0 ) {
160*7127Speter 	    continue;
161*7127Speter 	}
162*7127Speter 	if ( childp -> ncall == 0 ) {
163*7127Speter 	    continue;
164*7127Speter 	}
165*7127Speter 	if ( childp == parentp ) {
166*7127Speter 	    continue;
167*7127Speter 	}
168*7127Speter 	if ( childp -> cyclehead != childp ) {
169*7127Speter 	    if ( parentp -> cycleno == childp -> cycleno ) {
170*7127Speter 		continue;
171*7127Speter 	    }
1724508Speter #	    ifdef DEBUG
1734508Speter 		if ( debug & ARCDEBUG ) {
174*7127Speter 		    printf( "[propagate]\t it's a call into cycle %d\n" ,
175*7127Speter 			    childp -> cycleno );
1764508Speter 		}
1774508Speter #	    endif DEBUG
178*7127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
179*7127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
1804508Speter 	    }
181*7127Speter 	    childp = childp -> cyclehead;
182*7127Speter 	} else {
183*7127Speter 	    if ( parentp -> toporder <= childp -> toporder ) {
184*7127Speter 		fprintf( stderr , "[propagate] toporder botches\n" );
1854508Speter 		continue;
1864508Speter 	    }
187*7127Speter 	}
188*7127Speter 	    /*
189*7127Speter 	     *	distribute time for this arc
190*7127Speter 	     */
191*7127Speter 	arcp -> arc_time = childp -> time *
192*7127Speter 			    ( ( (double) arcp -> arc_count ) /
193*7127Speter 			    ( (double) childp -> ncall ) );
194*7127Speter 	arcp -> arc_childtime = childp -> childtime *
195*7127Speter 			    ( ( (double) arcp -> arc_count ) /
196*7127Speter 			    ( (double) childp -> ncall ) );
197*7127Speter 	share = arcp -> arc_time + arcp -> arc_childtime;
198*7127Speter #	ifdef DEBUG
199*7127Speter 	    if ( debug & ARCDEBUG ) {
200*7127Speter 		printf( "[propagate]\t " );
201*7127Speter 		printname( childp );
202*7127Speter 		printf( " time %8.2f + childtime %8.2f\n" ,
203*7127Speter 		    childp -> time , childp -> childtime );
204*7127Speter 		printf( "[propagate]\t this is %d arcs of the %d calls\n",
205*7127Speter 		    arcp -> arc_count , childp -> ncall );
206*7127Speter 		printf( "[propagate]\t so this gives %8.2f+%8.2f to %s\n" ,
207*7127Speter 		    arcp -> arc_time , arcp -> arc_childtime ,
208*7127Speter 		    parentp -> name );
2094508Speter 	    }
210*7127Speter #	endif DEBUG
211*7127Speter 	parentp -> childtime += share;
212*7127Speter 	    /*
213*7127Speter 	     *	add this share to the cycle header, if any
214*7127Speter 	     */
215*7127Speter 	if ( parentp -> cyclehead != parentp ) {
2164508Speter #	    ifdef DEBUG
2174508Speter 		if ( debug & ARCDEBUG ) {
218*7127Speter 		    printf( "[propagate]\t and to cycle %d\n" ,
219*7127Speter 			    parentp -> cycleno );
2204508Speter 		}
2214508Speter #	    endif DEBUG
222*7127Speter 	    parentp -> cyclehead -> childtime += share;
2234508Speter 	}
2244508Speter     }
2254508Speter }
2264508Speter 
2274508Speter cyclelink()
2284508Speter {
2294508Speter     register nltype	*nlp;
2304508Speter     register nltype	*parentp;
2314508Speter     register nltype	*childp;
2324508Speter     register nltype	*cyclenlp;
2334508Speter     int			cycle;
2344508Speter     arctype		*arcp;
2354508Speter     long		ncall;
2364508Speter     double		time;
2374508Speter     long		callsamong;
2384508Speter 
2394508Speter 	/*
2404508Speter 	 *	Count the number of cycles, and initialze the cycle lists
2414508Speter 	 */
242*7127Speter     ncycle = 0;
2434508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2444508Speter 	    /*
2454508Speter 	     *	this is how you find unattached cycles
2464508Speter 	     */
2474508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
248*7127Speter 	    ncycle += 1;
2494508Speter 	}
2504508Speter     }
251*7127Speter 	/*
252*7127Speter 	 *	cyclenl is indexed by cycle number:
253*7127Speter 	 *	i.e. it is origin 1, not origin 0.
254*7127Speter 	 */
255*7127Speter     cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
256*7127Speter     if ( cyclenl == 0 ) {
257*7127Speter 	fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
258*7127Speter 		whoami , ( ncycle + 1 ) * sizeof( nltype ) );
259*7127Speter 	done();
2604508Speter     }
2614508Speter 	/*
2624508Speter 	 *	now link cycles to true cycleheads,
2634508Speter 	 *	number them, accumulate the data for the cycle
2644508Speter 	 */
2654508Speter     cycle = 0;
2664508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2674508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
2684508Speter 	    continue;
2694508Speter 	}
2704508Speter 	cycle += 1;
271*7127Speter 	cyclenlp = &cyclenl[cycle];
2724508Speter 	cyclenlp -> cycleno = cycle;
2734508Speter 	cyclenlp -> cyclehead = cyclenlp;
2744508Speter 	cyclenlp -> cnext = nlp;
2754508Speter #	ifdef DEBUG
2764508Speter 	    if ( debug & CYCLEDEBUG ) {
2774508Speter 		printf( "[cyclelink] " );
2784508Speter 		printname( nlp );
2794508Speter 		printf( " is the head of cycle %d\n" , cycle );
2804508Speter 	    }
2814508Speter #	endif DEBUG
2824508Speter 	    /*
2834508Speter 	     *	n-squaredly (in the size of the cycle)
2844508Speter 	     *	find all the call within the cycle
2854508Speter 	     *	(including self-recursive calls)
2864508Speter 	     *	and remove them, thus making the cycle into
2874508Speter 	     *	`node' with calls only from the outside.
2884508Speter 	     *	note: that this doesn't deal with
2894508Speter 	     *	self-recursive calls outside cycles (sigh).
2904508Speter 	     */
2914508Speter 	callsamong = 0;
2924508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
2934508Speter 	    parentp -> cycleno = cycle;
2944508Speter 	    parentp -> cyclehead = cyclenlp;
2954508Speter 	    for ( childp = nlp ; childp ; childp = childp -> cnext ) {
2964508Speter 		if ( parentp == childp ) {
2974508Speter 		    continue;
2984508Speter 		}
2994508Speter 		arcp = arclookup( parentp , childp );
3004508Speter 		if ( arcp != 0 ) {
3014508Speter 		    callsamong += arcp -> arc_count;
3024508Speter #		    ifdef DEBUG
3034508Speter 			if ( debug & CYCLEDEBUG ) {
3044508Speter 			    printf("[cyclelink] %s calls sibling %s %d times\n",
3054508Speter 				parentp -> name , childp -> name ,
3064508Speter 				arcp -> arc_count );
3074508Speter 			}
3084508Speter #		    endif DEBUG
3094508Speter 		}
3104508Speter 	    }
3114508Speter 	}
3124508Speter 	    /*
3134508Speter 	     *	collect calls and time around the cycle,
3144508Speter 	     *	and save it in the cycle header.
3154508Speter 	     */
3164508Speter 	ncall = -callsamong;
3174508Speter 	time = 0.0;
3184508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
3194508Speter 	    ncall += parentp -> ncall;
3204508Speter 	    time += parentp -> time;
3214508Speter 	}
3224508Speter #	ifdef DEBUG
3234508Speter 	    if ( debug & CYCLEDEBUG ) {
3244508Speter 		printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" ,
3254508Speter 			cycle , time , ncall , callsamong );
3264508Speter 	    }
3274508Speter #	endif DEBUG
3284508Speter 	cyclenlp -> ncall = ncall;
3294508Speter 	cyclenlp -> selfcalls = callsamong;
3304508Speter 	cyclenlp -> time = time;
3314508Speter 	cyclenlp -> childtime = 0.0;
3324508Speter     }
3334508Speter }
334