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