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