1*21957Sdist /* 2*21957Sdist * Copyright (c) 1983 Regents of the University of California. 3*21957Sdist * All rights reserved. The Berkeley software License Agreement 4*21957Sdist * specifies the terms and conditions for redistribution. 5*21957Sdist */ 6*21957Sdist 74508Speter #ifndef lint 8*21957Sdist static char sccsid[] = "@(#)arcs.c 5.1 (Berkeley) 06/04/85"; 9*21957Sdist #endif not lint 104508Speter 114561Speter #include "gprof.h" 124508Speter 134721Speter /* 144721Speter * add (or just increment) an arc 154721Speter */ 164721Speter addarc( parentp , childp , count ) 174721Speter nltype *parentp; 184721Speter nltype *childp; 194721Speter long count; 204721Speter { 214750Speter arctype *calloc(); 224721Speter arctype *arcp; 234721Speter 244721Speter # ifdef DEBUG 254721Speter if ( debug & TALLYDEBUG ) { 264721Speter printf( "[addarc] %d arcs from %s to %s\n" , 274721Speter count , parentp -> name , childp -> name ); 284721Speter } 294721Speter # endif DEBUG 304721Speter arcp = arclookup( parentp , childp ); 314721Speter if ( arcp != 0 ) { 324721Speter /* 334721Speter * a hit: just increment the count. 344721Speter */ 354721Speter # ifdef DEBUG 364721Speter if ( debug & TALLYDEBUG ) { 374721Speter printf( "[tally] hit %d += %d\n" , 384721Speter arcp -> arc_count , count ); 394721Speter } 404721Speter # endif DEBUG 414721Speter arcp -> arc_count += count; 424721Speter return; 434721Speter } 444750Speter arcp = calloc( 1 , sizeof *arcp ); 454721Speter arcp -> arc_parentp = parentp; 464721Speter arcp -> arc_childp = childp; 474721Speter arcp -> arc_count = count; 484721Speter /* 494721Speter * prepend this child to the children of this parent 504721Speter */ 514721Speter arcp -> arc_childlist = parentp -> children; 524721Speter parentp -> children = arcp; 534721Speter /* 544721Speter * prepend this parent to the parents of this child 554721Speter */ 564721Speter arcp -> arc_parentlist = childp -> parents; 574721Speter childp -> parents = arcp; 584721Speter } 594721Speter 607172Speter /* 617172Speter * the code below topologically sorts the graph (collapsing cycles), 627172Speter * and propagates time bottom up and flags top down. 637172Speter */ 647172Speter 657172Speter /* 667172Speter * the topologically sorted name list pointers 677172Speter */ 687172Speter nltype **topsortnlp; 697172Speter 704508Speter topcmp( npp1 , npp2 ) 714508Speter nltype **npp1; 724508Speter nltype **npp2; 734508Speter { 744508Speter return (*npp1) -> toporder - (*npp2) -> toporder; 754508Speter } 764508Speter 7716850Smckusick nltype ** 784508Speter doarcs() 794508Speter { 8016850Smckusick nltype *parentp, **timesortnlp; 814508Speter arctype *arcp; 824508Speter long index; 834508Speter 844508Speter /* 854508Speter * initialize various things: 864508Speter * zero out child times. 874508Speter * count self-recursive calls. 884508Speter * indicate that nothing is on cycles. 894508Speter */ 904508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 914508Speter parentp -> childtime = 0.0; 924508Speter arcp = arclookup( parentp , parentp ); 934508Speter if ( arcp != 0 ) { 944508Speter parentp -> ncall -= arcp -> arc_count; 954508Speter parentp -> selfcalls = arcp -> arc_count; 964508Speter } else { 974508Speter parentp -> selfcalls = 0; 984508Speter } 997221Speter parentp -> propfraction = 0.0; 1007221Speter parentp -> propself = 0.0; 1017221Speter parentp -> propchild = 0.0; 1027172Speter parentp -> printflag = FALSE; 10310284Speter parentp -> toporder = DFN_NAN; 1044508Speter parentp -> cycleno = 0; 1054508Speter parentp -> cyclehead = parentp; 1064508Speter parentp -> cnext = 0; 1077172Speter if ( cflag ) { 1087172Speter findcalls( parentp , parentp -> value , (parentp+1) -> value ); 1097172Speter } 1104508Speter } 1114508Speter /* 1124508Speter * topologically order things 11310284Speter * if any node is unnumbered, 11410284Speter * number it and any of its descendents. 1154508Speter */ 1164508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 11710284Speter if ( parentp -> toporder == DFN_NAN ) { 1184508Speter dfn( parentp ); 1194508Speter } 1204508Speter } 1214508Speter /* 1224508Speter * link together nodes on the same cycle 1234508Speter */ 1244508Speter cyclelink(); 1254508Speter /* 1264508Speter * Sort the symbol table in reverse topological order 1274508Speter */ 1284508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1294508Speter if ( topsortnlp == (nltype **) 0 ) { 1304508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1314508Speter } 1324508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1334508Speter topsortnlp[ index ] = &nl[ index ]; 1344508Speter } 1354508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1364508Speter # ifdef DEBUG 1374508Speter if ( debug & DFNDEBUG ) { 1384508Speter printf( "[doarcs] topological sort listing\n" ); 1394508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1404508Speter printf( "[doarcs] " ); 1414508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1424508Speter printname( topsortnlp[ index ] ); 1434508Speter printf( "\n" ); 1444508Speter } 1454508Speter } 1464508Speter # endif DEBUG 1474508Speter /* 1487221Speter * starting from the topological top, 1497221Speter * propagate print flags to children. 1507221Speter * also, calculate propagation fractions. 1517221Speter * this happens before time propagation 1527221Speter * since time propagation uses the fractions. 1537221Speter */ 1547221Speter doflags(); 1557221Speter /* 1564508Speter * starting from the topological bottom, 1577172Speter * propogate children times up to parents. 1584508Speter */ 1597172Speter dotime(); 16016850Smckusick /* 16116850Smckusick * Now, sort by propself + propchild. 16216850Smckusick * sorting both the regular function names 16316850Smckusick * and cycle headers. 16416850Smckusick */ 16516850Smckusick timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 16616850Smckusick if ( timesortnlp == (nltype **) 0 ) { 16716850Smckusick fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 16816850Smckusick } 16916850Smckusick for ( index = 0 ; index < nname ; index++ ) { 17016850Smckusick timesortnlp[index] = &nl[index]; 17116850Smckusick } 17216850Smckusick for ( index = 1 ; index <= ncycle ; index++ ) { 17316850Smckusick timesortnlp[nname+index-1] = &cyclenl[index]; 17416850Smckusick } 17516850Smckusick qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); 17616850Smckusick for ( index = 0 ; index < nname + ncycle ; index++ ) { 17716850Smckusick timesortnlp[ index ] -> index = index + 1; 17816850Smckusick } 17916850Smckusick return( timesortnlp ); 1807172Speter } 1817172Speter 1827172Speter dotime() 1837172Speter { 1847172Speter int index; 1857172Speter 1867172Speter cycletime(); 1874508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1887172Speter timepropagate( topsortnlp[ index ] ); 1897127Speter } 1907127Speter } 1917127Speter 1927172Speter timepropagate( parentp ) 1937127Speter nltype *parentp; 1947127Speter { 1957127Speter arctype *arcp; 1967127Speter nltype *childp; 1977127Speter double share; 1987221Speter double propshare; 1997127Speter 2007221Speter if ( parentp -> propfraction == 0.0 ) { 2017221Speter return; 2027221Speter } 2037127Speter /* 2047127Speter * gather time from children of this parent. 2057127Speter */ 2067172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 2077127Speter childp = arcp -> arc_childp; 2087127Speter if ( arcp -> arc_count == 0 ) { 2097127Speter continue; 2107127Speter } 2117221Speter if ( childp == parentp ) { 2127127Speter continue; 2137127Speter } 2147221Speter if ( childp -> propfraction == 0.0 ) { 2157127Speter continue; 2167127Speter } 2177127Speter if ( childp -> cyclehead != childp ) { 2187127Speter if ( parentp -> cycleno == childp -> cycleno ) { 2197127Speter continue; 2207127Speter } 2217127Speter if ( parentp -> toporder <= childp -> toporder ) { 2227127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2234508Speter } 2247127Speter childp = childp -> cyclehead; 2257127Speter } else { 2267127Speter if ( parentp -> toporder <= childp -> toporder ) { 2277127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2284508Speter continue; 2294508Speter } 2307127Speter } 2317221Speter if ( childp -> ncall == 0 ) { 2327221Speter continue; 2337221Speter } 2347127Speter /* 2357127Speter * distribute time for this arc 2367127Speter */ 2377221Speter arcp -> arc_time = childp -> time 2387221Speter * ( ( (double) arcp -> arc_count ) / 2397221Speter ( (double) childp -> ncall ) ); 2407221Speter arcp -> arc_childtime = childp -> childtime 2417221Speter * ( ( (double) arcp -> arc_count ) / 2427221Speter ( (double) childp -> ncall ) ); 2437127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2447127Speter parentp -> childtime += share; 2457127Speter /* 2467221Speter * ( 1 - propfraction ) gets lost along the way 2477127Speter */ 2487221Speter propshare = parentp -> propfraction * share; 2497221Speter /* 2507221Speter * fix things for printing 2517221Speter */ 2527221Speter parentp -> propchild += propshare; 2537221Speter arcp -> arc_time *= parentp -> propfraction; 2547221Speter arcp -> arc_childtime *= parentp -> propfraction; 2557221Speter /* 2567221Speter * add this share to the parent's cycle header, if any. 2577221Speter */ 2587127Speter if ( parentp -> cyclehead != parentp ) { 2597127Speter parentp -> cyclehead -> childtime += share; 2607221Speter parentp -> cyclehead -> propchild += propshare; 2614508Speter } 2627221Speter # ifdef DEBUG 2637221Speter if ( debug & PROPDEBUG ) { 2647221Speter printf( "[dotime] child \t" ); 2657221Speter printname( childp ); 2667221Speter printf( " with %f %f %d/%d\n" , 2677221Speter childp -> time , childp -> childtime , 2687221Speter arcp -> arc_count , childp -> ncall ); 2697221Speter printf( "[dotime] parent\t" ); 2707221Speter printname( parentp ); 2717221Speter printf( "\n[dotime] share %f\n" , share ); 2727221Speter } 2737221Speter # endif DEBUG 2744508Speter } 2754508Speter } 2764508Speter 2774508Speter cyclelink() 2784508Speter { 2794508Speter register nltype *nlp; 2804508Speter register nltype *cyclenlp; 2814508Speter int cycle; 2827172Speter nltype *memberp; 2837248Speter arctype *arcp; 2844508Speter 2854508Speter /* 2864508Speter * Count the number of cycles, and initialze the cycle lists 2874508Speter */ 2887127Speter ncycle = 0; 2894508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2904508Speter /* 2914508Speter * this is how you find unattached cycles 2924508Speter */ 2934508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2947127Speter ncycle += 1; 2954508Speter } 2964508Speter } 2977127Speter /* 2987127Speter * cyclenl is indexed by cycle number: 2997127Speter * i.e. it is origin 1, not origin 0. 3007127Speter */ 3017127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 3027127Speter if ( cyclenl == 0 ) { 3037127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 3047127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 3057127Speter done(); 3064508Speter } 3074508Speter /* 3084508Speter * now link cycles to true cycleheads, 3094508Speter * number them, accumulate the data for the cycle 3104508Speter */ 3114508Speter cycle = 0; 3124508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 31310284Speter if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 3144508Speter continue; 3154508Speter } 3164508Speter cycle += 1; 3177127Speter cyclenlp = &cyclenl[cycle]; 3187249Speter cyclenlp -> name = 0; /* the name */ 3197221Speter cyclenlp -> value = 0; /* the pc entry point */ 3207221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 3217221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 3227221Speter cyclenlp -> ncall = 0; /* how many times called */ 3237221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 3247221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 3257221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 3267221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 3277221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 3287221Speter cyclenlp -> index = 0; /* index in the graph list */ 32910284Speter cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 3307221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 3317221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 3327221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 3337221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 3347221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3354508Speter # ifdef DEBUG 3364508Speter if ( debug & CYCLEDEBUG ) { 3374508Speter printf( "[cyclelink] " ); 3384508Speter printname( nlp ); 3394508Speter printf( " is the head of cycle %d\n" , cycle ); 3404508Speter } 3414508Speter # endif DEBUG 3427248Speter /* 3437248Speter * link members to cycle header 3447248Speter */ 3457172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3467172Speter memberp -> cycleno = cycle; 3477172Speter memberp -> cyclehead = cyclenlp; 3487172Speter } 3497248Speter /* 3507248Speter * count calls from outside the cycle 3517248Speter * and those among cycle members 3527248Speter */ 3537248Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3547248Speter for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 3557248Speter if ( arcp -> arc_parentp == memberp ) { 3567248Speter continue; 3577248Speter } 3587248Speter if ( arcp -> arc_parentp -> cycleno == cycle ) { 3597248Speter cyclenlp -> selfcalls += arcp -> arc_count; 3607248Speter } else { 3617248Speter cyclenlp -> ncall += arcp -> arc_count; 3627248Speter } 3637248Speter } 3647248Speter } 3657172Speter } 3667172Speter } 3677172Speter 3687172Speter cycletime() 3697172Speter { 3707172Speter int cycle; 3717172Speter nltype *cyclenlp; 3727172Speter nltype *childp; 3737172Speter 3747172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3757172Speter cyclenlp = &cyclenl[ cycle ]; 3767221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 3777221Speter if ( childp -> propfraction == 0.0 ) { 3787221Speter /* 3797221Speter * all members have the same propfraction except those 3807221Speter * that were excluded with -E 3817221Speter */ 3827221Speter continue; 3837221Speter } 3847221Speter cyclenlp -> time += childp -> time; 3854508Speter } 3867221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3874508Speter } 3884508Speter } 3897172Speter 3907172Speter /* 3917172Speter * in one top to bottom pass over the topologically sorted namelist 3927221Speter * propagate: 3937221Speter * printflag as the union of parents' printflags 3947221Speter * propfraction as the sum of fractional parents' propfractions 3957221Speter * and while we're here, sum time for functions. 3967172Speter */ 3977172Speter doflags() 3987172Speter { 3997172Speter int index; 4007172Speter nltype *childp; 4017172Speter nltype *oldhead; 4027172Speter 4037172Speter oldhead = 0; 4047172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 4057172Speter childp = topsortnlp[ index ]; 4067172Speter /* 4077172Speter * if we haven't done this function or cycle, 4087221Speter * inherit things from parent. 4097172Speter * this way, we are linear in the number of arcs 4107172Speter * since we do all members of a cycle (and the cycle itself) 4117172Speter * as we hit the first member of the cycle. 4127172Speter */ 4137172Speter if ( childp -> cyclehead != oldhead ) { 4147172Speter oldhead = childp -> cyclehead; 4157221Speter inheritflags( childp ); 4167172Speter } 4177221Speter # ifdef DEBUG 4187221Speter if ( debug & PROPDEBUG ) { 4197221Speter printf( "[doflags] " ); 4207221Speter printname( childp ); 4217221Speter printf( " inherits printflag %d and propfraction %f\n" , 4227221Speter childp -> printflag , childp -> propfraction ); 4237221Speter } 4247221Speter # endif DEBUG 4257172Speter if ( ! childp -> printflag ) { 4267172Speter /* 4277221Speter * printflag is off 4287221Speter * it gets turned on by 4297221Speter * being on -f list, 4307221Speter * or there not being any -f list and not being on -e list. 4317172Speter */ 4327221Speter if ( onlist( flist , childp -> name ) 4337221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4347172Speter childp -> printflag = TRUE; 4357172Speter } 4367221Speter } else { 4377221Speter /* 4387221Speter * this function has printing parents: 4397221Speter * maybe someone wants to shut it up 4407221Speter * by putting it on -e list. (but favor -f over -e) 4417221Speter */ 4427221Speter if ( ( !onlist( flist , childp -> name ) ) 4437221Speter && onlist( elist , childp -> name ) ) { 4447221Speter childp -> printflag = FALSE; 4457172Speter } 4467221Speter } 4477221Speter if ( childp -> propfraction == 0.0 ) { 4487221Speter /* 4497221Speter * no parents to pass time to. 4507221Speter * collect time from children if 4517221Speter * its on -F list, 4527221Speter * or there isn't any -F list and its not on -E list. 4537221Speter */ 4547221Speter if ( onlist( Flist , childp -> name ) 4557221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 4567221Speter childp -> propfraction = 1.0; 4577172Speter } 4587221Speter } else { 4597221Speter /* 4607221Speter * it has parents to pass time to, 4617221Speter * but maybe someone wants to shut it up 4627221Speter * by puttting it on -E list. (but favor -F over -E) 4637221Speter */ 4647221Speter if ( !onlist( Flist , childp -> name ) 4657221Speter && onlist( Elist , childp -> name ) ) { 4667221Speter childp -> propfraction = 0.0; 4677221Speter } 4687172Speter } 4697221Speter childp -> propself = childp -> time * childp -> propfraction; 4707221Speter printtime += childp -> propself; 4717221Speter # ifdef DEBUG 4727221Speter if ( debug & PROPDEBUG ) { 4737221Speter printf( "[doflags] " ); 4747221Speter printname( childp ); 4757221Speter printf( " ends up with printflag %d and propfraction %f\n" , 4767221Speter childp -> printflag , childp -> propfraction ); 4778908Speter printf( "time %f propself %f printtime %f\n" , 4788908Speter childp -> time , childp -> propself , printtime ); 4797221Speter } 4807221Speter # endif DEBUG 4817172Speter } 4827172Speter } 4837172Speter 4847172Speter /* 4857172Speter * check if any parent of this child 4867172Speter * (or outside parents of this cycle) 4877172Speter * have their print flags on and set the 4887172Speter * print flag of the child (cycle) appropriately. 4897221Speter * similarly, deal with propagation fractions from parents. 4907172Speter */ 4917221Speter inheritflags( childp ) 4927172Speter nltype *childp; 4937172Speter { 4947172Speter nltype *headp; 4957221Speter arctype *arcp; 4967221Speter nltype *parentp; 4977172Speter nltype *memp; 4987172Speter 4997172Speter headp = childp -> cyclehead; 5007172Speter if ( childp == headp ) { 5017172Speter /* 5027172Speter * just a regular child, check its parents 5037172Speter */ 5047221Speter childp -> printflag = FALSE; 5057221Speter childp -> propfraction = 0.0; 5067221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 5077221Speter parentp = arcp -> arc_parentp; 5088908Speter if ( childp == parentp ) { 5098908Speter continue; 5108908Speter } 5117221Speter childp -> printflag |= parentp -> printflag; 51214140Speter /* 51314140Speter * if the child was never actually called 51414140Speter * (e.g. this arc is static (and all others are, too)) 51514140Speter * no time propagates along this arc. 51614140Speter */ 51714140Speter if ( childp -> ncall ) { 51814140Speter childp -> propfraction += parentp -> propfraction 51914140Speter * ( ( (double) arcp -> arc_count ) 52014140Speter / ( (double) childp -> ncall ) ); 52114140Speter } 5227172Speter } 5237221Speter } else { 5247221Speter /* 5257221Speter * its a member of a cycle, look at all parents from 5267221Speter * outside the cycle 5277221Speter */ 5287221Speter headp -> printflag = FALSE; 5297221Speter headp -> propfraction = 0.0; 5307221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 5317221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 5327221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 5337221Speter continue; 5347221Speter } 5357221Speter parentp = arcp -> arc_parentp; 5367221Speter headp -> printflag |= parentp -> printflag; 53714140Speter /* 53814140Speter * if the cycle was never actually called 53914140Speter * (e.g. this arc is static (and all others are, too)) 54014140Speter * no time propagates along this arc. 54114140Speter */ 54214140Speter if ( headp -> ncall ) { 54314140Speter headp -> propfraction += parentp -> propfraction 54414140Speter * ( ( (double) arcp -> arc_count ) 54514140Speter / ( (double) headp -> ncall ) ); 54614140Speter } 5477172Speter } 5487172Speter } 5497221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 5507221Speter memp -> printflag = headp -> printflag; 5517221Speter memp -> propfraction = headp -> propfraction; 5527221Speter } 5537172Speter } 5547172Speter } 555