14508Speter #ifndef lint 2*10284Speter static char *sccsid = "@(#)arcs.c 1.13 (Berkeley) 01/15/83"; 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 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 } 927221Speter parentp -> propfraction = 0.0; 937221Speter parentp -> propself = 0.0; 947221Speter parentp -> propchild = 0.0; 957172Speter parentp -> printflag = FALSE; 96*10284Speter parentp -> toporder = DFN_NAN; 974508Speter parentp -> cycleno = 0; 984508Speter parentp -> cyclehead = parentp; 994508Speter parentp -> cnext = 0; 1007172Speter if ( cflag ) { 1017172Speter findcalls( parentp , parentp -> value , (parentp+1) -> value ); 1027172Speter } 1034508Speter } 1044508Speter /* 1054508Speter * topologically order things 106*10284Speter * if any node is unnumbered, 107*10284Speter * number it and any of its descendents. 1084508Speter */ 1094508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 110*10284Speter if ( parentp -> toporder == DFN_NAN ) { 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 /* 1417221Speter * starting from the topological top, 1427221Speter * propagate print flags to children. 1437221Speter * also, calculate propagation fractions. 1447221Speter * this happens before time propagation 1457221Speter * since time propagation uses the fractions. 1467221Speter */ 1477221Speter doflags(); 1487221Speter /* 1494508Speter * starting from the topological bottom, 1507172Speter * propogate children times up to parents. 1514508Speter */ 1527172Speter dotime(); 1537172Speter printgprof(); 1547172Speter } 1557172Speter 1567172Speter dotime() 1577172Speter { 1587172Speter int index; 1597172Speter 1607172Speter cycletime(); 1614508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1627172Speter timepropagate( topsortnlp[ index ] ); 1637127Speter } 1647127Speter } 1657127Speter 1667172Speter timepropagate( parentp ) 1677127Speter nltype *parentp; 1687127Speter { 1697127Speter arctype *arcp; 1707127Speter nltype *childp; 1717127Speter double share; 1727221Speter double propshare; 1737127Speter 1747221Speter if ( parentp -> propfraction == 0.0 ) { 1757221Speter return; 1767221Speter } 1777127Speter /* 1787127Speter * gather time from children of this parent. 1797127Speter */ 1807172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 1817127Speter childp = arcp -> arc_childp; 1827127Speter if ( arcp -> arc_count == 0 ) { 1837127Speter continue; 1847127Speter } 1857221Speter if ( childp == parentp ) { 1867127Speter continue; 1877127Speter } 1887221Speter if ( childp -> propfraction == 0.0 ) { 1897127Speter continue; 1907127Speter } 1917127Speter if ( childp -> cyclehead != childp ) { 1927127Speter if ( parentp -> cycleno == childp -> cycleno ) { 1937127Speter continue; 1947127Speter } 1957127Speter if ( parentp -> toporder <= childp -> toporder ) { 1967127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 1974508Speter } 1987127Speter childp = childp -> cyclehead; 1997127Speter } else { 2007127Speter if ( parentp -> toporder <= childp -> toporder ) { 2017127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2024508Speter continue; 2034508Speter } 2047127Speter } 2057221Speter if ( childp -> ncall == 0 ) { 2067221Speter continue; 2077221Speter } 2087127Speter /* 2097127Speter * distribute time for this arc 2107127Speter */ 2117221Speter arcp -> arc_time = childp -> time 2127221Speter * ( ( (double) arcp -> arc_count ) / 2137221Speter ( (double) childp -> ncall ) ); 2147221Speter arcp -> arc_childtime = childp -> childtime 2157221Speter * ( ( (double) arcp -> arc_count ) / 2167221Speter ( (double) childp -> ncall ) ); 2177127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2187127Speter parentp -> childtime += share; 2197127Speter /* 2207221Speter * ( 1 - propfraction ) gets lost along the way 2217127Speter */ 2227221Speter propshare = parentp -> propfraction * share; 2237221Speter /* 2247221Speter * fix things for printing 2257221Speter */ 2267221Speter parentp -> propchild += propshare; 2277221Speter arcp -> arc_time *= parentp -> propfraction; 2287221Speter arcp -> arc_childtime *= parentp -> propfraction; 2297221Speter /* 2307221Speter * add this share to the parent's cycle header, if any. 2317221Speter */ 2327127Speter if ( parentp -> cyclehead != parentp ) { 2337127Speter parentp -> cyclehead -> childtime += share; 2347221Speter parentp -> cyclehead -> propchild += propshare; 2354508Speter } 2367221Speter # ifdef DEBUG 2377221Speter if ( debug & PROPDEBUG ) { 2387221Speter printf( "[dotime] child \t" ); 2397221Speter printname( childp ); 2407221Speter printf( " with %f %f %d/%d\n" , 2417221Speter childp -> time , childp -> childtime , 2427221Speter arcp -> arc_count , childp -> ncall ); 2437221Speter printf( "[dotime] parent\t" ); 2447221Speter printname( parentp ); 2457221Speter printf( "\n[dotime] share %f\n" , share ); 2467221Speter } 2477221Speter # endif DEBUG 2484508Speter } 2494508Speter } 2504508Speter 2514508Speter cyclelink() 2524508Speter { 2534508Speter register nltype *nlp; 2544508Speter register nltype *cyclenlp; 2554508Speter int cycle; 2567172Speter nltype *memberp; 2577248Speter arctype *arcp; 2584508Speter 2594508Speter /* 2604508Speter * Count the number of cycles, and initialze the cycle lists 2614508Speter */ 2627127Speter ncycle = 0; 2634508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2644508Speter /* 2654508Speter * this is how you find unattached cycles 2664508Speter */ 2674508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2687127Speter ncycle += 1; 2694508Speter } 2704508Speter } 2717127Speter /* 2727127Speter * cyclenl is indexed by cycle number: 2737127Speter * i.e. it is origin 1, not origin 0. 2747127Speter */ 2757127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 2767127Speter if ( cyclenl == 0 ) { 2777127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 2787127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 2797127Speter done(); 2804508Speter } 2814508Speter /* 2824508Speter * now link cycles to true cycleheads, 2834508Speter * number them, accumulate the data for the cycle 2844508Speter */ 2854508Speter cycle = 0; 2864508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 287*10284Speter if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 2884508Speter continue; 2894508Speter } 2904508Speter cycle += 1; 2917127Speter cyclenlp = &cyclenl[cycle]; 2927249Speter cyclenlp -> name = 0; /* the name */ 2937221Speter cyclenlp -> value = 0; /* the pc entry point */ 2947221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 2957221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 2967221Speter cyclenlp -> ncall = 0; /* how many times called */ 2977221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 2987221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 2997221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 3007221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 3017221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 3027221Speter cyclenlp -> index = 0; /* index in the graph list */ 303*10284Speter cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 3047221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 3057221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 3067221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 3077221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 3087221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3094508Speter # ifdef DEBUG 3104508Speter if ( debug & CYCLEDEBUG ) { 3114508Speter printf( "[cyclelink] " ); 3124508Speter printname( nlp ); 3134508Speter printf( " is the head of cycle %d\n" , cycle ); 3144508Speter } 3154508Speter # endif DEBUG 3167248Speter /* 3177248Speter * link members to cycle header 3187248Speter */ 3197172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3207172Speter memberp -> cycleno = cycle; 3217172Speter memberp -> cyclehead = cyclenlp; 3227172Speter } 3237248Speter /* 3247248Speter * count calls from outside the cycle 3257248Speter * and those among cycle members 3267248Speter */ 3277248Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3287248Speter for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 3297248Speter if ( arcp -> arc_parentp == memberp ) { 3307248Speter continue; 3317248Speter } 3327248Speter if ( arcp -> arc_parentp -> cycleno == cycle ) { 3337248Speter cyclenlp -> selfcalls += arcp -> arc_count; 3347248Speter } else { 3357248Speter cyclenlp -> ncall += arcp -> arc_count; 3367248Speter } 3377248Speter } 3387248Speter } 3397172Speter } 3407172Speter } 3417172Speter 3427172Speter cycletime() 3437172Speter { 3447172Speter int cycle; 3457172Speter nltype *cyclenlp; 3467172Speter nltype *childp; 3477172Speter 3487172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3497172Speter cyclenlp = &cyclenl[ cycle ]; 3507221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 3517221Speter if ( childp -> propfraction == 0.0 ) { 3527221Speter /* 3537221Speter * all members have the same propfraction except those 3547221Speter * that were excluded with -E 3557221Speter */ 3567221Speter continue; 3577221Speter } 3587221Speter cyclenlp -> time += childp -> time; 3594508Speter } 3607221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3614508Speter } 3624508Speter } 3637172Speter 3647172Speter /* 3657172Speter * in one top to bottom pass over the topologically sorted namelist 3667221Speter * propagate: 3677221Speter * printflag as the union of parents' printflags 3687221Speter * propfraction as the sum of fractional parents' propfractions 3697221Speter * and while we're here, sum time for functions. 3707172Speter */ 3717172Speter doflags() 3727172Speter { 3737172Speter int index; 3747172Speter nltype *childp; 3757172Speter nltype *oldhead; 3767172Speter 3777172Speter oldhead = 0; 3787172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 3797172Speter childp = topsortnlp[ index ]; 3807172Speter /* 3817172Speter * if we haven't done this function or cycle, 3827221Speter * inherit things from parent. 3837172Speter * this way, we are linear in the number of arcs 3847172Speter * since we do all members of a cycle (and the cycle itself) 3857172Speter * as we hit the first member of the cycle. 3867172Speter */ 3877172Speter if ( childp -> cyclehead != oldhead ) { 3887172Speter oldhead = childp -> cyclehead; 3897221Speter inheritflags( childp ); 3907172Speter } 3917221Speter # ifdef DEBUG 3927221Speter if ( debug & PROPDEBUG ) { 3937221Speter printf( "[doflags] " ); 3947221Speter printname( childp ); 3957221Speter printf( " inherits printflag %d and propfraction %f\n" , 3967221Speter childp -> printflag , childp -> propfraction ); 3977221Speter } 3987221Speter # endif DEBUG 3997172Speter if ( ! childp -> printflag ) { 4007172Speter /* 4017221Speter * printflag is off 4027221Speter * it gets turned on by 4037221Speter * being on -f list, 4047221Speter * or there not being any -f list and not being on -e list. 4057172Speter */ 4067221Speter if ( onlist( flist , childp -> name ) 4077221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4087172Speter childp -> printflag = TRUE; 4097172Speter } 4107221Speter } else { 4117221Speter /* 4127221Speter * this function has printing parents: 4137221Speter * maybe someone wants to shut it up 4147221Speter * by putting it on -e list. (but favor -f over -e) 4157221Speter */ 4167221Speter if ( ( !onlist( flist , childp -> name ) ) 4177221Speter && onlist( elist , childp -> name ) ) { 4187221Speter childp -> printflag = FALSE; 4197172Speter } 4207221Speter } 4217221Speter if ( childp -> propfraction == 0.0 ) { 4227221Speter /* 4237221Speter * no parents to pass time to. 4247221Speter * collect time from children if 4257221Speter * its on -F list, 4267221Speter * or there isn't any -F list and its not on -E list. 4277221Speter */ 4287221Speter if ( onlist( Flist , childp -> name ) 4297221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 4307221Speter childp -> propfraction = 1.0; 4317172Speter } 4327221Speter } else { 4337221Speter /* 4347221Speter * it has parents to pass time to, 4357221Speter * but maybe someone wants to shut it up 4367221Speter * by puttting it on -E list. (but favor -F over -E) 4377221Speter */ 4387221Speter if ( !onlist( Flist , childp -> name ) 4397221Speter && onlist( Elist , childp -> name ) ) { 4407221Speter childp -> propfraction = 0.0; 4417221Speter } 4427172Speter } 4437221Speter childp -> propself = childp -> time * childp -> propfraction; 4447221Speter printtime += childp -> propself; 4457221Speter # ifdef DEBUG 4467221Speter if ( debug & PROPDEBUG ) { 4477221Speter printf( "[doflags] " ); 4487221Speter printname( childp ); 4497221Speter printf( " ends up with printflag %d and propfraction %f\n" , 4507221Speter childp -> printflag , childp -> propfraction ); 4518908Speter printf( "time %f propself %f printtime %f\n" , 4528908Speter childp -> time , childp -> propself , printtime ); 4537221Speter } 4547221Speter # endif DEBUG 4557172Speter } 4567172Speter } 4577172Speter 4587172Speter /* 4597172Speter * check if any parent of this child 4607172Speter * (or outside parents of this cycle) 4617172Speter * have their print flags on and set the 4627172Speter * print flag of the child (cycle) appropriately. 4637221Speter * similarly, deal with propagation fractions from parents. 4647172Speter */ 4657221Speter inheritflags( childp ) 4667172Speter nltype *childp; 4677172Speter { 4687172Speter nltype *headp; 4697221Speter arctype *arcp; 4707221Speter nltype *parentp; 4717172Speter nltype *memp; 4727172Speter 4737172Speter headp = childp -> cyclehead; 4747172Speter if ( childp == headp ) { 4757172Speter /* 4767172Speter * just a regular child, check its parents 4777172Speter */ 4787221Speter childp -> printflag = FALSE; 4797221Speter childp -> propfraction = 0.0; 4807221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 4817221Speter parentp = arcp -> arc_parentp; 4828908Speter if ( childp == parentp ) { 4838908Speter continue; 4848908Speter } 4857221Speter childp -> printflag |= parentp -> printflag; 4867221Speter childp -> propfraction += parentp -> propfraction 4877221Speter * ( ( (double) arcp -> arc_count ) 4887248Speter / ( (double) childp -> ncall ) ); 4897172Speter } 4907221Speter } else { 4917221Speter /* 4927221Speter * its a member of a cycle, look at all parents from 4937221Speter * outside the cycle 4947221Speter */ 4957221Speter headp -> printflag = FALSE; 4967221Speter headp -> propfraction = 0.0; 4977221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 4987221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 4997221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 5007221Speter continue; 5017221Speter } 5027221Speter parentp = arcp -> arc_parentp; 5037221Speter headp -> printflag |= parentp -> printflag; 5047248Speter headp -> propfraction += parentp -> propfraction 5057248Speter * ( ( (double) arcp -> arc_count ) 5067248Speter / ( (double) headp -> ncall ) ); 5077172Speter } 5087172Speter } 5097221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 5107221Speter memp -> printflag = headp -> printflag; 5117221Speter memp -> propfraction = headp -> propfraction; 5127221Speter } 5137172Speter } 5147172Speter } 515