14508Speter #ifndef lint 2*7172Speter static char *sccsid = "@(#)arcs.c 1.7 (Berkeley) 06/14/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 54*7172Speter /* 55*7172Speter * the code below topologically sorts the graph (collapsing cycles), 56*7172Speter * and propagates time bottom up and flags top down. 57*7172Speter */ 58*7172Speter 59*7172Speter /* 60*7172Speter * the topologically sorted name list pointers 61*7172Speter */ 62*7172Speter nltype **topsortnlp; 63*7172Speter 644508Speter topcmp( npp1 , npp2 ) 654508Speter nltype **npp1; 664508Speter nltype **npp2; 674508Speter { 684508Speter return (*npp1) -> toporder - (*npp2) -> toporder; 694508Speter } 704508Speter 714508Speter doarcs() 724508Speter { 734508Speter nltype *parentp; 744508Speter arctype *arcp; 754508Speter long index; 764508Speter 774508Speter /* 784508Speter * initialize various things: 794508Speter * zero out child times. 804508Speter * count self-recursive calls. 814508Speter * indicate that nothing is on cycles. 824508Speter */ 834508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 844508Speter parentp -> childtime = 0.0; 854508Speter arcp = arclookup( parentp , parentp ); 864508Speter if ( arcp != 0 ) { 874508Speter parentp -> ncall -= arcp -> arc_count; 884508Speter parentp -> selfcalls = arcp -> arc_count; 894508Speter } else { 904508Speter parentp -> selfcalls = 0; 914508Speter } 92*7172Speter parentp -> printflag = FALSE; 934508Speter parentp -> toporder = 0; 944508Speter parentp -> cycleno = 0; 954508Speter parentp -> cyclehead = parentp; 964508Speter parentp -> cnext = 0; 97*7172Speter if ( cflag ) { 98*7172Speter findcalls( parentp , parentp -> value , (parentp+1) -> value ); 99*7172Speter } 1004508Speter } 1014508Speter /* 102*7172Speter * time for functions which print is accumulated here. 103*7172Speter */ 104*7172Speter printtime = 0.0; 105*7172Speter /* 1064508Speter * topologically order things 1074508Speter * from each of the roots of the call graph 1084508Speter */ 1094508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 1104508Speter if ( parentp -> parents == 0 ) { 1114508Speter dfn( parentp ); 1124508Speter } 1134508Speter } 1144508Speter /* 1154508Speter * link together nodes on the same cycle 1164508Speter */ 1174508Speter cyclelink(); 1184508Speter /* 1194508Speter * Sort the symbol table in reverse topological order 1204508Speter */ 1214508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1224508Speter if ( topsortnlp == (nltype **) 0 ) { 1234508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1244508Speter } 1254508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1264508Speter topsortnlp[ index ] = &nl[ index ]; 1274508Speter } 1284508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1294508Speter # ifdef DEBUG 1304508Speter if ( debug & DFNDEBUG ) { 1314508Speter printf( "[doarcs] topological sort listing\n" ); 1324508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1334508Speter printf( "[doarcs] " ); 1344508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1354508Speter printname( topsortnlp[ index ] ); 1364508Speter printf( "\n" ); 1374508Speter } 1384508Speter } 1394508Speter # endif DEBUG 1404508Speter /* 1414508Speter * starting from the topological bottom, 142*7172Speter * propogate children times up to parents. 1434508Speter */ 144*7172Speter dotime(); 145*7172Speter /* 146*7172Speter * starting from the topological top, 147*7172Speter * propagate print flags to children. 148*7172Speter */ 149*7172Speter doflags(); 150*7172Speter printgprof(); 151*7172Speter } 152*7172Speter 153*7172Speter dotime() 154*7172Speter { 155*7172Speter int index; 156*7172Speter 157*7172Speter cycletime(); 1584508Speter for ( index = 0 ; index < nname ; index += 1 ) { 159*7172Speter timepropagate( topsortnlp[ index ] ); 1607127Speter } 1617127Speter } 1627127Speter 163*7172Speter timepropagate( parentp ) 1647127Speter nltype *parentp; 1657127Speter { 1667127Speter arctype *arcp; 1677127Speter nltype *childp; 1687127Speter double share; 1697127Speter 1707127Speter /* 1717127Speter * gather time from children of this parent. 1727127Speter */ 173*7172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 1747127Speter childp = arcp -> arc_childp; 1757127Speter # ifdef DEBUG 1767127Speter if ( debug & ARCDEBUG ) { 1777127Speter printf( "[propagate] " ); 1787127Speter printname( parentp ); 1797127Speter printf( " calls " ); 1807127Speter printname( childp ); 1817127Speter printf( " %d (%d) times\n" , 1827127Speter arcp -> arc_count , childp -> ncall ); 1837127Speter } 1847127Speter # endif DEBUG 1857127Speter if ( arcp -> arc_count == 0 ) { 1867127Speter continue; 1877127Speter } 1887127Speter if ( childp -> ncall == 0 ) { 1897127Speter continue; 1907127Speter } 1917127Speter if ( childp == parentp ) { 1927127Speter continue; 1937127Speter } 1947127Speter if ( childp -> cyclehead != childp ) { 1957127Speter if ( parentp -> cycleno == childp -> cycleno ) { 1967127Speter continue; 1977127Speter } 1984508Speter # ifdef DEBUG 1994508Speter if ( debug & ARCDEBUG ) { 2007127Speter printf( "[propagate]\t it's a call into cycle %d\n" , 2017127Speter childp -> cycleno ); 2024508Speter } 2034508Speter # endif DEBUG 2047127Speter if ( parentp -> toporder <= childp -> toporder ) { 2057127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2064508Speter } 2077127Speter childp = childp -> cyclehead; 2087127Speter } else { 2097127Speter if ( parentp -> toporder <= childp -> toporder ) { 2107127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2114508Speter continue; 2124508Speter } 2137127Speter } 2147127Speter /* 2157127Speter * distribute time for this arc 2167127Speter */ 2177127Speter arcp -> arc_time = childp -> time * 2187127Speter ( ( (double) arcp -> arc_count ) / 2197127Speter ( (double) childp -> ncall ) ); 2207127Speter arcp -> arc_childtime = childp -> childtime * 2217127Speter ( ( (double) arcp -> arc_count ) / 2227127Speter ( (double) childp -> ncall ) ); 2237127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2247127Speter # ifdef DEBUG 2257127Speter if ( debug & ARCDEBUG ) { 2267127Speter printf( "[propagate]\t " ); 2277127Speter printname( childp ); 2287127Speter printf( " time %8.2f + childtime %8.2f\n" , 2297127Speter childp -> time , childp -> childtime ); 2307127Speter printf( "[propagate]\t this is %d arcs of the %d calls\n", 2317127Speter arcp -> arc_count , childp -> ncall ); 2327127Speter printf( "[propagate]\t so this gives %8.2f+%8.2f to %s\n" , 2337127Speter arcp -> arc_time , arcp -> arc_childtime , 2347127Speter parentp -> name ); 2354508Speter } 2367127Speter # endif DEBUG 2377127Speter parentp -> childtime += share; 2387127Speter /* 2397127Speter * add this share to the cycle header, if any 2407127Speter */ 2417127Speter if ( parentp -> cyclehead != parentp ) { 2424508Speter # ifdef DEBUG 2434508Speter if ( debug & ARCDEBUG ) { 2447127Speter printf( "[propagate]\t and to cycle %d\n" , 2457127Speter parentp -> cycleno ); 2464508Speter } 2474508Speter # endif DEBUG 2487127Speter parentp -> cyclehead -> childtime += share; 2494508Speter } 2504508Speter } 2514508Speter } 2524508Speter 2534508Speter cyclelink() 2544508Speter { 2554508Speter register nltype *nlp; 2564508Speter register nltype *cyclenlp; 2574508Speter int cycle; 258*7172Speter nltype *memberp; 2594508Speter 2604508Speter /* 2614508Speter * Count the number of cycles, and initialze the cycle lists 2624508Speter */ 2637127Speter ncycle = 0; 2644508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2654508Speter /* 2664508Speter * this is how you find unattached cycles 2674508Speter */ 2684508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2697127Speter ncycle += 1; 2704508Speter } 2714508Speter } 2727127Speter /* 2737127Speter * cyclenl is indexed by cycle number: 2747127Speter * i.e. it is origin 1, not origin 0. 2757127Speter */ 2767127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 2777127Speter if ( cyclenl == 0 ) { 2787127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 2797127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 2807127Speter done(); 2814508Speter } 2824508Speter /* 2834508Speter * now link cycles to true cycleheads, 2844508Speter * number them, accumulate the data for the cycle 2854508Speter */ 2864508Speter cycle = 0; 2874508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2884508Speter if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) { 2894508Speter continue; 2904508Speter } 2914508Speter cycle += 1; 2927127Speter cyclenlp = &cyclenl[cycle]; 2934508Speter cyclenlp -> cycleno = cycle; 2944508Speter cyclenlp -> cyclehead = cyclenlp; 2954508Speter cyclenlp -> cnext = nlp; 2964508Speter # ifdef DEBUG 2974508Speter if ( debug & CYCLEDEBUG ) { 2984508Speter printf( "[cyclelink] " ); 2994508Speter printname( nlp ); 3004508Speter printf( " is the head of cycle %d\n" , cycle ); 3014508Speter } 3024508Speter # endif DEBUG 303*7172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 304*7172Speter memberp -> cycleno = cycle; 305*7172Speter memberp -> cyclehead = cyclenlp; 306*7172Speter } 307*7172Speter } 308*7172Speter } 309*7172Speter 310*7172Speter cycletime() 311*7172Speter { 312*7172Speter int cycle; 313*7172Speter nltype *cyclenlp; 314*7172Speter nltype *parentp; 315*7172Speter nltype *childp; 316*7172Speter arctype *arcp; 317*7172Speter long ncall; 318*7172Speter double time; 319*7172Speter long callsamong; 320*7172Speter 321*7172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 322*7172Speter cyclenlp = &cyclenl[ cycle ]; 3234508Speter /* 3244508Speter * n-squaredly (in the size of the cycle) 3254508Speter * find all the call within the cycle 3264508Speter * (including self-recursive calls) 3274508Speter * and remove them, thus making the cycle into 3284508Speter * `node' with calls only from the outside. 3294508Speter * note: that this doesn't deal with 3304508Speter * self-recursive calls outside cycles (sigh). 3314508Speter */ 3324508Speter callsamong = 0; 333*7172Speter for ( parentp = cyclenlp->cnext; parentp; parentp = parentp->cnext ) { 334*7172Speter for ( childp = cyclenlp->cnext; childp; childp = childp -> cnext ) { 3354508Speter if ( parentp == childp ) { 3364508Speter continue; 3374508Speter } 3384508Speter arcp = arclookup( parentp , childp ); 3394508Speter if ( arcp != 0 ) { 3404508Speter callsamong += arcp -> arc_count; 3414508Speter # ifdef DEBUG 3424508Speter if ( debug & CYCLEDEBUG ) { 3434508Speter printf("[cyclelink] %s calls sibling %s %d times\n", 3444508Speter parentp -> name , childp -> name , 3454508Speter arcp -> arc_count ); 3464508Speter } 3474508Speter # endif DEBUG 3484508Speter } 3494508Speter } 3504508Speter } 3514508Speter /* 3524508Speter * collect calls and time around the cycle, 3534508Speter * and save it in the cycle header. 3544508Speter */ 3554508Speter ncall = -callsamong; 3564508Speter time = 0.0; 357*7172Speter for ( parentp = cyclenlp->cnext; parentp; parentp = parentp->cnext ) { 3584508Speter ncall += parentp -> ncall; 3594508Speter time += parentp -> time; 3604508Speter } 3614508Speter # ifdef DEBUG 3624508Speter if ( debug & CYCLEDEBUG ) { 3634508Speter printf( "[cyclelink] cycle %d %f ticks in %d (%d) calls\n" , 3644508Speter cycle , time , ncall , callsamong ); 3654508Speter } 3664508Speter # endif DEBUG 3674508Speter cyclenlp -> ncall = ncall; 3684508Speter cyclenlp -> selfcalls = callsamong; 3694508Speter cyclenlp -> time = time; 3704508Speter cyclenlp -> childtime = 0.0; 3714508Speter } 3724508Speter } 373*7172Speter 374*7172Speter /* 375*7172Speter * in one top to bottom pass over the topologically sorted namelist 376*7172Speter * set the print flags and sum up the time that will be shown in the 377*7172Speter * graph profile. 378*7172Speter */ 379*7172Speter doflags() 380*7172Speter { 381*7172Speter int index; 382*7172Speter nltype *childp; 383*7172Speter nltype *oldhead; 384*7172Speter 385*7172Speter oldhead = 0; 386*7172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 387*7172Speter childp = topsortnlp[ index ]; 388*7172Speter /* 389*7172Speter * if we haven't done this function or cycle, 390*7172Speter * calculate its printflag. 391*7172Speter * this way, we are linear in the number of arcs 392*7172Speter * since we do all members of a cycle (and the cycle itself) 393*7172Speter * as we hit the first member of the cycle. 394*7172Speter */ 395*7172Speter if ( childp -> cyclehead != oldhead ) { 396*7172Speter oldhead = childp -> cyclehead; 397*7172Speter parentprint( childp ); 398*7172Speter } 399*7172Speter if ( ! childp -> printflag ) { 400*7172Speter /* 401*7172Speter * -f function says print the sucker 402*7172Speter * -e function says don't print it (leave it non-printing) 403*7172Speter * no -f's at all says print everything 404*7172Speter */ 405*7172Speter if ( fflag && onflist( childp -> name ) ) { 406*7172Speter childp -> printflag = TRUE; 407*7172Speter printtime += childp -> time + childp -> childtime; 408*7172Speter continue; 409*7172Speter } 410*7172Speter if ( eflag && onelist( childp -> name ) ) { 411*7172Speter continue; 412*7172Speter } 413*7172Speter if ( !fflag ) { 414*7172Speter childp -> printflag = TRUE; 415*7172Speter printtime += childp -> time + childp -> childtime; 416*7172Speter continue; 417*7172Speter } 418*7172Speter continue; 419*7172Speter } 420*7172Speter /* 421*7172Speter * this function has printing parents: 422*7172Speter * maybe someone wants to shut it up. 423*7172Speter */ 424*7172Speter if ( eflag && onelist( childp -> name ) ) { 425*7172Speter childp -> printflag = FALSE; 426*7172Speter continue; 427*7172Speter } 428*7172Speter } 429*7172Speter } 430*7172Speter 431*7172Speter /* 432*7172Speter * check if any parent of this child 433*7172Speter * (or outside parents of this cycle) 434*7172Speter * have their print flags on and set the 435*7172Speter * print flag of the child (cycle) appropriately. 436*7172Speter */ 437*7172Speter parentprint( childp ) 438*7172Speter nltype *childp; 439*7172Speter { 440*7172Speter nltype *headp; 441*7172Speter nltype *memp; 442*7172Speter arctype *arcp; 443*7172Speter 444*7172Speter headp = childp -> cyclehead; 445*7172Speter if ( childp == headp ) { 446*7172Speter /* 447*7172Speter * just a regular child, check its parents 448*7172Speter */ 449*7172Speter for ( arcp = childp->parents ; arcp ; arcp = arcp->arc_parentlist ) { 450*7172Speter if ( arcp -> arc_parentp -> printflag ) { 451*7172Speter childp -> printflag = TRUE; 452*7172Speter break; 453*7172Speter } 454*7172Speter } 455*7172Speter return; 456*7172Speter } 457*7172Speter /* 458*7172Speter * its a member of a cycle, look at all parents from 459*7172Speter * outside the cycle 460*7172Speter */ 461*7172Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 462*7172Speter for ( arcp = memp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) { 463*7172Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 464*7172Speter continue; 465*7172Speter } 466*7172Speter if ( arcp -> arc_parentp -> printflag ) { 467*7172Speter goto set; 468*7172Speter } 469*7172Speter } 470*7172Speter } 471*7172Speter return; 472*7172Speter /* 473*7172Speter * the cycle has a printing parent: set the cycle 474*7172Speter */ 475*7172Speter set: 476*7172Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 477*7172Speter memp -> printflag = TRUE; 478*7172Speter } 479*7172Speter } 480