xref: /csrg-svn/usr.bin/gprof/arcs.c (revision 4721)
14508Speter #ifndef lint
2*4721Speter     static	char *sccsid = "@(#)arcs.c	1.3 (Berkeley) 11/02/81";
34508Speter #endif lint
44508Speter 
54561Speter #include "gprof.h"
64508Speter 
7*4721Speter     /*
8*4721Speter      *	add (or just increment) an arc
9*4721Speter      */
10*4721Speter addarc( parentp , childp , count )
11*4721Speter     nltype	*parentp;
12*4721Speter     nltype	*childp;
13*4721Speter     long	count;
14*4721Speter {
15*4721Speter     arctype		*malloc();
16*4721Speter     arctype		*arcp;
17*4721Speter 
18*4721Speter #   ifdef DEBUG
19*4721Speter 	if ( debug & TALLYDEBUG ) {
20*4721Speter 	    printf( "[addarc] %d arcs from %s to %s\n" ,
21*4721Speter 		    count , parentp -> name , childp -> name );
22*4721Speter 	}
23*4721Speter #   endif DEBUG
24*4721Speter     arcp = arclookup( parentp , childp );
25*4721Speter     if ( arcp != 0 ) {
26*4721Speter 	    /*
27*4721Speter 	     *	a hit:  just increment the count.
28*4721Speter 	     */
29*4721Speter #	ifdef DEBUG
30*4721Speter 	    if ( debug & TALLYDEBUG ) {
31*4721Speter 		printf( "[tally] hit %d += %d\n" ,
32*4721Speter 			arcp -> arc_count , count );
33*4721Speter 	    }
34*4721Speter #	endif DEBUG
35*4721Speter 	arcp -> arc_count += count;
36*4721Speter 	return;
37*4721Speter     }
38*4721Speter     arcp = malloc( sizeof *arcp );
39*4721Speter     arcp -> arc_parentp = parentp;
40*4721Speter     arcp -> arc_childp = childp;
41*4721Speter     arcp -> arc_count = count;
42*4721Speter 	/*
43*4721Speter 	 *	prepend this child to the children of this parent
44*4721Speter 	 */
45*4721Speter     arcp -> arc_childlist = parentp -> children;
46*4721Speter     parentp -> children = arcp;
47*4721Speter 	/*
48*4721Speter 	 *	prepend this parent to the parents of this child
49*4721Speter 	 */
50*4721Speter     arcp -> arc_parentlist = childp -> parents;
51*4721Speter     childp -> parents = arcp;
52*4721Speter }
53*4721Speter 
544508Speter topcmp( npp1 , npp2 )
554508Speter     nltype	**npp1;
564508Speter     nltype	**npp2;
574508Speter {
584508Speter     return (*npp1) -> toporder - (*npp2) -> toporder;
594508Speter }
604508Speter 
614508Speter     /*
624508Speter      *	sort by decreasing total time (time+childtime)
634508Speter      *	if times are equal, but one is a cycle header,
644508Speter      *	say that's first (e.g. less)
654508Speter      */
664508Speter int
674508Speter totalcmp( npp1 , npp2 )
684508Speter     nltype	**npp1;
694508Speter     nltype	**npp2;
704508Speter {
714508Speter     register nltype	*np1 = *npp1;
724508Speter     register nltype	*np2 = *npp2;
734508Speter     double		diff;
744508Speter 
754508Speter     diff =    ( np1 -> time + np1 -> childtime )
764508Speter 	    - ( np2 -> time + np2 -> childtime );
774508Speter     if ( diff < 0.0 )
784508Speter 	    return 1;
794508Speter     if ( diff > 0.0 )
804508Speter 	    return -1;
814508Speter     if ( np1 -> name == 0 && np1 -> cycleno != 0 )
824508Speter 	return -1;
834508Speter     if ( np2 -> name == 0 && np1 -> cycleno != 0 )
844508Speter 	return 1;
854508Speter     return 0;
864508Speter }
874508Speter 
884508Speter doarcs()
894508Speter {
904508Speter     nltype	*parentp;
914508Speter     arctype	*arcp;
924508Speter     nltype	**topsortnlp;
934508Speter     long	index;
944508Speter     nltype	*childp;
954508Speter     double	share;
964508Speter 
974508Speter 	/*
984508Speter 	 *	initialize various things:
994508Speter 	 *	    zero out child times.
1004508Speter 	 *	    count self-recursive calls.
1014508Speter 	 *	    indicate that nothing is on cycles.
1024508Speter 	 */
1034508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
1044508Speter 	parentp -> childtime = 0.0;
1054508Speter 	arcp = arclookup( parentp , parentp );
1064508Speter 	if ( arcp != 0 ) {
1074508Speter 	    parentp -> ncall -= arcp -> arc_count;
1084508Speter 	    parentp -> selfcalls = arcp -> arc_count;
1094508Speter 	} else {
1104508Speter 	    parentp -> selfcalls = 0;
1114508Speter 	}
112*4721Speter 	if ( cflag ) {
113*4721Speter 	    findcalls( parentp , parentp -> value , (parentp+1) -> value );
114*4721Speter 	}
1154508Speter 	parentp -> toporder = 0;
1164508Speter 	parentp -> cycleno = 0;
1174508Speter 	parentp -> cyclehead = parentp;
1184508Speter 	parentp -> cnext = 0;
1194508Speter     }
1204508Speter 	/*
1214508Speter 	 *	topologically order things
1224508Speter 	 *	from each of the roots of the call graph
1234508Speter 	 */
1244508Speter     for ( parentp = nl ; parentp < npe ; parentp++ ) {
1254508Speter 	if ( parentp -> parents == 0 ) {
1264508Speter 	    dfn( parentp );
1274508Speter 	}
1284508Speter     }
1294508Speter 	/*
1304508Speter 	 *	link together nodes on the same cycle
1314508Speter 	 */
1324508Speter     cyclelink();
1334508Speter 	/*
1344508Speter 	 *	Sort the symbol table in reverse topological order
1354508Speter 	 */
1364508Speter     topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
1374508Speter     if ( topsortnlp == (nltype **) 0 ) {
1384508Speter 	fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
1394508Speter     }
1404508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1414508Speter 	topsortnlp[ index ] = &nl[ index ];
1424508Speter     }
1434508Speter     qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
1444508Speter #   ifdef DEBUG
1454508Speter 	if ( debug & DFNDEBUG ) {
1464508Speter 	    printf( "[doarcs] topological sort listing\n" );
1474508Speter 	    for ( index = 0 ; index < nname ; index += 1 ) {
1484508Speter 		printf( "[doarcs] " );
1494508Speter 		printf( "%d:" , topsortnlp[ index ] -> toporder );
1504508Speter 		printname( topsortnlp[ index ] );
1514508Speter 		printf( "\n" );
1524508Speter 	    }
1534508Speter 	}
1544508Speter #   endif DEBUG
1554508Speter 	/*
1564508Speter 	 *	starting from the topological bottom,
1574508Speter 	 *	propogate children times
1584508Speter 	 */
1594508Speter     for ( index = 0 ; index < nname ; index += 1 ) {
1604508Speter 	parentp = topsortnlp[ index ];
1614508Speter 	for ( arcp = parentp->children ; arcp ; arcp = arcp->arc_childlist ) {
1624508Speter 	    childp = arcp -> arc_childp;
1634508Speter #	    ifdef DEBUG
1644508Speter 		if ( debug & ARCDEBUG ) {
1654508Speter 			printf( "[doarcs] " );
1664508Speter 			printname( parentp );
1674508Speter 			printf( " calls " );
1684508Speter 			printname( childp );
1694508Speter 			printf( " %d (%d) times\n" ,
1704508Speter 				arcp -> arc_count , childp -> ncall );
1714508Speter 		}
1724508Speter #	    endif DEBUG
1734508Speter 	    if ( arcp -> arc_count == 0 ) {
1744508Speter 		continue;
1754508Speter 	    }
1764508Speter 	    if ( childp -> ncall == 0 ) {
1774508Speter 		continue;
1784508Speter 	    }
1794508Speter 	    if ( childp == parentp ) {
1804508Speter 		continue;
1814508Speter 	    }
1824508Speter 	    if ( childp -> cyclehead != childp ) {
1834508Speter 		if ( parentp -> cycleno == childp -> cycleno ) {
1844508Speter 		    continue;
1854508Speter 		}
1864508Speter #		ifdef DEBUG
1874508Speter 		    if ( debug & ARCDEBUG ) {
1884508Speter 			printf( "[doarcs]\t it's a call into cycle %d\n" ,
1894508Speter 				childp -> cycleno );
1904508Speter 		    }
1914508Speter #		endif DEBUG
1924508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
1934508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
1944508Speter 		}
1954508Speter 		childp = childp -> cyclehead;
1964508Speter 	    } else {
1974508Speter 		if ( parentp -> toporder <= childp -> toporder ) {
1984508Speter 		    fprintf( stderr , "[doarcs] toporder botches\n" );
1994508Speter 		    continue;
2004508Speter 		}
2014508Speter 	    }
2024508Speter 		/*
2034508Speter 		 *	distribute time for this arc
2044508Speter 		 */
2054508Speter 	    arcp -> arc_time = childp -> time *
2064508Speter 				( ( (double) arcp -> arc_count ) /
2074508Speter 				( (double) childp -> ncall ) );
2084508Speter 	    arcp -> arc_childtime = childp -> childtime *
2094508Speter 				( ( (double) arcp -> arc_count ) /
2104508Speter 				( (double) childp -> ncall ) );
2114508Speter 	    share = arcp -> arc_time + arcp -> arc_childtime;
2124508Speter #	    ifdef DEBUG
2134508Speter 		if ( debug & ARCDEBUG ) {
2144508Speter 		    printf( "[doarcs]\t " );
2154508Speter 		    printname( childp );
2164508Speter 		    printf( " time %8.2f + childtime %8.2f\n" ,
2174508Speter 			childp -> time , childp -> childtime );
2184508Speter 		    printf( "[doarcs]\t this is %d arcs of the %d calls\n",
2194508Speter 			arcp -> arc_count , childp -> ncall );
2204508Speter 		    printf( "[doarcs]\t so this gives %8.2f+%8.2f to %s\n" ,
2214508Speter 			arcp -> arc_time , arcp -> arc_childtime ,
2224508Speter 			parentp -> name );
2234508Speter 		}
2244508Speter #	    endif DEBUG
2254508Speter 	    parentp -> childtime += share;
2264508Speter 		/*
2274508Speter 		 *	add this share to the cycle header, if any
2284508Speter 		 */
2294508Speter 	    if ( parentp -> cyclehead != parentp ) {
2304508Speter #		ifdef DEBUG
2314508Speter 		    if ( debug & ARCDEBUG ) {
2324508Speter 			printf( "[doarcs]\t and to cycle %d\n" ,
2334508Speter 				parentp -> cycleno );
2344508Speter 		    }
2354508Speter #		endif DEBUG
2364508Speter 		parentp -> cyclehead -> childtime += share;
2374508Speter 	    }
2384508Speter 	}
2394508Speter     }
2404561Speter     printgprof();
2414508Speter }
2424508Speter 
2434508Speter cyclelink()
2444508Speter {
2454508Speter     register nltype	*nlp;
2464508Speter     register nltype	*parentp;
2474508Speter     register nltype	*childp;
2484508Speter     register nltype	*cyclenlp;
2494508Speter     int			cycle;
2504508Speter     arctype		*arcp;
2514508Speter     long		ncall;
2524508Speter     double		time;
2534508Speter     long		callsamong;
2544508Speter 
2554508Speter 	/*
2564508Speter 	 *	Count the number of cycles, and initialze the cycle lists
2574508Speter 	 */
2584508Speter     cyclemax = 0;
2594508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2604508Speter 	    /*
2614508Speter 	     *	this is how you find unattached cycles
2624508Speter 	     */
2634508Speter 	if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
2644508Speter 	    cyclemax += 1;
2654508Speter 	}
2664508Speter     }
2674508Speter     if ( cyclemax > ncycles ) {
2684508Speter 	fprintf( stderr , "prof: %d cycles in %d names exceeds %f%%\n" ,
2694508Speter 		cyclemax , nname , CYCLEFRACTION * 100.0 );
2704508Speter 	exit( 1 );
2714508Speter     }
2724508Speter 	/*
2734508Speter 	 *	now link cycles to true cycleheads,
2744508Speter 	 *	number them, accumulate the data for the cycle
2754508Speter 	 */
2764508Speter     cycle = 0;
2774508Speter     for ( nlp = nl ; nlp < npe ; nlp++ ) {
2784508Speter 	if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) {
2794508Speter 	    continue;
2804508Speter 	}
2814508Speter 	cycle += 1;
2824508Speter 	cyclenlp = &nl[nname+cycle];
2834508Speter 	cyclenlp -> cycleno = cycle;
2844508Speter 	cyclenlp -> cyclehead = cyclenlp;
2854508Speter 	cyclenlp -> cnext = nlp;
2864508Speter #	ifdef DEBUG
2874508Speter 	    if ( debug & CYCLEDEBUG ) {
2884508Speter 		printf( "[cyclelink] " );
2894508Speter 		printname( nlp );
2904508Speter 		printf( " is the head of cycle %d\n" , cycle );
2914508Speter 	    }
2924508Speter #	endif DEBUG
2934508Speter 	    /*
2944508Speter 	     *	n-squaredly (in the size of the cycle)
2954508Speter 	     *	find all the call within the cycle
2964508Speter 	     *	(including self-recursive calls)
2974508Speter 	     *	and remove them, thus making the cycle into
2984508Speter 	     *	`node' with calls only from the outside.
2994508Speter 	     *	note: that this doesn't deal with
3004508Speter 	     *	self-recursive calls outside cycles (sigh).
3014508Speter 	     */
3024508Speter 	callsamong = 0;
3034508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
3044508Speter 	    parentp -> cycleno = cycle;
3054508Speter 	    parentp -> cyclehead = cyclenlp;
3064508Speter 	    for ( childp = nlp ; childp ; childp = childp -> cnext ) {
3074508Speter 		if ( parentp == childp ) {
3084508Speter 		    continue;
3094508Speter 		}
3104508Speter 		arcp = arclookup( parentp , childp );
3114508Speter 		if ( arcp != 0 ) {
3124508Speter 		    callsamong += arcp -> arc_count;
3134508Speter #		    ifdef DEBUG
3144508Speter 			if ( debug & CYCLEDEBUG ) {
3154508Speter 			    printf("[cyclelink] %s calls sibling %s %d times\n",
3164508Speter 				parentp -> name , childp -> name ,
3174508Speter 				arcp -> arc_count );
3184508Speter 			}
3194508Speter #		    endif DEBUG
3204508Speter 		}
3214508Speter 	    }
3224508Speter 	}
3234508Speter 	    /*
3244508Speter 	     *	collect calls and time around the cycle,
3254508Speter 	     *	and save it in the cycle header.
3264508Speter 	     */
3274508Speter 	ncall = -callsamong;
3284508Speter 	time = 0.0;
3294508Speter 	for ( parentp = nlp ; parentp ; parentp = parentp -> cnext ) {
3304508Speter 	    ncall += parentp -> ncall;
3314508Speter 	    time += parentp -> time;
3324508Speter 	}
3334508Speter #	ifdef DEBUG
3344508Speter 	    if ( debug & CYCLEDEBUG ) {
3354508Speter 		printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" ,
3364508Speter 			cycle , time , ncall , callsamong );
3374508Speter 	    }
3384508Speter #	endif DEBUG
3394508Speter 	cyclenlp -> ncall = ncall;
3404508Speter 	cyclenlp -> selfcalls = callsamong;
3414508Speter 	cyclenlp -> time = time;
3424508Speter 	cyclenlp -> childtime = 0.0;
3434508Speter     }
3444508Speter }
345