xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 4561)
14508Speter #ifndef lint
2*4561Speter     static	char *sccsid = "@(#)arcs.c	1.2 (Berkeley) 10/20/81";
34508Speter #endif lint
44508Speter 
5*4561Speter #include "gprof.h"
64508Speter 
74508Speter topcmp( npp1 , npp2 )
84508Speter     nltype	**npp1;
94508Speter     nltype	**npp2;
104508Speter {
114508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
124508Speter }
134508Speter 
144508Speter     /*
154508Speter      *	sort by decreasing total time (time+childtime)
164508Speter      *	if times are equal, but one is a cycle header,
174508Speter      *	say that's first (e.g. less)
184508Speter      */
194508Speter int
204508Speter totalcmp( npp1 , npp2 )
214508Speter     nltype	**npp1;
224508Speter     nltype	**npp2;
234508Speter {
244508Speter     register nltype	*np1 = *npp1;
254508Speter     register nltype	*np2 = *npp2;
264508Speter     double		diff;
274508Speter 
284508Speter     diff =    ( np1 -> time + np1 -> childtime )
294508Speter 	    - ( np2 -> time + np2 -> childtime );
304508Speter     if ( diff < 0.0 )
314508Speter 	    return 1;
324508Speter     if ( diff > 0.0 )
334508Speter 	    return -1;
344508Speter     if ( np1 -> name == 0 && np1 -> cycleno != 0 )
354508Speter 	return -1;
364508Speter     if ( np2 -> name == 0 && np1 -> cycleno != 0 )
374508Speter 	return 1;
384508Speter     return 0;
394508Speter }
404508Speter 
414508Speter doarcs()
424508Speter {
434508Speter     nltype	*parentp;
444508Speter     arctype	*arcp;
454508Speter     nltype	**topsortnlp;
464508Speter     long	index;
474508Speter     nltype	*childp;
484508Speter     double	share;
494508Speter 
504508Speter 	/*
514508Speter 	 *	initialize various things:
524508Speter 	 *	    zero out child times.
534508Speter 	 *	    count self-recursive calls.
544508Speter 	 *	    indicate that nothing is on cycles.
554508Speter 	 */
564508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
574508Speter 	parentp -> childtime = 0.0;
584508Speter 	arcp = arclookup( parentp , parentp );
594508Speter 	if ( arcp != 0 ) {
604508Speter 	    parentp -> ncall -= arcp -> arc_count;
614508Speter 	    parentp -> selfcalls = arcp -> arc_count;
624508Speter 	} else {
634508Speter 	    parentp -> selfcalls = 0;
644508Speter 	}
654508Speter 	parentp -> toporder = 0;
664508Speter 	parentp -> cycleno = 0;
674508Speter 	parentp -> cyclehead = parentp;
684508Speter 	parentp -> cnext = 0;
694508Speter     }
704508Speter 	/*
714508Speter 	 *	topologically order things
724508Speter 	 *	from each of the roots of the call graph
734508Speter 	 */
744508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
754508Speter 	if ( parentp -> parents == 0 ) {
764508Speter 	    dfn( parentp );
774508Speter 	}
784508Speter     }
794508Speter 	/*
804508Speter 	 *	link together nodes on the same cycle
814508Speter 	 */
824508Speter     cyclelink();
834508Speter 	/*
844508Speter 	 *	Sort the symbol table in reverse topological order
854508Speter 	 */
864508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
874508Speter     if ( topsortnlp == (nltype **) 0 ) {
884508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
894508Speter     }
904508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
914508Speter 	topsortnlp[ index ] = &nl[ index ];
924508Speter     }
934508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
944508Speter #   ifdef DEBUG
954508Speter 	if ( debug & DFNDEBUG ) {
964508Speter 	    printf( "[doarcs] topological sort listing\n" );
974508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
984508Speter 		printf( "[doarcs] " );
994508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1004508Speter 		printname( topsortnlp[ index ] );
1014508Speter 		printf( "\n" );
1024508Speter 	    }
1034508Speter 	}
1044508Speter #   endif DEBUG
1054508Speter 	/*
1064508Speter 	 *	starting from the topological bottom,
1074508Speter 	 *	propogate children times
1084508Speter 	 */
1094508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1104508Speter 	parentp = topsortnlp[ index ];
1114508Speter 	for ( arcp = parentp->children ; arcp ; arcp = arcp->arc_childlist ) {
1124508Speter 	    childp = arcp -> arc_childp;
1134508Speter #	    ifdef DEBUG
1144508Speter 		if ( debug & ARCDEBUG ) {
1154508Speter 			printf( "[doarcs] " );
1164508Speter 			printname( parentp );
1174508Speter 			printf( " calls " );
1184508Speter 			printname( childp );
1194508Speter 			printf( " %d (%d) times\n" ,
1204508Speter 				arcp -> arc_count , childp -> ncall );
1214508Speter 		}
1224508Speter #	    endif DEBUG
1234508Speter 	    if ( arcp -> arc_count == 0 ) {
1244508Speter 		continue;
1254508Speter 	    }
1264508Speter 	    if ( childp -> ncall == 0 ) {
1274508Speter 		continue;
1284508Speter 	    }
1294508Speter 	    if ( childp == parentp ) {
1304508Speter 		continue;
1314508Speter 	    }
1324508Speter 	    if ( childp -> cyclehead != childp ) {
1334508Speter 		if ( parentp -> cycleno == childp -> cycleno ) {
1344508Speter 		    continue;
1354508Speter 		}
1364508Speter #		ifdef DEBUG
1374508Speter 		    if ( debug & ARCDEBUG ) {
1384508Speter 			printf( "[doarcs]\t it's a call into cycle %d\n" ,
1394508Speter 				childp -> cycleno );
1404508Speter 		    }
1414508Speter #		endif DEBUG
1424508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
1434508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
1444508Speter 		}
1454508Speter 		childp = childp -> cyclehead;
1464508Speter 	    } else {
1474508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
1484508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
1494508Speter 		    continue;
1504508Speter 		}
1514508Speter 	    }
1524508Speter 		/*
1534508Speter 		 *	distribute time for this arc
1544508Speter 		 */
1554508Speter 	    arcp -> arc_time = childp -> time *
1564508Speter 				( ( (double) arcp -> arc_count ) /
1574508Speter 				( (double) childp -> ncall ) );
1584508Speter 	    arcp -> arc_childtime = childp -> childtime *
1594508Speter 				( ( (double) arcp -> arc_count ) /
1604508Speter 				( (double) childp -> ncall ) );
1614508Speter 	    share = arcp -> arc_time + arcp -> arc_childtime;
1624508Speter #	    ifdef DEBUG
1634508Speter 		if ( debug & ARCDEBUG ) {
1644508Speter 		    printf( "[doarcs]\t " );
1654508Speter 		    printname( childp );
1664508Speter 		    printf( " time %8.2f + childtime %8.2f\n" ,
1674508Speter 			childp -> time , childp -> childtime );
1684508Speter 		    printf( "[doarcs]\t this is %d arcs of the %d calls\n",
1694508Speter 			arcp -> arc_count , childp -> ncall );
1704508Speter 		    printf( "[doarcs]\t so this gives %8.2f+%8.2f to %s\n" ,
1714508Speter 			arcp -> arc_time , arcp -> arc_childtime ,
1724508Speter 			parentp -> name );
1734508Speter 		}
1744508Speter #	    endif DEBUG
1754508Speter 	    parentp -> childtime += share;
1764508Speter 		/*
1774508Speter 		 *	add this share to the cycle header, if any
1784508Speter 		 */
1794508Speter 	    if ( parentp -> cyclehead != parentp ) {
1804508Speter #		ifdef DEBUG
1814508Speter 		    if ( debug & ARCDEBUG ) {
1824508Speter 			printf( "[doarcs]\t and to cycle %d\n" ,
1834508Speter 				parentp -> cycleno );
1844508Speter 		    }
1854508Speter #		endif DEBUG
1864508Speter 		parentp -> cyclehead -> childtime += share;
1874508Speter 	    }
1884508Speter 	}
1894508Speter     }
190*4561Speter     printgprof();
1914508Speter }
1924508Speter 
1934508Speter cyclelink()
1944508Speter {
1954508Speter     register nltype	*nlp;
1964508Speter     register nltype	*parentp;
1974508Speter     register nltype	*childp;
1984508Speter     register nltype	*cyclenlp;
1994508Speter     int			cycle;
2004508Speter     arctype		*arcp;
2014508Speter     long		ncall;
2024508Speter     double		time;
2034508Speter     long		callsamong;
2044508Speter 
2054508Speter 	/*
2064508Speter 	 *	Count the number of cycles, and initialze the cycle lists
2074508Speter 	 */
2084508Speter     cyclemax = 0;
2094508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2104508Speter 	    /*
2114508Speter 	     *	this is how you find unattached cycles
2124508Speter 	     */
2134508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
2144508Speter 	    cyclemax += 1;
2154508Speter 	}
2164508Speter     }
2174508Speter     if ( cyclemax > ncycles ) {
2184508Speter 	fprintf( stderr , "prof: %d cycles in %d names exceeds %f%%\n" ,
2194508Speter 		cyclemax , nname , CYCLEFRACTION * 100.0 );
2204508Speter 	exit( 1 );
2214508Speter     }
2224508Speter 	/*
2234508Speter 	 *	now link cycles to true cycleheads,
2244508Speter 	 *	number them, accumulate the data for the cycle
2254508Speter 	 */
2264508Speter     cycle = 0;
2274508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2284508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
2294508Speter 	    continue;
2304508Speter 	}
2314508Speter 	cycle += 1;
2324508Speter 	cyclenlp = &nl[nname+cycle];
2334508Speter 	cyclenlp -> cycleno = cycle;
2344508Speter 	cyclenlp -> cyclehead = cyclenlp;
2354508Speter 	cyclenlp -> cnext = nlp;
2364508Speter #	ifdef DEBUG
2374508Speter 	    if ( debug & CYCLEDEBUG ) {
2384508Speter 		printf( "[cyclelink] " );
2394508Speter 		printname( nlp );
2404508Speter 		printf( " is the head of cycle %d\n" , cycle );
2414508Speter 	    }
2424508Speter #	endif DEBUG
2434508Speter 	    /*
2444508Speter 	     *	n-squaredly (in the size of the cycle)
2454508Speter 	     *	find all the call within the cycle
2464508Speter 	     *	(including self-recursive calls)
2474508Speter 	     *	and remove them, thus making the cycle into
2484508Speter 	     *	`node' with calls only from the outside.
2494508Speter 	     *	note: that this doesn't deal with
2504508Speter 	     *	self-recursive calls outside cycles (sigh).
2514508Speter 	     */
2524508Speter 	callsamong = 0;
2534508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
2544508Speter 	    parentp -> cycleno = cycle;
2554508Speter 	    parentp -> cyclehead = cyclenlp;
2564508Speter 	    for ( childp = nlp ; childp ; childp = childp -> cnext ) {
2574508Speter 		if ( parentp == childp ) {
2584508Speter 		    continue;
2594508Speter 		}
2604508Speter 		arcp = arclookup( parentp , childp );
2614508Speter 		if ( arcp != 0 ) {
2624508Speter 		    callsamong += arcp -> arc_count;
2634508Speter #		    ifdef DEBUG
2644508Speter 			if ( debug & CYCLEDEBUG ) {
2654508Speter 			    printf("[cyclelink] %s calls sibling %s %d times\n",
2664508Speter 				parentp -> name , childp -> name ,
2674508Speter 				arcp -> arc_count );
2684508Speter 			}
2694508Speter #		    endif DEBUG
2704508Speter 		}
2714508Speter 	    }
2724508Speter 	}
2734508Speter 	    /*
2744508Speter 	     *	collect calls and time around the cycle,
2754508Speter 	     *	and save it in the cycle header.
2764508Speter 	     */
2774508Speter 	ncall = -callsamong;
2784508Speter 	time = 0.0;
2794508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
2804508Speter 	    ncall += parentp -> ncall;
2814508Speter 	    time += parentp -> time;
2824508Speter 	}
2834508Speter #	ifdef DEBUG
2844508Speter 	    if ( debug & CYCLEDEBUG ) {
2854508Speter 		printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" ,
2864508Speter 			cycle , time , ncall , callsamong );
2874508Speter 	    }
2884508Speter #	endif DEBUG
2894508Speter 	cyclenlp -> ncall = ncall;
2904508Speter 	cyclenlp -> selfcalls = callsamong;
2914508Speter 	cyclenlp -> time = time;
2924508Speter 	cyclenlp -> childtime = 0.0;
2934508Speter     }
2944508Speter }
295