121957Sdist /* 221957Sdist * Copyright (c) 1983 Regents of the University of California. 334199Sbostic * All rights reserved. 434199Sbostic * 5*42683Sbostic * %sccs.include.redist.c% 621957Sdist */ 721957Sdist 84508Speter #ifndef lint 9*42683Sbostic static char sccsid[] = "@(#)arcs.c 5.6 (Berkeley) 06/01/90"; 1034199Sbostic #endif /* not lint */ 114508Speter 124561Speter #include "gprof.h" 134508Speter 144721Speter /* 154721Speter * add (or just increment) an arc 164721Speter */ 174721Speter addarc( parentp , childp , count ) 184721Speter nltype *parentp; 194721Speter nltype *childp; 204721Speter long count; 214721Speter { 224750Speter arctype *calloc(); 234721Speter arctype *arcp; 244721Speter 254721Speter # ifdef DEBUG 264721Speter if ( debug & TALLYDEBUG ) { 274721Speter printf( "[addarc] %d arcs from %s to %s\n" , 284721Speter count , parentp -> name , childp -> name ); 294721Speter } 304721Speter # endif DEBUG 314721Speter arcp = arclookup( parentp , childp ); 324721Speter if ( arcp != 0 ) { 334721Speter /* 344721Speter * a hit: just increment the count. 354721Speter */ 364721Speter # ifdef DEBUG 374721Speter if ( debug & TALLYDEBUG ) { 384721Speter printf( "[tally] hit %d += %d\n" , 394721Speter arcp -> arc_count , count ); 404721Speter } 414721Speter # endif DEBUG 424721Speter arcp -> arc_count += count; 434721Speter return; 444721Speter } 454750Speter arcp = calloc( 1 , sizeof *arcp ); 464721Speter arcp -> arc_parentp = parentp; 474721Speter arcp -> arc_childp = childp; 484721Speter arcp -> arc_count = count; 494721Speter /* 504721Speter * prepend this child to the children of this parent 514721Speter */ 524721Speter arcp -> arc_childlist = parentp -> children; 534721Speter parentp -> children = arcp; 544721Speter /* 554721Speter * prepend this parent to the parents of this child 564721Speter */ 574721Speter arcp -> arc_parentlist = childp -> parents; 584721Speter childp -> parents = arcp; 594721Speter } 604721Speter 617172Speter /* 627172Speter * the code below topologically sorts the graph (collapsing cycles), 637172Speter * and propagates time bottom up and flags top down. 647172Speter */ 657172Speter 667172Speter /* 677172Speter * the topologically sorted name list pointers 687172Speter */ 697172Speter nltype **topsortnlp; 707172Speter 714508Speter topcmp( npp1 , npp2 ) 724508Speter nltype **npp1; 734508Speter nltype **npp2; 744508Speter { 754508Speter return (*npp1) -> toporder - (*npp2) -> toporder; 764508Speter } 774508Speter 7816850Smckusick nltype ** 794508Speter doarcs() 804508Speter { 8116850Smckusick nltype *parentp, **timesortnlp; 824508Speter arctype *arcp; 834508Speter long index; 844508Speter 854508Speter /* 864508Speter * initialize various things: 874508Speter * zero out child times. 884508Speter * count self-recursive calls. 894508Speter * indicate that nothing is on cycles. 904508Speter */ 914508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 924508Speter parentp -> childtime = 0.0; 934508Speter arcp = arclookup( parentp , parentp ); 944508Speter if ( arcp != 0 ) { 954508Speter parentp -> ncall -= arcp -> arc_count; 964508Speter parentp -> selfcalls = arcp -> arc_count; 974508Speter } else { 984508Speter parentp -> selfcalls = 0; 994508Speter } 1007221Speter parentp -> propfraction = 0.0; 1017221Speter parentp -> propself = 0.0; 1027221Speter parentp -> propchild = 0.0; 1037172Speter parentp -> printflag = FALSE; 10410284Speter parentp -> toporder = DFN_NAN; 1054508Speter parentp -> cycleno = 0; 1064508Speter parentp -> cyclehead = parentp; 1074508Speter parentp -> cnext = 0; 1087172Speter if ( cflag ) { 10925713Ssam findcall( parentp , parentp -> value , (parentp+1) -> value ); 1107172Speter } 1114508Speter } 1124508Speter /* 1134508Speter * topologically order things 11410284Speter * if any node is unnumbered, 11510284Speter * number it and any of its descendents. 1164508Speter */ 1174508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 11810284Speter if ( parentp -> toporder == DFN_NAN ) { 1194508Speter dfn( parentp ); 1204508Speter } 1214508Speter } 1224508Speter /* 1234508Speter * link together nodes on the same cycle 1244508Speter */ 1254508Speter cyclelink(); 1264508Speter /* 1274508Speter * Sort the symbol table in reverse topological order 1284508Speter */ 1294508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1304508Speter if ( topsortnlp == (nltype **) 0 ) { 1314508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1324508Speter } 1334508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1344508Speter topsortnlp[ index ] = &nl[ index ]; 1354508Speter } 1364508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1374508Speter # ifdef DEBUG 1384508Speter if ( debug & DFNDEBUG ) { 1394508Speter printf( "[doarcs] topological sort listing\n" ); 1404508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1414508Speter printf( "[doarcs] " ); 1424508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1434508Speter printname( topsortnlp[ index ] ); 1444508Speter printf( "\n" ); 1454508Speter } 1464508Speter } 1474508Speter # endif DEBUG 1484508Speter /* 1497221Speter * starting from the topological top, 1507221Speter * propagate print flags to children. 1517221Speter * also, calculate propagation fractions. 1527221Speter * this happens before time propagation 1537221Speter * since time propagation uses the fractions. 1547221Speter */ 1557221Speter doflags(); 1567221Speter /* 1574508Speter * starting from the topological bottom, 1587172Speter * propogate children times up to parents. 1594508Speter */ 1607172Speter dotime(); 16116850Smckusick /* 16216850Smckusick * Now, sort by propself + propchild. 16316850Smckusick * sorting both the regular function names 16416850Smckusick * and cycle headers. 16516850Smckusick */ 16616850Smckusick timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 16716850Smckusick if ( timesortnlp == (nltype **) 0 ) { 16816850Smckusick fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 16916850Smckusick } 17016850Smckusick for ( index = 0 ; index < nname ; index++ ) { 17116850Smckusick timesortnlp[index] = &nl[index]; 17216850Smckusick } 17316850Smckusick for ( index = 1 ; index <= ncycle ; index++ ) { 17416850Smckusick timesortnlp[nname+index-1] = &cyclenl[index]; 17516850Smckusick } 17616850Smckusick qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); 17716850Smckusick for ( index = 0 ; index < nname + ncycle ; index++ ) { 17816850Smckusick timesortnlp[ index ] -> index = index + 1; 17916850Smckusick } 18016850Smckusick return( timesortnlp ); 1817172Speter } 1827172Speter 1837172Speter dotime() 1847172Speter { 1857172Speter int index; 1867172Speter 1877172Speter cycletime(); 1884508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1897172Speter timepropagate( topsortnlp[ index ] ); 1907127Speter } 1917127Speter } 1927127Speter 1937172Speter timepropagate( parentp ) 1947127Speter nltype *parentp; 1957127Speter { 1967127Speter arctype *arcp; 1977127Speter nltype *childp; 1987127Speter double share; 1997221Speter double propshare; 2007127Speter 2017221Speter if ( parentp -> propfraction == 0.0 ) { 2027221Speter return; 2037221Speter } 2047127Speter /* 2057127Speter * gather time from children of this parent. 2067127Speter */ 2077172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 2087127Speter childp = arcp -> arc_childp; 2097127Speter if ( arcp -> arc_count == 0 ) { 2107127Speter continue; 2117127Speter } 2127221Speter if ( childp == parentp ) { 2137127Speter continue; 2147127Speter } 2157221Speter if ( childp -> propfraction == 0.0 ) { 2167127Speter continue; 2177127Speter } 2187127Speter if ( childp -> cyclehead != childp ) { 2197127Speter if ( parentp -> cycleno == childp -> cycleno ) { 2207127Speter continue; 2217127Speter } 2227127Speter if ( parentp -> toporder <= childp -> toporder ) { 2237127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2244508Speter } 2257127Speter childp = childp -> cyclehead; 2267127Speter } else { 2277127Speter if ( parentp -> toporder <= childp -> toporder ) { 2287127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2294508Speter continue; 2304508Speter } 2317127Speter } 2327221Speter if ( childp -> ncall == 0 ) { 2337221Speter continue; 2347221Speter } 2357127Speter /* 2367127Speter * distribute time for this arc 2377127Speter */ 2387221Speter arcp -> arc_time = childp -> time 2397221Speter * ( ( (double) arcp -> arc_count ) / 2407221Speter ( (double) childp -> ncall ) ); 2417221Speter arcp -> arc_childtime = childp -> childtime 2427221Speter * ( ( (double) arcp -> arc_count ) / 2437221Speter ( (double) childp -> ncall ) ); 2447127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2457127Speter parentp -> childtime += share; 2467127Speter /* 2477221Speter * ( 1 - propfraction ) gets lost along the way 2487127Speter */ 2497221Speter propshare = parentp -> propfraction * share; 2507221Speter /* 2517221Speter * fix things for printing 2527221Speter */ 2537221Speter parentp -> propchild += propshare; 2547221Speter arcp -> arc_time *= parentp -> propfraction; 2557221Speter arcp -> arc_childtime *= parentp -> propfraction; 2567221Speter /* 2577221Speter * add this share to the parent's cycle header, if any. 2587221Speter */ 2597127Speter if ( parentp -> cyclehead != parentp ) { 2607127Speter parentp -> cyclehead -> childtime += share; 2617221Speter parentp -> cyclehead -> propchild += propshare; 2624508Speter } 2637221Speter # ifdef DEBUG 2647221Speter if ( debug & PROPDEBUG ) { 2657221Speter printf( "[dotime] child \t" ); 2667221Speter printname( childp ); 2677221Speter printf( " with %f %f %d/%d\n" , 2687221Speter childp -> time , childp -> childtime , 2697221Speter arcp -> arc_count , childp -> ncall ); 2707221Speter printf( "[dotime] parent\t" ); 2717221Speter printname( parentp ); 2727221Speter printf( "\n[dotime] share %f\n" , share ); 2737221Speter } 2747221Speter # endif DEBUG 2754508Speter } 2764508Speter } 2774508Speter 2784508Speter cyclelink() 2794508Speter { 2804508Speter register nltype *nlp; 2814508Speter register nltype *cyclenlp; 2824508Speter int cycle; 2837172Speter nltype *memberp; 2847248Speter arctype *arcp; 2854508Speter 2864508Speter /* 2874508Speter * Count the number of cycles, and initialze the cycle lists 2884508Speter */ 2897127Speter ncycle = 0; 2904508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2914508Speter /* 2924508Speter * this is how you find unattached cycles 2934508Speter */ 2944508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2957127Speter ncycle += 1; 2964508Speter } 2974508Speter } 2987127Speter /* 2997127Speter * cyclenl is indexed by cycle number: 3007127Speter * i.e. it is origin 1, not origin 0. 3017127Speter */ 3027127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 3037127Speter if ( cyclenl == 0 ) { 3047127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 3057127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 3067127Speter done(); 3074508Speter } 3084508Speter /* 3094508Speter * now link cycles to true cycleheads, 3104508Speter * number them, accumulate the data for the cycle 3114508Speter */ 3124508Speter cycle = 0; 3134508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 31410284Speter if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 3154508Speter continue; 3164508Speter } 3174508Speter cycle += 1; 3187127Speter cyclenlp = &cyclenl[cycle]; 3197249Speter cyclenlp -> name = 0; /* the name */ 3207221Speter cyclenlp -> value = 0; /* the pc entry point */ 3217221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 3227221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 3237221Speter cyclenlp -> ncall = 0; /* how many times called */ 3247221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 3257221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 3267221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 3277221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 3287221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 3297221Speter cyclenlp -> index = 0; /* index in the graph list */ 33010284Speter cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 3317221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 3327221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 3337221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 3347221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 3357221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3364508Speter # ifdef DEBUG 3374508Speter if ( debug & CYCLEDEBUG ) { 3384508Speter printf( "[cyclelink] " ); 3394508Speter printname( nlp ); 3404508Speter printf( " is the head of cycle %d\n" , cycle ); 3414508Speter } 3424508Speter # endif DEBUG 3437248Speter /* 3447248Speter * link members to cycle header 3457248Speter */ 3467172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3477172Speter memberp -> cycleno = cycle; 3487172Speter memberp -> cyclehead = cyclenlp; 3497172Speter } 3507248Speter /* 3517248Speter * count calls from outside the cycle 3527248Speter * and those among cycle members 3537248Speter */ 3547248Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3557248Speter for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 3567248Speter if ( arcp -> arc_parentp == memberp ) { 3577248Speter continue; 3587248Speter } 3597248Speter if ( arcp -> arc_parentp -> cycleno == cycle ) { 3607248Speter cyclenlp -> selfcalls += arcp -> arc_count; 3617248Speter } else { 3627248Speter cyclenlp -> ncall += arcp -> arc_count; 3637248Speter } 3647248Speter } 3657248Speter } 3667172Speter } 3677172Speter } 3687172Speter 3697172Speter cycletime() 3707172Speter { 3717172Speter int cycle; 3727172Speter nltype *cyclenlp; 3737172Speter nltype *childp; 3747172Speter 3757172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3767172Speter cyclenlp = &cyclenl[ cycle ]; 3777221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 3787221Speter if ( childp -> propfraction == 0.0 ) { 3797221Speter /* 3807221Speter * all members have the same propfraction except those 3817221Speter * that were excluded with -E 3827221Speter */ 3837221Speter continue; 3847221Speter } 3857221Speter cyclenlp -> time += childp -> time; 3864508Speter } 3877221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3884508Speter } 3894508Speter } 3907172Speter 3917172Speter /* 3927172Speter * in one top to bottom pass over the topologically sorted namelist 3937221Speter * propagate: 3947221Speter * printflag as the union of parents' printflags 3957221Speter * propfraction as the sum of fractional parents' propfractions 3967221Speter * and while we're here, sum time for functions. 3977172Speter */ 3987172Speter doflags() 3997172Speter { 4007172Speter int index; 4017172Speter nltype *childp; 4027172Speter nltype *oldhead; 4037172Speter 4047172Speter oldhead = 0; 4057172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 4067172Speter childp = topsortnlp[ index ]; 4077172Speter /* 4087172Speter * if we haven't done this function or cycle, 4097221Speter * inherit things from parent. 4107172Speter * this way, we are linear in the number of arcs 4117172Speter * since we do all members of a cycle (and the cycle itself) 4127172Speter * as we hit the first member of the cycle. 4137172Speter */ 4147172Speter if ( childp -> cyclehead != oldhead ) { 4157172Speter oldhead = childp -> cyclehead; 4167221Speter inheritflags( childp ); 4177172Speter } 4187221Speter # ifdef DEBUG 4197221Speter if ( debug & PROPDEBUG ) { 4207221Speter printf( "[doflags] " ); 4217221Speter printname( childp ); 4227221Speter printf( " inherits printflag %d and propfraction %f\n" , 4237221Speter childp -> printflag , childp -> propfraction ); 4247221Speter } 4257221Speter # endif DEBUG 4267172Speter if ( ! childp -> printflag ) { 4277172Speter /* 4287221Speter * printflag is off 4297221Speter * it gets turned on by 4307221Speter * being on -f list, 4317221Speter * or there not being any -f list and not being on -e list. 4327172Speter */ 4337221Speter if ( onlist( flist , childp -> name ) 4347221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4357172Speter childp -> printflag = TRUE; 4367172Speter } 4377221Speter } else { 4387221Speter /* 4397221Speter * this function has printing parents: 4407221Speter * maybe someone wants to shut it up 4417221Speter * by putting it on -e list. (but favor -f over -e) 4427221Speter */ 4437221Speter if ( ( !onlist( flist , childp -> name ) ) 4447221Speter && onlist( elist , childp -> name ) ) { 4457221Speter childp -> printflag = FALSE; 4467172Speter } 4477221Speter } 4487221Speter if ( childp -> propfraction == 0.0 ) { 4497221Speter /* 4507221Speter * no parents to pass time to. 4517221Speter * collect time from children if 4527221Speter * its on -F list, 4537221Speter * or there isn't any -F list and its not on -E list. 4547221Speter */ 4557221Speter if ( onlist( Flist , childp -> name ) 4567221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 4577221Speter childp -> propfraction = 1.0; 4587172Speter } 4597221Speter } else { 4607221Speter /* 4617221Speter * it has parents to pass time to, 4627221Speter * but maybe someone wants to shut it up 4637221Speter * by puttting it on -E list. (but favor -F over -E) 4647221Speter */ 4657221Speter if ( !onlist( Flist , childp -> name ) 4667221Speter && onlist( Elist , childp -> name ) ) { 4677221Speter childp -> propfraction = 0.0; 4687221Speter } 4697172Speter } 4707221Speter childp -> propself = childp -> time * childp -> propfraction; 4717221Speter printtime += childp -> propself; 4727221Speter # ifdef DEBUG 4737221Speter if ( debug & PROPDEBUG ) { 4747221Speter printf( "[doflags] " ); 4757221Speter printname( childp ); 4767221Speter printf( " ends up with printflag %d and propfraction %f\n" , 4777221Speter childp -> printflag , childp -> propfraction ); 4788908Speter printf( "time %f propself %f printtime %f\n" , 4798908Speter childp -> time , childp -> propself , printtime ); 4807221Speter } 4817221Speter # endif DEBUG 4827172Speter } 4837172Speter } 4847172Speter 4857172Speter /* 4867172Speter * check if any parent of this child 4877172Speter * (or outside parents of this cycle) 4887172Speter * have their print flags on and set the 4897172Speter * print flag of the child (cycle) appropriately. 4907221Speter * similarly, deal with propagation fractions from parents. 4917172Speter */ 4927221Speter inheritflags( childp ) 4937172Speter nltype *childp; 4947172Speter { 4957172Speter nltype *headp; 4967221Speter arctype *arcp; 4977221Speter nltype *parentp; 4987172Speter nltype *memp; 4997172Speter 5007172Speter headp = childp -> cyclehead; 5017172Speter if ( childp == headp ) { 5027172Speter /* 5037172Speter * just a regular child, check its parents 5047172Speter */ 5057221Speter childp -> printflag = FALSE; 5067221Speter childp -> propfraction = 0.0; 5077221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 5087221Speter parentp = arcp -> arc_parentp; 5098908Speter if ( childp == parentp ) { 5108908Speter continue; 5118908Speter } 5127221Speter childp -> printflag |= parentp -> printflag; 51314140Speter /* 51414140Speter * if the child was never actually called 51514140Speter * (e.g. this arc is static (and all others are, too)) 51614140Speter * no time propagates along this arc. 51714140Speter */ 51814140Speter if ( childp -> ncall ) { 51914140Speter childp -> propfraction += parentp -> propfraction 52014140Speter * ( ( (double) arcp -> arc_count ) 52114140Speter / ( (double) childp -> ncall ) ); 52214140Speter } 5237172Speter } 5247221Speter } else { 5257221Speter /* 5267221Speter * its a member of a cycle, look at all parents from 5277221Speter * outside the cycle 5287221Speter */ 5297221Speter headp -> printflag = FALSE; 5307221Speter headp -> propfraction = 0.0; 5317221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 5327221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 5337221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 5347221Speter continue; 5357221Speter } 5367221Speter parentp = arcp -> arc_parentp; 5377221Speter headp -> printflag |= parentp -> printflag; 53814140Speter /* 53914140Speter * if the cycle was never actually called 54014140Speter * (e.g. this arc is static (and all others are, too)) 54114140Speter * no time propagates along this arc. 54214140Speter */ 54314140Speter if ( headp -> ncall ) { 54414140Speter headp -> propfraction += parentp -> propfraction 54514140Speter * ( ( (double) arcp -> arc_count ) 54614140Speter / ( (double) headp -> ncall ) ); 54714140Speter } 5487172Speter } 5497172Speter } 5507221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 5517221Speter memp -> printflag = headp -> printflag; 5527221Speter memp -> propfraction = headp -> propfraction; 5537221Speter } 5547172Speter } 5557172Speter } 556