121957Sdist /* 221957Sdist * Copyright (c) 1983 Regents of the University of California. 3*34199Sbostic * All rights reserved. 4*34199Sbostic * 5*34199Sbostic * Redistribution and use in source and binary forms are permitted 6*34199Sbostic * provided that this notice is preserved and that due credit is given 7*34199Sbostic * to the University of California at Berkeley. The name of the University 8*34199Sbostic * may not be used to endorse or promote products derived from this 9*34199Sbostic * software without specific prior written permission. This software 10*34199Sbostic * is provided ``as is'' without express or implied warranty. 1121957Sdist */ 1221957Sdist 134508Speter #ifndef lint 14*34199Sbostic static char sccsid[] = "@(#)arcs.c 5.4 (Berkeley) 05/05/88"; 15*34199Sbostic #endif /* not lint */ 164508Speter 174561Speter #include "gprof.h" 184508Speter 194721Speter /* 204721Speter * add (or just increment) an arc 214721Speter */ 224721Speter addarc( parentp , childp , count ) 234721Speter nltype *parentp; 244721Speter nltype *childp; 254721Speter long count; 264721Speter { 274750Speter arctype *calloc(); 284721Speter arctype *arcp; 294721Speter 304721Speter # ifdef DEBUG 314721Speter if ( debug & TALLYDEBUG ) { 324721Speter printf( "[addarc] %d arcs from %s to %s\n" , 334721Speter count , parentp -> name , childp -> name ); 344721Speter } 354721Speter # endif DEBUG 364721Speter arcp = arclookup( parentp , childp ); 374721Speter if ( arcp != 0 ) { 384721Speter /* 394721Speter * a hit: just increment the count. 404721Speter */ 414721Speter # ifdef DEBUG 424721Speter if ( debug & TALLYDEBUG ) { 434721Speter printf( "[tally] hit %d += %d\n" , 444721Speter arcp -> arc_count , count ); 454721Speter } 464721Speter # endif DEBUG 474721Speter arcp -> arc_count += count; 484721Speter return; 494721Speter } 504750Speter arcp = calloc( 1 , sizeof *arcp ); 514721Speter arcp -> arc_parentp = parentp; 524721Speter arcp -> arc_childp = childp; 534721Speter arcp -> arc_count = count; 544721Speter /* 554721Speter * prepend this child to the children of this parent 564721Speter */ 574721Speter arcp -> arc_childlist = parentp -> children; 584721Speter parentp -> children = arcp; 594721Speter /* 604721Speter * prepend this parent to the parents of this child 614721Speter */ 624721Speter arcp -> arc_parentlist = childp -> parents; 634721Speter childp -> parents = arcp; 644721Speter } 654721Speter 667172Speter /* 677172Speter * the code below topologically sorts the graph (collapsing cycles), 687172Speter * and propagates time bottom up and flags top down. 697172Speter */ 707172Speter 717172Speter /* 727172Speter * the topologically sorted name list pointers 737172Speter */ 747172Speter nltype **topsortnlp; 757172Speter 764508Speter topcmp( npp1 , npp2 ) 774508Speter nltype **npp1; 784508Speter nltype **npp2; 794508Speter { 804508Speter return (*npp1) -> toporder - (*npp2) -> toporder; 814508Speter } 824508Speter 8316850Smckusick nltype ** 844508Speter doarcs() 854508Speter { 8616850Smckusick nltype *parentp, **timesortnlp; 874508Speter arctype *arcp; 884508Speter long index; 894508Speter 904508Speter /* 914508Speter * initialize various things: 924508Speter * zero out child times. 934508Speter * count self-recursive calls. 944508Speter * indicate that nothing is on cycles. 954508Speter */ 964508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 974508Speter parentp -> childtime = 0.0; 984508Speter arcp = arclookup( parentp , parentp ); 994508Speter if ( arcp != 0 ) { 1004508Speter parentp -> ncall -= arcp -> arc_count; 1014508Speter parentp -> selfcalls = arcp -> arc_count; 1024508Speter } else { 1034508Speter parentp -> selfcalls = 0; 1044508Speter } 1057221Speter parentp -> propfraction = 0.0; 1067221Speter parentp -> propself = 0.0; 1077221Speter parentp -> propchild = 0.0; 1087172Speter parentp -> printflag = FALSE; 10910284Speter parentp -> toporder = DFN_NAN; 1104508Speter parentp -> cycleno = 0; 1114508Speter parentp -> cyclehead = parentp; 1124508Speter parentp -> cnext = 0; 1137172Speter if ( cflag ) { 11425713Ssam findcall( parentp , parentp -> value , (parentp+1) -> value ); 1157172Speter } 1164508Speter } 1174508Speter /* 1184508Speter * topologically order things 11910284Speter * if any node is unnumbered, 12010284Speter * number it and any of its descendents. 1214508Speter */ 1224508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 12310284Speter if ( parentp -> toporder == DFN_NAN ) { 1244508Speter dfn( parentp ); 1254508Speter } 1264508Speter } 1274508Speter /* 1284508Speter * link together nodes on the same cycle 1294508Speter */ 1304508Speter cyclelink(); 1314508Speter /* 1324508Speter * Sort the symbol table in reverse topological order 1334508Speter */ 1344508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1354508Speter if ( topsortnlp == (nltype **) 0 ) { 1364508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1374508Speter } 1384508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1394508Speter topsortnlp[ index ] = &nl[ index ]; 1404508Speter } 1414508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1424508Speter # ifdef DEBUG 1434508Speter if ( debug & DFNDEBUG ) { 1444508Speter printf( "[doarcs] topological sort listing\n" ); 1454508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1464508Speter printf( "[doarcs] " ); 1474508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1484508Speter printname( topsortnlp[ index ] ); 1494508Speter printf( "\n" ); 1504508Speter } 1514508Speter } 1524508Speter # endif DEBUG 1534508Speter /* 1547221Speter * starting from the topological top, 1557221Speter * propagate print flags to children. 1567221Speter * also, calculate propagation fractions. 1577221Speter * this happens before time propagation 1587221Speter * since time propagation uses the fractions. 1597221Speter */ 1607221Speter doflags(); 1617221Speter /* 1624508Speter * starting from the topological bottom, 1637172Speter * propogate children times up to parents. 1644508Speter */ 1657172Speter dotime(); 16616850Smckusick /* 16716850Smckusick * Now, sort by propself + propchild. 16816850Smckusick * sorting both the regular function names 16916850Smckusick * and cycle headers. 17016850Smckusick */ 17116850Smckusick timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 17216850Smckusick if ( timesortnlp == (nltype **) 0 ) { 17316850Smckusick fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 17416850Smckusick } 17516850Smckusick for ( index = 0 ; index < nname ; index++ ) { 17616850Smckusick timesortnlp[index] = &nl[index]; 17716850Smckusick } 17816850Smckusick for ( index = 1 ; index <= ncycle ; index++ ) { 17916850Smckusick timesortnlp[nname+index-1] = &cyclenl[index]; 18016850Smckusick } 18116850Smckusick qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); 18216850Smckusick for ( index = 0 ; index < nname + ncycle ; index++ ) { 18316850Smckusick timesortnlp[ index ] -> index = index + 1; 18416850Smckusick } 18516850Smckusick return( timesortnlp ); 1867172Speter } 1877172Speter 1887172Speter dotime() 1897172Speter { 1907172Speter int index; 1917172Speter 1927172Speter cycletime(); 1934508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1947172Speter timepropagate( topsortnlp[ index ] ); 1957127Speter } 1967127Speter } 1977127Speter 1987172Speter timepropagate( parentp ) 1997127Speter nltype *parentp; 2007127Speter { 2017127Speter arctype *arcp; 2027127Speter nltype *childp; 2037127Speter double share; 2047221Speter double propshare; 2057127Speter 2067221Speter if ( parentp -> propfraction == 0.0 ) { 2077221Speter return; 2087221Speter } 2097127Speter /* 2107127Speter * gather time from children of this parent. 2117127Speter */ 2127172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 2137127Speter childp = arcp -> arc_childp; 2147127Speter if ( arcp -> arc_count == 0 ) { 2157127Speter continue; 2167127Speter } 2177221Speter if ( childp == parentp ) { 2187127Speter continue; 2197127Speter } 2207221Speter if ( childp -> propfraction == 0.0 ) { 2217127Speter continue; 2227127Speter } 2237127Speter if ( childp -> cyclehead != childp ) { 2247127Speter if ( parentp -> cycleno == childp -> cycleno ) { 2257127Speter continue; 2267127Speter } 2277127Speter if ( parentp -> toporder <= childp -> toporder ) { 2287127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2294508Speter } 2307127Speter childp = childp -> cyclehead; 2317127Speter } else { 2327127Speter if ( parentp -> toporder <= childp -> toporder ) { 2337127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2344508Speter continue; 2354508Speter } 2367127Speter } 2377221Speter if ( childp -> ncall == 0 ) { 2387221Speter continue; 2397221Speter } 2407127Speter /* 2417127Speter * distribute time for this arc 2427127Speter */ 2437221Speter arcp -> arc_time = childp -> time 2447221Speter * ( ( (double) arcp -> arc_count ) / 2457221Speter ( (double) childp -> ncall ) ); 2467221Speter arcp -> arc_childtime = childp -> childtime 2477221Speter * ( ( (double) arcp -> arc_count ) / 2487221Speter ( (double) childp -> ncall ) ); 2497127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2507127Speter parentp -> childtime += share; 2517127Speter /* 2527221Speter * ( 1 - propfraction ) gets lost along the way 2537127Speter */ 2547221Speter propshare = parentp -> propfraction * share; 2557221Speter /* 2567221Speter * fix things for printing 2577221Speter */ 2587221Speter parentp -> propchild += propshare; 2597221Speter arcp -> arc_time *= parentp -> propfraction; 2607221Speter arcp -> arc_childtime *= parentp -> propfraction; 2617221Speter /* 2627221Speter * add this share to the parent's cycle header, if any. 2637221Speter */ 2647127Speter if ( parentp -> cyclehead != parentp ) { 2657127Speter parentp -> cyclehead -> childtime += share; 2667221Speter parentp -> cyclehead -> propchild += propshare; 2674508Speter } 2687221Speter # ifdef DEBUG 2697221Speter if ( debug & PROPDEBUG ) { 2707221Speter printf( "[dotime] child \t" ); 2717221Speter printname( childp ); 2727221Speter printf( " with %f %f %d/%d\n" , 2737221Speter childp -> time , childp -> childtime , 2747221Speter arcp -> arc_count , childp -> ncall ); 2757221Speter printf( "[dotime] parent\t" ); 2767221Speter printname( parentp ); 2777221Speter printf( "\n[dotime] share %f\n" , share ); 2787221Speter } 2797221Speter # endif DEBUG 2804508Speter } 2814508Speter } 2824508Speter 2834508Speter cyclelink() 2844508Speter { 2854508Speter register nltype *nlp; 2864508Speter register nltype *cyclenlp; 2874508Speter int cycle; 2887172Speter nltype *memberp; 2897248Speter arctype *arcp; 2904508Speter 2914508Speter /* 2924508Speter * Count the number of cycles, and initialze the cycle lists 2934508Speter */ 2947127Speter ncycle = 0; 2954508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2964508Speter /* 2974508Speter * this is how you find unattached cycles 2984508Speter */ 2994508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 3007127Speter ncycle += 1; 3014508Speter } 3024508Speter } 3037127Speter /* 3047127Speter * cyclenl is indexed by cycle number: 3057127Speter * i.e. it is origin 1, not origin 0. 3067127Speter */ 3077127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 3087127Speter if ( cyclenl == 0 ) { 3097127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 3107127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 3117127Speter done(); 3124508Speter } 3134508Speter /* 3144508Speter * now link cycles to true cycleheads, 3154508Speter * number them, accumulate the data for the cycle 3164508Speter */ 3174508Speter cycle = 0; 3184508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 31910284Speter if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 3204508Speter continue; 3214508Speter } 3224508Speter cycle += 1; 3237127Speter cyclenlp = &cyclenl[cycle]; 3247249Speter cyclenlp -> name = 0; /* the name */ 3257221Speter cyclenlp -> value = 0; /* the pc entry point */ 3267221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 3277221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 3287221Speter cyclenlp -> ncall = 0; /* how many times called */ 3297221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 3307221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 3317221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 3327221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 3337221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 3347221Speter cyclenlp -> index = 0; /* index in the graph list */ 33510284Speter cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 3367221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 3377221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 3387221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 3397221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 3407221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3414508Speter # ifdef DEBUG 3424508Speter if ( debug & CYCLEDEBUG ) { 3434508Speter printf( "[cyclelink] " ); 3444508Speter printname( nlp ); 3454508Speter printf( " is the head of cycle %d\n" , cycle ); 3464508Speter } 3474508Speter # endif DEBUG 3487248Speter /* 3497248Speter * link members to cycle header 3507248Speter */ 3517172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3527172Speter memberp -> cycleno = cycle; 3537172Speter memberp -> cyclehead = cyclenlp; 3547172Speter } 3557248Speter /* 3567248Speter * count calls from outside the cycle 3577248Speter * and those among cycle members 3587248Speter */ 3597248Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3607248Speter for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 3617248Speter if ( arcp -> arc_parentp == memberp ) { 3627248Speter continue; 3637248Speter } 3647248Speter if ( arcp -> arc_parentp -> cycleno == cycle ) { 3657248Speter cyclenlp -> selfcalls += arcp -> arc_count; 3667248Speter } else { 3677248Speter cyclenlp -> ncall += arcp -> arc_count; 3687248Speter } 3697248Speter } 3707248Speter } 3717172Speter } 3727172Speter } 3737172Speter 3747172Speter cycletime() 3757172Speter { 3767172Speter int cycle; 3777172Speter nltype *cyclenlp; 3787172Speter nltype *childp; 3797172Speter 3807172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3817172Speter cyclenlp = &cyclenl[ cycle ]; 3827221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 3837221Speter if ( childp -> propfraction == 0.0 ) { 3847221Speter /* 3857221Speter * all members have the same propfraction except those 3867221Speter * that were excluded with -E 3877221Speter */ 3887221Speter continue; 3897221Speter } 3907221Speter cyclenlp -> time += childp -> time; 3914508Speter } 3927221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3934508Speter } 3944508Speter } 3957172Speter 3967172Speter /* 3977172Speter * in one top to bottom pass over the topologically sorted namelist 3987221Speter * propagate: 3997221Speter * printflag as the union of parents' printflags 4007221Speter * propfraction as the sum of fractional parents' propfractions 4017221Speter * and while we're here, sum time for functions. 4027172Speter */ 4037172Speter doflags() 4047172Speter { 4057172Speter int index; 4067172Speter nltype *childp; 4077172Speter nltype *oldhead; 4087172Speter 4097172Speter oldhead = 0; 4107172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 4117172Speter childp = topsortnlp[ index ]; 4127172Speter /* 4137172Speter * if we haven't done this function or cycle, 4147221Speter * inherit things from parent. 4157172Speter * this way, we are linear in the number of arcs 4167172Speter * since we do all members of a cycle (and the cycle itself) 4177172Speter * as we hit the first member of the cycle. 4187172Speter */ 4197172Speter if ( childp -> cyclehead != oldhead ) { 4207172Speter oldhead = childp -> cyclehead; 4217221Speter inheritflags( childp ); 4227172Speter } 4237221Speter # ifdef DEBUG 4247221Speter if ( debug & PROPDEBUG ) { 4257221Speter printf( "[doflags] " ); 4267221Speter printname( childp ); 4277221Speter printf( " inherits printflag %d and propfraction %f\n" , 4287221Speter childp -> printflag , childp -> propfraction ); 4297221Speter } 4307221Speter # endif DEBUG 4317172Speter if ( ! childp -> printflag ) { 4327172Speter /* 4337221Speter * printflag is off 4347221Speter * it gets turned on by 4357221Speter * being on -f list, 4367221Speter * or there not being any -f list and not being on -e list. 4377172Speter */ 4387221Speter if ( onlist( flist , childp -> name ) 4397221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4407172Speter childp -> printflag = TRUE; 4417172Speter } 4427221Speter } else { 4437221Speter /* 4447221Speter * this function has printing parents: 4457221Speter * maybe someone wants to shut it up 4467221Speter * by putting it on -e list. (but favor -f over -e) 4477221Speter */ 4487221Speter if ( ( !onlist( flist , childp -> name ) ) 4497221Speter && onlist( elist , childp -> name ) ) { 4507221Speter childp -> printflag = FALSE; 4517172Speter } 4527221Speter } 4537221Speter if ( childp -> propfraction == 0.0 ) { 4547221Speter /* 4557221Speter * no parents to pass time to. 4567221Speter * collect time from children if 4577221Speter * its on -F list, 4587221Speter * or there isn't any -F list and its not on -E list. 4597221Speter */ 4607221Speter if ( onlist( Flist , childp -> name ) 4617221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 4627221Speter childp -> propfraction = 1.0; 4637172Speter } 4647221Speter } else { 4657221Speter /* 4667221Speter * it has parents to pass time to, 4677221Speter * but maybe someone wants to shut it up 4687221Speter * by puttting it on -E list. (but favor -F over -E) 4697221Speter */ 4707221Speter if ( !onlist( Flist , childp -> name ) 4717221Speter && onlist( Elist , childp -> name ) ) { 4727221Speter childp -> propfraction = 0.0; 4737221Speter } 4747172Speter } 4757221Speter childp -> propself = childp -> time * childp -> propfraction; 4767221Speter printtime += childp -> propself; 4777221Speter # ifdef DEBUG 4787221Speter if ( debug & PROPDEBUG ) { 4797221Speter printf( "[doflags] " ); 4807221Speter printname( childp ); 4817221Speter printf( " ends up with printflag %d and propfraction %f\n" , 4827221Speter childp -> printflag , childp -> propfraction ); 4838908Speter printf( "time %f propself %f printtime %f\n" , 4848908Speter childp -> time , childp -> propself , printtime ); 4857221Speter } 4867221Speter # endif DEBUG 4877172Speter } 4887172Speter } 4897172Speter 4907172Speter /* 4917172Speter * check if any parent of this child 4927172Speter * (or outside parents of this cycle) 4937172Speter * have their print flags on and set the 4947172Speter * print flag of the child (cycle) appropriately. 4957221Speter * similarly, deal with propagation fractions from parents. 4967172Speter */ 4977221Speter inheritflags( childp ) 4987172Speter nltype *childp; 4997172Speter { 5007172Speter nltype *headp; 5017221Speter arctype *arcp; 5027221Speter nltype *parentp; 5037172Speter nltype *memp; 5047172Speter 5057172Speter headp = childp -> cyclehead; 5067172Speter if ( childp == headp ) { 5077172Speter /* 5087172Speter * just a regular child, check its parents 5097172Speter */ 5107221Speter childp -> printflag = FALSE; 5117221Speter childp -> propfraction = 0.0; 5127221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 5137221Speter parentp = arcp -> arc_parentp; 5148908Speter if ( childp == parentp ) { 5158908Speter continue; 5168908Speter } 5177221Speter childp -> printflag |= parentp -> printflag; 51814140Speter /* 51914140Speter * if the child was never actually called 52014140Speter * (e.g. this arc is static (and all others are, too)) 52114140Speter * no time propagates along this arc. 52214140Speter */ 52314140Speter if ( childp -> ncall ) { 52414140Speter childp -> propfraction += parentp -> propfraction 52514140Speter * ( ( (double) arcp -> arc_count ) 52614140Speter / ( (double) childp -> ncall ) ); 52714140Speter } 5287172Speter } 5297221Speter } else { 5307221Speter /* 5317221Speter * its a member of a cycle, look at all parents from 5327221Speter * outside the cycle 5337221Speter */ 5347221Speter headp -> printflag = FALSE; 5357221Speter headp -> propfraction = 0.0; 5367221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 5377221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 5387221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 5397221Speter continue; 5407221Speter } 5417221Speter parentp = arcp -> arc_parentp; 5427221Speter headp -> printflag |= parentp -> printflag; 54314140Speter /* 54414140Speter * if the cycle was never actually called 54514140Speter * (e.g. this arc is static (and all others are, too)) 54614140Speter * no time propagates along this arc. 54714140Speter */ 54814140Speter if ( headp -> ncall ) { 54914140Speter headp -> propfraction += parentp -> propfraction 55014140Speter * ( ( (double) arcp -> arc_count ) 55114140Speter / ( (double) headp -> ncall ) ); 55214140Speter } 5537172Speter } 5547172Speter } 5557221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 5567221Speter memp -> printflag = headp -> printflag; 5577221Speter memp -> propfraction = headp -> propfraction; 5587221Speter } 5597172Speter } 5607172Speter } 561