xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 4508)
1*4508Speter #ifndef lint
2*4508Speter     static	char *sccsid = "@(#)arcs.c	1.1 (Berkeley) 10/15/81";
3*4508Speter #endif lint
4*4508Speter 
5*4508Speter #include "dprof.h"
6*4508Speter 
7*4508Speter topcmp( npp1 , npp2 )
8*4508Speter     nltype	**npp1;
9*4508Speter     nltype	**npp2;
10*4508Speter {
11*4508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
12*4508Speter }
13*4508Speter 
14*4508Speter     /*
15*4508Speter      *	sort by decreasing total time (time+childtime)
16*4508Speter      *	if times are equal, but one is a cycle header,
17*4508Speter      *	say that's first (e.g. less)
18*4508Speter      */
19*4508Speter int
20*4508Speter totalcmp( npp1 , npp2 )
21*4508Speter     nltype	**npp1;
22*4508Speter     nltype	**npp2;
23*4508Speter {
24*4508Speter     register nltype	*np1 = *npp1;
25*4508Speter     register nltype	*np2 = *npp2;
26*4508Speter     double		diff;
27*4508Speter 
28*4508Speter     diff =    ( np1 -> time + np1 -> childtime )
29*4508Speter 	    - ( np2 -> time + np2 -> childtime );
30*4508Speter     if ( diff < 0.0 )
31*4508Speter 	    return 1;
32*4508Speter     if ( diff > 0.0 )
33*4508Speter 	    return -1;
34*4508Speter     if ( np1 -> name == 0 && np1 -> cycleno != 0 )
35*4508Speter 	return -1;
36*4508Speter     if ( np2 -> name == 0 && np1 -> cycleno != 0 )
37*4508Speter 	return 1;
38*4508Speter     return 0;
39*4508Speter }
40*4508Speter 
41*4508Speter doarcs()
42*4508Speter {
43*4508Speter     nltype	*parentp;
44*4508Speter     arctype	*arcp;
45*4508Speter     nltype	**topsortnlp;
46*4508Speter     long	index;
47*4508Speter     nltype	*childp;
48*4508Speter     double	share;
49*4508Speter 
50*4508Speter 	/*
51*4508Speter 	 *	initialize various things:
52*4508Speter 	 *	    zero out child times.
53*4508Speter 	 *	    count self-recursive calls.
54*4508Speter 	 *	    indicate that nothing is on cycles.
55*4508Speter 	 */
56*4508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
57*4508Speter 	parentp -> childtime = 0.0;
58*4508Speter 	arcp = arclookup( parentp , parentp );
59*4508Speter 	if ( arcp != 0 ) {
60*4508Speter 	    parentp -> ncall -= arcp -> arc_count;
61*4508Speter 	    parentp -> selfcalls = arcp -> arc_count;
62*4508Speter 	} else {
63*4508Speter 	    parentp -> selfcalls = 0;
64*4508Speter 	}
65*4508Speter 	parentp -> toporder = 0;
66*4508Speter 	parentp -> cycleno = 0;
67*4508Speter 	parentp -> cyclehead = parentp;
68*4508Speter 	parentp -> cnext = 0;
69*4508Speter     }
70*4508Speter 	/*
71*4508Speter 	 *	topologically order things
72*4508Speter 	 *	from each of the roots of the call graph
73*4508Speter 	 */
74*4508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
75*4508Speter 	if ( parentp -> parents == 0 ) {
76*4508Speter 	    dfn( parentp );
77*4508Speter 	}
78*4508Speter     }
79*4508Speter 	/*
80*4508Speter 	 *	link together nodes on the same cycle
81*4508Speter 	 */
82*4508Speter     cyclelink();
83*4508Speter 	/*
84*4508Speter 	 *	Sort the symbol table in reverse topological order
85*4508Speter 	 */
86*4508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
87*4508Speter     if ( topsortnlp == (nltype **) 0 ) {
88*4508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
89*4508Speter     }
90*4508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
91*4508Speter 	topsortnlp[ index ] = &nl[ index ];
92*4508Speter     }
93*4508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
94*4508Speter #   ifdef DEBUG
95*4508Speter 	if ( debug & DFNDEBUG ) {
96*4508Speter 	    printf( "[doarcs] topological sort listing\n" );
97*4508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
98*4508Speter 		printf( "[doarcs] " );
99*4508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
100*4508Speter 		printname( topsortnlp[ index ] );
101*4508Speter 		printf( "\n" );
102*4508Speter 	    }
103*4508Speter 	}
104*4508Speter #   endif DEBUG
105*4508Speter 	/*
106*4508Speter 	 *	starting from the topological bottom,
107*4508Speter 	 *	propogate children times
108*4508Speter 	 */
109*4508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
110*4508Speter 	parentp = topsortnlp[ index ];
111*4508Speter 	for ( arcp = parentp->children ; arcp ; arcp = arcp->arc_childlist ) {
112*4508Speter 	    childp = arcp -> arc_childp;
113*4508Speter #	    ifdef DEBUG
114*4508Speter 		if ( debug & ARCDEBUG ) {
115*4508Speter 			printf( "[doarcs] " );
116*4508Speter 			printname( parentp );
117*4508Speter 			printf( " calls " );
118*4508Speter 			printname( childp );
119*4508Speter 			printf( " %d (%d) times\n" ,
120*4508Speter 				arcp -> arc_count , childp -> ncall );
121*4508Speter 		}
122*4508Speter #	    endif DEBUG
123*4508Speter 	    if ( arcp -> arc_count == 0 ) {
124*4508Speter 		continue;
125*4508Speter 	    }
126*4508Speter 	    if ( childp -> ncall == 0 ) {
127*4508Speter 		continue;
128*4508Speter 	    }
129*4508Speter 	    if ( childp == parentp ) {
130*4508Speter 		continue;
131*4508Speter 	    }
132*4508Speter 	    if ( childp -> cyclehead != childp ) {
133*4508Speter 		if ( parentp -> cycleno == childp -> cycleno ) {
134*4508Speter 		    continue;
135*4508Speter 		}
136*4508Speter #		ifdef DEBUG
137*4508Speter 		    if ( debug & ARCDEBUG ) {
138*4508Speter 			printf( "[doarcs]\t it's a call into cycle %d\n" ,
139*4508Speter 				childp -> cycleno );
140*4508Speter 		    }
141*4508Speter #		endif DEBUG
142*4508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
143*4508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
144*4508Speter 		}
145*4508Speter 		childp = childp -> cyclehead;
146*4508Speter 	    } else {
147*4508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
148*4508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
149*4508Speter 		    continue;
150*4508Speter 		}
151*4508Speter 	    }
152*4508Speter 		/*
153*4508Speter 		 *	distribute time for this arc
154*4508Speter 		 */
155*4508Speter 	    arcp -> arc_time = childp -> time *
156*4508Speter 				( ( (double) arcp -> arc_count ) /
157*4508Speter 				( (double) childp -> ncall ) );
158*4508Speter 	    arcp -> arc_childtime = childp -> childtime *
159*4508Speter 				( ( (double) arcp -> arc_count ) /
160*4508Speter 				( (double) childp -> ncall ) );
161*4508Speter 	    share = arcp -> arc_time + arcp -> arc_childtime;
162*4508Speter #	    ifdef DEBUG
163*4508Speter 		if ( debug & ARCDEBUG ) {
164*4508Speter 		    printf( "[doarcs]\t " );
165*4508Speter 		    printname( childp );
166*4508Speter 		    printf( " time %8.2f + childtime %8.2f\n" ,
167*4508Speter 			childp -> time , childp -> childtime );
168*4508Speter 		    printf( "[doarcs]\t this is %d arcs of the %d calls\n",
169*4508Speter 			arcp -> arc_count , childp -> ncall );
170*4508Speter 		    printf( "[doarcs]\t so this gives %8.2f+%8.2f to %s\n" ,
171*4508Speter 			arcp -> arc_time , arcp -> arc_childtime ,
172*4508Speter 			parentp -> name );
173*4508Speter 		}
174*4508Speter #	    endif DEBUG
175*4508Speter 	    parentp -> childtime += share;
176*4508Speter 		/*
177*4508Speter 		 *	add this share to the cycle header, if any
178*4508Speter 		 */
179*4508Speter 	    if ( parentp -> cyclehead != parentp ) {
180*4508Speter #		ifdef DEBUG
181*4508Speter 		    if ( debug & ARCDEBUG ) {
182*4508Speter 			printf( "[doarcs]\t and to cycle %d\n" ,
183*4508Speter 				parentp -> cycleno );
184*4508Speter 		    }
185*4508Speter #		endif DEBUG
186*4508Speter 		parentp -> cyclehead -> childtime += share;
187*4508Speter 	    }
188*4508Speter 	}
189*4508Speter     }
190*4508Speter     printdprof();
191*4508Speter }
192*4508Speter 
193*4508Speter cyclelink()
194*4508Speter {
195*4508Speter     register nltype	*nlp;
196*4508Speter     register nltype	*parentp;
197*4508Speter     register nltype	*childp;
198*4508Speter     register nltype	*cyclenlp;
199*4508Speter     int			cycle;
200*4508Speter     arctype		*arcp;
201*4508Speter     long		ncall;
202*4508Speter     double		time;
203*4508Speter     long		callsamong;
204*4508Speter 
205*4508Speter 	/*
206*4508Speter 	 *	Count the number of cycles, and initialze the cycle lists
207*4508Speter 	 */
208*4508Speter     cyclemax = 0;
209*4508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
210*4508Speter 	    /*
211*4508Speter 	     *	this is how you find unattached cycles
212*4508Speter 	     */
213*4508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
214*4508Speter 	    cyclemax += 1;
215*4508Speter 	}
216*4508Speter     }
217*4508Speter     if ( cyclemax > ncycles ) {
218*4508Speter 	fprintf( stderr , "prof: %d cycles in %d names exceeds %f%%\n" ,
219*4508Speter 		cyclemax , nname , CYCLEFRACTION * 100.0 );
220*4508Speter 	exit( 1 );
221*4508Speter     }
222*4508Speter 	/*
223*4508Speter 	 *	now link cycles to true cycleheads,
224*4508Speter 	 *	number them, accumulate the data for the cycle
225*4508Speter 	 */
226*4508Speter     cycle = 0;
227*4508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
228*4508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
229*4508Speter 	    continue;
230*4508Speter 	}
231*4508Speter 	cycle += 1;
232*4508Speter 	cyclenlp = &nl[nname+cycle];
233*4508Speter 	cyclenlp -> cycleno = cycle;
234*4508Speter 	cyclenlp -> cyclehead = cyclenlp;
235*4508Speter 	cyclenlp -> cnext = nlp;
236*4508Speter #	ifdef DEBUG
237*4508Speter 	    if ( debug & CYCLEDEBUG ) {
238*4508Speter 		printf( "[cyclelink] " );
239*4508Speter 		printname( nlp );
240*4508Speter 		printf( " is the head of cycle %d\n" , cycle );
241*4508Speter 	    }
242*4508Speter #	endif DEBUG
243*4508Speter 	    /*
244*4508Speter 	     *	n-squaredly (in the size of the cycle)
245*4508Speter 	     *	find all the call within the cycle
246*4508Speter 	     *	(including self-recursive calls)
247*4508Speter 	     *	and remove them, thus making the cycle into
248*4508Speter 	     *	`node' with calls only from the outside.
249*4508Speter 	     *	note: that this doesn't deal with
250*4508Speter 	     *	self-recursive calls outside cycles (sigh).
251*4508Speter 	     */
252*4508Speter 	callsamong = 0;
253*4508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
254*4508Speter 	    parentp -> cycleno = cycle;
255*4508Speter 	    parentp -> cyclehead = cyclenlp;
256*4508Speter 	    for ( childp = nlp ; childp ; childp = childp -> cnext ) {
257*4508Speter 		if ( parentp == childp ) {
258*4508Speter 		    continue;
259*4508Speter 		}
260*4508Speter 		arcp = arclookup( parentp , childp );
261*4508Speter 		if ( arcp != 0 ) {
262*4508Speter 		    callsamong += arcp -> arc_count;
263*4508Speter #		    ifdef DEBUG
264*4508Speter 			if ( debug & CYCLEDEBUG ) {
265*4508Speter 			    printf("[cyclelink] %s calls sibling %s %d times\n",
266*4508Speter 				parentp -> name , childp -> name ,
267*4508Speter 				arcp -> arc_count );
268*4508Speter 			}
269*4508Speter #		    endif DEBUG
270*4508Speter 		}
271*4508Speter 	    }
272*4508Speter 	}
273*4508Speter 	    /*
274*4508Speter 	     *	collect calls and time around the cycle,
275*4508Speter 	     *	and save it in the cycle header.
276*4508Speter 	     */
277*4508Speter 	ncall = -callsamong;
278*4508Speter 	time = 0.0;
279*4508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
280*4508Speter 	    ncall += parentp -> ncall;
281*4508Speter 	    time += parentp -> time;
282*4508Speter 	}
283*4508Speter #	ifdef DEBUG
284*4508Speter 	    if ( debug & CYCLEDEBUG ) {
285*4508Speter 		printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" ,
286*4508Speter 			cycle , time , ncall , callsamong );
287*4508Speter 	    }
288*4508Speter #	endif DEBUG
289*4508Speter 	cyclenlp -> ncall = ncall;
290*4508Speter 	cyclenlp -> selfcalls = callsamong;
291*4508Speter 	cyclenlp -> time = time;
292*4508Speter 	cyclenlp -> childtime = 0.0;
293*4508Speter     }
294*4508Speter }
295