14508Speter #ifndef lint 2*16850Smckusick static char *sccsid = "@(#)arcs.c 1.15 (Berkeley) 08/07/84"; 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 547172Speter /* 557172Speter * the code below topologically sorts the graph (collapsing cycles), 567172Speter * and propagates time bottom up and flags top down. 577172Speter */ 587172Speter 597172Speter /* 607172Speter * the topologically sorted name list pointers 617172Speter */ 627172Speter nltype **topsortnlp; 637172Speter 644508Speter topcmp( npp1 , npp2 ) 654508Speter nltype **npp1; 664508Speter nltype **npp2; 674508Speter { 684508Speter return (*npp1) -> toporder - (*npp2) -> toporder; 694508Speter } 704508Speter 71*16850Smckusick nltype ** 724508Speter doarcs() 734508Speter { 74*16850Smckusick nltype *parentp, **timesortnlp; 754508Speter arctype *arcp; 764508Speter long index; 774508Speter 784508Speter /* 794508Speter * initialize various things: 804508Speter * zero out child times. 814508Speter * count self-recursive calls. 824508Speter * indicate that nothing is on cycles. 834508Speter */ 844508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 854508Speter parentp -> childtime = 0.0; 864508Speter arcp = arclookup( parentp , parentp ); 874508Speter if ( arcp != 0 ) { 884508Speter parentp -> ncall -= arcp -> arc_count; 894508Speter parentp -> selfcalls = arcp -> arc_count; 904508Speter } else { 914508Speter parentp -> selfcalls = 0; 924508Speter } 937221Speter parentp -> propfraction = 0.0; 947221Speter parentp -> propself = 0.0; 957221Speter parentp -> propchild = 0.0; 967172Speter parentp -> printflag = FALSE; 9710284Speter parentp -> toporder = DFN_NAN; 984508Speter parentp -> cycleno = 0; 994508Speter parentp -> cyclehead = parentp; 1004508Speter parentp -> cnext = 0; 1017172Speter if ( cflag ) { 1027172Speter findcalls( parentp , parentp -> value , (parentp+1) -> value ); 1037172Speter } 1044508Speter } 1054508Speter /* 1064508Speter * topologically order things 10710284Speter * if any node is unnumbered, 10810284Speter * number it and any of its descendents. 1094508Speter */ 1104508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 11110284Speter if ( parentp -> toporder == DFN_NAN ) { 1124508Speter dfn( parentp ); 1134508Speter } 1144508Speter } 1154508Speter /* 1164508Speter * link together nodes on the same cycle 1174508Speter */ 1184508Speter cyclelink(); 1194508Speter /* 1204508Speter * Sort the symbol table in reverse topological order 1214508Speter */ 1224508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1234508Speter if ( topsortnlp == (nltype **) 0 ) { 1244508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1254508Speter } 1264508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1274508Speter topsortnlp[ index ] = &nl[ index ]; 1284508Speter } 1294508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1304508Speter # ifdef DEBUG 1314508Speter if ( debug & DFNDEBUG ) { 1324508Speter printf( "[doarcs] topological sort listing\n" ); 1334508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1344508Speter printf( "[doarcs] " ); 1354508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1364508Speter printname( topsortnlp[ index ] ); 1374508Speter printf( "\n" ); 1384508Speter } 1394508Speter } 1404508Speter # endif DEBUG 1414508Speter /* 1427221Speter * starting from the topological top, 1437221Speter * propagate print flags to children. 1447221Speter * also, calculate propagation fractions. 1457221Speter * this happens before time propagation 1467221Speter * since time propagation uses the fractions. 1477221Speter */ 1487221Speter doflags(); 1497221Speter /* 1504508Speter * starting from the topological bottom, 1517172Speter * propogate children times up to parents. 1524508Speter */ 1537172Speter dotime(); 154*16850Smckusick /* 155*16850Smckusick * Now, sort by propself + propchild. 156*16850Smckusick * sorting both the regular function names 157*16850Smckusick * and cycle headers. 158*16850Smckusick */ 159*16850Smckusick timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 160*16850Smckusick if ( timesortnlp == (nltype **) 0 ) { 161*16850Smckusick fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 162*16850Smckusick } 163*16850Smckusick for ( index = 0 ; index < nname ; index++ ) { 164*16850Smckusick timesortnlp[index] = &nl[index]; 165*16850Smckusick } 166*16850Smckusick for ( index = 1 ; index <= ncycle ; index++ ) { 167*16850Smckusick timesortnlp[nname+index-1] = &cyclenl[index]; 168*16850Smckusick } 169*16850Smckusick qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); 170*16850Smckusick for ( index = 0 ; index < nname + ncycle ; index++ ) { 171*16850Smckusick timesortnlp[ index ] -> index = index + 1; 172*16850Smckusick } 173*16850Smckusick return( timesortnlp ); 1747172Speter } 1757172Speter 1767172Speter dotime() 1777172Speter { 1787172Speter int index; 1797172Speter 1807172Speter cycletime(); 1814508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1827172Speter timepropagate( topsortnlp[ index ] ); 1837127Speter } 1847127Speter } 1857127Speter 1867172Speter timepropagate( parentp ) 1877127Speter nltype *parentp; 1887127Speter { 1897127Speter arctype *arcp; 1907127Speter nltype *childp; 1917127Speter double share; 1927221Speter double propshare; 1937127Speter 1947221Speter if ( parentp -> propfraction == 0.0 ) { 1957221Speter return; 1967221Speter } 1977127Speter /* 1987127Speter * gather time from children of this parent. 1997127Speter */ 2007172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 2017127Speter childp = arcp -> arc_childp; 2027127Speter if ( arcp -> arc_count == 0 ) { 2037127Speter continue; 2047127Speter } 2057221Speter if ( childp == parentp ) { 2067127Speter continue; 2077127Speter } 2087221Speter if ( childp -> propfraction == 0.0 ) { 2097127Speter continue; 2107127Speter } 2117127Speter if ( childp -> cyclehead != childp ) { 2127127Speter if ( parentp -> cycleno == childp -> cycleno ) { 2137127Speter continue; 2147127Speter } 2157127Speter if ( parentp -> toporder <= childp -> toporder ) { 2167127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2174508Speter } 2187127Speter childp = childp -> cyclehead; 2197127Speter } else { 2207127Speter if ( parentp -> toporder <= childp -> toporder ) { 2217127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2224508Speter continue; 2234508Speter } 2247127Speter } 2257221Speter if ( childp -> ncall == 0 ) { 2267221Speter continue; 2277221Speter } 2287127Speter /* 2297127Speter * distribute time for this arc 2307127Speter */ 2317221Speter arcp -> arc_time = childp -> time 2327221Speter * ( ( (double) arcp -> arc_count ) / 2337221Speter ( (double) childp -> ncall ) ); 2347221Speter arcp -> arc_childtime = childp -> childtime 2357221Speter * ( ( (double) arcp -> arc_count ) / 2367221Speter ( (double) childp -> ncall ) ); 2377127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2387127Speter parentp -> childtime += share; 2397127Speter /* 2407221Speter * ( 1 - propfraction ) gets lost along the way 2417127Speter */ 2427221Speter propshare = parentp -> propfraction * share; 2437221Speter /* 2447221Speter * fix things for printing 2457221Speter */ 2467221Speter parentp -> propchild += propshare; 2477221Speter arcp -> arc_time *= parentp -> propfraction; 2487221Speter arcp -> arc_childtime *= parentp -> propfraction; 2497221Speter /* 2507221Speter * add this share to the parent's cycle header, if any. 2517221Speter */ 2527127Speter if ( parentp -> cyclehead != parentp ) { 2537127Speter parentp -> cyclehead -> childtime += share; 2547221Speter parentp -> cyclehead -> propchild += propshare; 2554508Speter } 2567221Speter # ifdef DEBUG 2577221Speter if ( debug & PROPDEBUG ) { 2587221Speter printf( "[dotime] child \t" ); 2597221Speter printname( childp ); 2607221Speter printf( " with %f %f %d/%d\n" , 2617221Speter childp -> time , childp -> childtime , 2627221Speter arcp -> arc_count , childp -> ncall ); 2637221Speter printf( "[dotime] parent\t" ); 2647221Speter printname( parentp ); 2657221Speter printf( "\n[dotime] share %f\n" , share ); 2667221Speter } 2677221Speter # endif DEBUG 2684508Speter } 2694508Speter } 2704508Speter 2714508Speter cyclelink() 2724508Speter { 2734508Speter register nltype *nlp; 2744508Speter register nltype *cyclenlp; 2754508Speter int cycle; 2767172Speter nltype *memberp; 2777248Speter arctype *arcp; 2784508Speter 2794508Speter /* 2804508Speter * Count the number of cycles, and initialze the cycle lists 2814508Speter */ 2827127Speter ncycle = 0; 2834508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2844508Speter /* 2854508Speter * this is how you find unattached cycles 2864508Speter */ 2874508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2887127Speter ncycle += 1; 2894508Speter } 2904508Speter } 2917127Speter /* 2927127Speter * cyclenl is indexed by cycle number: 2937127Speter * i.e. it is origin 1, not origin 0. 2947127Speter */ 2957127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 2967127Speter if ( cyclenl == 0 ) { 2977127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 2987127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 2997127Speter done(); 3004508Speter } 3014508Speter /* 3024508Speter * now link cycles to true cycleheads, 3034508Speter * number them, accumulate the data for the cycle 3044508Speter */ 3054508Speter cycle = 0; 3064508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 30710284Speter if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 3084508Speter continue; 3094508Speter } 3104508Speter cycle += 1; 3117127Speter cyclenlp = &cyclenl[cycle]; 3127249Speter cyclenlp -> name = 0; /* the name */ 3137221Speter cyclenlp -> value = 0; /* the pc entry point */ 3147221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 3157221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 3167221Speter cyclenlp -> ncall = 0; /* how many times called */ 3177221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 3187221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 3197221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 3207221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 3217221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 3227221Speter cyclenlp -> index = 0; /* index in the graph list */ 32310284Speter cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 3247221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 3257221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 3267221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 3277221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 3287221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3294508Speter # ifdef DEBUG 3304508Speter if ( debug & CYCLEDEBUG ) { 3314508Speter printf( "[cyclelink] " ); 3324508Speter printname( nlp ); 3334508Speter printf( " is the head of cycle %d\n" , cycle ); 3344508Speter } 3354508Speter # endif DEBUG 3367248Speter /* 3377248Speter * link members to cycle header 3387248Speter */ 3397172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3407172Speter memberp -> cycleno = cycle; 3417172Speter memberp -> cyclehead = cyclenlp; 3427172Speter } 3437248Speter /* 3447248Speter * count calls from outside the cycle 3457248Speter * and those among cycle members 3467248Speter */ 3477248Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3487248Speter for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 3497248Speter if ( arcp -> arc_parentp == memberp ) { 3507248Speter continue; 3517248Speter } 3527248Speter if ( arcp -> arc_parentp -> cycleno == cycle ) { 3537248Speter cyclenlp -> selfcalls += arcp -> arc_count; 3547248Speter } else { 3557248Speter cyclenlp -> ncall += arcp -> arc_count; 3567248Speter } 3577248Speter } 3587248Speter } 3597172Speter } 3607172Speter } 3617172Speter 3627172Speter cycletime() 3637172Speter { 3647172Speter int cycle; 3657172Speter nltype *cyclenlp; 3667172Speter nltype *childp; 3677172Speter 3687172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3697172Speter cyclenlp = &cyclenl[ cycle ]; 3707221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 3717221Speter if ( childp -> propfraction == 0.0 ) { 3727221Speter /* 3737221Speter * all members have the same propfraction except those 3747221Speter * that were excluded with -E 3757221Speter */ 3767221Speter continue; 3777221Speter } 3787221Speter cyclenlp -> time += childp -> time; 3794508Speter } 3807221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3814508Speter } 3824508Speter } 3837172Speter 3847172Speter /* 3857172Speter * in one top to bottom pass over the topologically sorted namelist 3867221Speter * propagate: 3877221Speter * printflag as the union of parents' printflags 3887221Speter * propfraction as the sum of fractional parents' propfractions 3897221Speter * and while we're here, sum time for functions. 3907172Speter */ 3917172Speter doflags() 3927172Speter { 3937172Speter int index; 3947172Speter nltype *childp; 3957172Speter nltype *oldhead; 3967172Speter 3977172Speter oldhead = 0; 3987172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 3997172Speter childp = topsortnlp[ index ]; 4007172Speter /* 4017172Speter * if we haven't done this function or cycle, 4027221Speter * inherit things from parent. 4037172Speter * this way, we are linear in the number of arcs 4047172Speter * since we do all members of a cycle (and the cycle itself) 4057172Speter * as we hit the first member of the cycle. 4067172Speter */ 4077172Speter if ( childp -> cyclehead != oldhead ) { 4087172Speter oldhead = childp -> cyclehead; 4097221Speter inheritflags( childp ); 4107172Speter } 4117221Speter # ifdef DEBUG 4127221Speter if ( debug & PROPDEBUG ) { 4137221Speter printf( "[doflags] " ); 4147221Speter printname( childp ); 4157221Speter printf( " inherits printflag %d and propfraction %f\n" , 4167221Speter childp -> printflag , childp -> propfraction ); 4177221Speter } 4187221Speter # endif DEBUG 4197172Speter if ( ! childp -> printflag ) { 4207172Speter /* 4217221Speter * printflag is off 4227221Speter * it gets turned on by 4237221Speter * being on -f list, 4247221Speter * or there not being any -f list and not being on -e list. 4257172Speter */ 4267221Speter if ( onlist( flist , childp -> name ) 4277221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4287172Speter childp -> printflag = TRUE; 4297172Speter } 4307221Speter } else { 4317221Speter /* 4327221Speter * this function has printing parents: 4337221Speter * maybe someone wants to shut it up 4347221Speter * by putting it on -e list. (but favor -f over -e) 4357221Speter */ 4367221Speter if ( ( !onlist( flist , childp -> name ) ) 4377221Speter && onlist( elist , childp -> name ) ) { 4387221Speter childp -> printflag = FALSE; 4397172Speter } 4407221Speter } 4417221Speter if ( childp -> propfraction == 0.0 ) { 4427221Speter /* 4437221Speter * no parents to pass time to. 4447221Speter * collect time from children if 4457221Speter * its on -F list, 4467221Speter * or there isn't any -F list and its not on -E list. 4477221Speter */ 4487221Speter if ( onlist( Flist , childp -> name ) 4497221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 4507221Speter childp -> propfraction = 1.0; 4517172Speter } 4527221Speter } else { 4537221Speter /* 4547221Speter * it has parents to pass time to, 4557221Speter * but maybe someone wants to shut it up 4567221Speter * by puttting it on -E list. (but favor -F over -E) 4577221Speter */ 4587221Speter if ( !onlist( Flist , childp -> name ) 4597221Speter && onlist( Elist , childp -> name ) ) { 4607221Speter childp -> propfraction = 0.0; 4617221Speter } 4627172Speter } 4637221Speter childp -> propself = childp -> time * childp -> propfraction; 4647221Speter printtime += childp -> propself; 4657221Speter # ifdef DEBUG 4667221Speter if ( debug & PROPDEBUG ) { 4677221Speter printf( "[doflags] " ); 4687221Speter printname( childp ); 4697221Speter printf( " ends up with printflag %d and propfraction %f\n" , 4707221Speter childp -> printflag , childp -> propfraction ); 4718908Speter printf( "time %f propself %f printtime %f\n" , 4728908Speter childp -> time , childp -> propself , printtime ); 4737221Speter } 4747221Speter # endif DEBUG 4757172Speter } 4767172Speter } 4777172Speter 4787172Speter /* 4797172Speter * check if any parent of this child 4807172Speter * (or outside parents of this cycle) 4817172Speter * have their print flags on and set the 4827172Speter * print flag of the child (cycle) appropriately. 4837221Speter * similarly, deal with propagation fractions from parents. 4847172Speter */ 4857221Speter inheritflags( childp ) 4867172Speter nltype *childp; 4877172Speter { 4887172Speter nltype *headp; 4897221Speter arctype *arcp; 4907221Speter nltype *parentp; 4917172Speter nltype *memp; 4927172Speter 4937172Speter headp = childp -> cyclehead; 4947172Speter if ( childp == headp ) { 4957172Speter /* 4967172Speter * just a regular child, check its parents 4977172Speter */ 4987221Speter childp -> printflag = FALSE; 4997221Speter childp -> propfraction = 0.0; 5007221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 5017221Speter parentp = arcp -> arc_parentp; 5028908Speter if ( childp == parentp ) { 5038908Speter continue; 5048908Speter } 5057221Speter childp -> printflag |= parentp -> printflag; 50614140Speter /* 50714140Speter * if the child was never actually called 50814140Speter * (e.g. this arc is static (and all others are, too)) 50914140Speter * no time propagates along this arc. 51014140Speter */ 51114140Speter if ( childp -> ncall ) { 51214140Speter childp -> propfraction += parentp -> propfraction 51314140Speter * ( ( (double) arcp -> arc_count ) 51414140Speter / ( (double) childp -> ncall ) ); 51514140Speter } 5167172Speter } 5177221Speter } else { 5187221Speter /* 5197221Speter * its a member of a cycle, look at all parents from 5207221Speter * outside the cycle 5217221Speter */ 5227221Speter headp -> printflag = FALSE; 5237221Speter headp -> propfraction = 0.0; 5247221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 5257221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 5267221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 5277221Speter continue; 5287221Speter } 5297221Speter parentp = arcp -> arc_parentp; 5307221Speter headp -> printflag |= parentp -> printflag; 53114140Speter /* 53214140Speter * if the cycle was never actually called 53314140Speter * (e.g. this arc is static (and all others are, too)) 53414140Speter * no time propagates along this arc. 53514140Speter */ 53614140Speter if ( headp -> ncall ) { 53714140Speter headp -> propfraction += parentp -> propfraction 53814140Speter * ( ( (double) arcp -> arc_count ) 53914140Speter / ( (double) headp -> ncall ) ); 54014140Speter } 5417172Speter } 5427172Speter } 5437221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 5447221Speter memp -> printflag = headp -> printflag; 5457221Speter memp -> propfraction = headp -> propfraction; 5467221Speter } 5477172Speter } 5487172Speter } 549