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