14508Speter #ifndef lint 2*7221Speter static char *sccsid = "@(#)arcs.c 1.8 (Berkeley) 06/18/82"; 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 } 92*7221Speter parentp -> propfraction = 0.0; 93*7221Speter parentp -> propself = 0.0; 94*7221Speter parentp -> propchild = 0.0; 957172Speter parentp -> printflag = FALSE; 964508Speter parentp -> toporder = 0; 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 1064508Speter * from each of the roots of the call graph 1074508Speter */ 1084508Speter for ( parentp = nl ; parentp < npe ; parentp++ ) { 1094508Speter if ( parentp -> parents == 0 ) { 1104508Speter dfn( parentp ); 1114508Speter } 1124508Speter } 1134508Speter /* 1144508Speter * link together nodes on the same cycle 1154508Speter */ 1164508Speter cyclelink(); 1174508Speter /* 1184508Speter * Sort the symbol table in reverse topological order 1194508Speter */ 1204508Speter topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 1214508Speter if ( topsortnlp == (nltype **) 0 ) { 1224508Speter fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 1234508Speter } 1244508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1254508Speter topsortnlp[ index ] = &nl[ index ]; 1264508Speter } 1274508Speter qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 1284508Speter # ifdef DEBUG 1294508Speter if ( debug & DFNDEBUG ) { 1304508Speter printf( "[doarcs] topological sort listing\n" ); 1314508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1324508Speter printf( "[doarcs] " ); 1334508Speter printf( "%d:" , topsortnlp[ index ] -> toporder ); 1344508Speter printname( topsortnlp[ index ] ); 1354508Speter printf( "\n" ); 1364508Speter } 1374508Speter } 1384508Speter # endif DEBUG 1394508Speter /* 140*7221Speter * starting from the topological top, 141*7221Speter * propagate print flags to children. 142*7221Speter * also, calculate propagation fractions. 143*7221Speter * this happens before time propagation 144*7221Speter * since time propagation uses the fractions. 145*7221Speter */ 146*7221Speter doflags(); 147*7221Speter /* 1484508Speter * starting from the topological bottom, 1497172Speter * propogate children times up to parents. 1504508Speter */ 1517172Speter dotime(); 1527172Speter printgprof(); 1537172Speter } 1547172Speter 1557172Speter dotime() 1567172Speter { 1577172Speter int index; 1587172Speter 1597172Speter cycletime(); 1604508Speter for ( index = 0 ; index < nname ; index += 1 ) { 1617172Speter timepropagate( topsortnlp[ index ] ); 1627127Speter } 1637127Speter } 1647127Speter 1657172Speter timepropagate( parentp ) 1667127Speter nltype *parentp; 1677127Speter { 1687127Speter arctype *arcp; 1697127Speter nltype *childp; 1707127Speter double share; 171*7221Speter double propshare; 1727127Speter 173*7221Speter if ( parentp -> propfraction == 0.0 ) { 174*7221Speter return; 175*7221Speter } 1767127Speter /* 1777127Speter * gather time from children of this parent. 1787127Speter */ 1797172Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 1807127Speter childp = arcp -> arc_childp; 1817127Speter if ( arcp -> arc_count == 0 ) { 1827127Speter continue; 1837127Speter } 184*7221Speter if ( childp == parentp ) { 1857127Speter continue; 1867127Speter } 187*7221Speter if ( childp -> propfraction == 0.0 ) { 1887127Speter continue; 1897127Speter } 1907127Speter if ( childp -> cyclehead != childp ) { 1917127Speter if ( parentp -> cycleno == childp -> cycleno ) { 1927127Speter continue; 1937127Speter } 1947127Speter if ( parentp -> toporder <= childp -> toporder ) { 1957127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 1964508Speter } 1977127Speter childp = childp -> cyclehead; 1987127Speter } else { 1997127Speter if ( parentp -> toporder <= childp -> toporder ) { 2007127Speter fprintf( stderr , "[propagate] toporder botches\n" ); 2014508Speter continue; 2024508Speter } 2037127Speter } 204*7221Speter if ( childp -> ncall == 0 ) { 205*7221Speter continue; 206*7221Speter } 2077127Speter /* 2087127Speter * distribute time for this arc 2097127Speter */ 210*7221Speter arcp -> arc_time = childp -> time 211*7221Speter * ( ( (double) arcp -> arc_count ) / 212*7221Speter ( (double) childp -> ncall ) ); 213*7221Speter arcp -> arc_childtime = childp -> childtime 214*7221Speter * ( ( (double) arcp -> arc_count ) / 215*7221Speter ( (double) childp -> ncall ) ); 2167127Speter share = arcp -> arc_time + arcp -> arc_childtime; 2177127Speter parentp -> childtime += share; 2187127Speter /* 219*7221Speter * ( 1 - propfraction ) gets lost along the way 2207127Speter */ 221*7221Speter propshare = parentp -> propfraction * share; 222*7221Speter /* 223*7221Speter * fix things for printing 224*7221Speter */ 225*7221Speter parentp -> propchild += propshare; 226*7221Speter arcp -> arc_time *= parentp -> propfraction; 227*7221Speter arcp -> arc_childtime *= parentp -> propfraction; 228*7221Speter /* 229*7221Speter * add this share to the parent's cycle header, if any. 230*7221Speter */ 2317127Speter if ( parentp -> cyclehead != parentp ) { 2327127Speter parentp -> cyclehead -> childtime += share; 233*7221Speter parentp -> cyclehead -> propchild += propshare; 2344508Speter } 235*7221Speter # ifdef DEBUG 236*7221Speter if ( debug & PROPDEBUG ) { 237*7221Speter printf( "[dotime] child \t" ); 238*7221Speter printname( childp ); 239*7221Speter printf( " with %f %f %d/%d\n" , 240*7221Speter childp -> time , childp -> childtime , 241*7221Speter arcp -> arc_count , childp -> ncall ); 242*7221Speter printf( "[dotime] parent\t" ); 243*7221Speter printname( parentp ); 244*7221Speter printf( "\n[dotime] share %f\n" , share ); 245*7221Speter } 246*7221Speter # endif DEBUG 2474508Speter } 2484508Speter } 2494508Speter 2504508Speter cyclelink() 2514508Speter { 2524508Speter register nltype *nlp; 2534508Speter register nltype *cyclenlp; 2544508Speter int cycle; 2557172Speter nltype *memberp; 2564508Speter 2574508Speter /* 2584508Speter * Count the number of cycles, and initialze the cycle lists 2594508Speter */ 2607127Speter ncycle = 0; 2614508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2624508Speter /* 2634508Speter * this is how you find unattached cycles 2644508Speter */ 2654508Speter if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 2667127Speter ncycle += 1; 2674508Speter } 2684508Speter } 2697127Speter /* 2707127Speter * cyclenl is indexed by cycle number: 2717127Speter * i.e. it is origin 1, not origin 0. 2727127Speter */ 2737127Speter cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 2747127Speter if ( cyclenl == 0 ) { 2757127Speter fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 2767127Speter whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 2777127Speter done(); 2784508Speter } 2794508Speter /* 2804508Speter * now link cycles to true cycleheads, 2814508Speter * number them, accumulate the data for the cycle 2824508Speter */ 2834508Speter cycle = 0; 2844508Speter for ( nlp = nl ; nlp < npe ; nlp++ ) { 2854508Speter if ( nlp -> cyclehead != nlp || nlp -> cnext == 0 ) { 2864508Speter continue; 2874508Speter } 2884508Speter cycle += 1; 2897127Speter cyclenlp = &cyclenl[cycle]; 290*7221Speter cyclenlp -> name = ""; /* the name */ 291*7221Speter cyclenlp -> value = 0; /* the pc entry point */ 292*7221Speter cyclenlp -> time = 0.0; /* ticks in this routine */ 293*7221Speter cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 294*7221Speter cyclenlp -> ncall = 0; /* how many times called */ 295*7221Speter cyclenlp -> selfcalls = 0; /* how many calls to self */ 296*7221Speter cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 297*7221Speter cyclenlp -> propself = 0.0; /* how much self time propagates */ 298*7221Speter cyclenlp -> propchild = 0.0; /* how much child time propagates */ 299*7221Speter cyclenlp -> printflag = TRUE; /* should this be printed? */ 300*7221Speter cyclenlp -> index = 0; /* index in the graph list */ 301*7221Speter cyclenlp -> toporder = 0; /* graph call chain top-sort order */ 302*7221Speter cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 303*7221Speter cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 304*7221Speter cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 305*7221Speter cyclenlp -> parents = 0; /* list of caller arcs */ 306*7221Speter cyclenlp -> children = 0; /* list of callee arcs */ 3074508Speter # ifdef DEBUG 3084508Speter if ( debug & CYCLEDEBUG ) { 3094508Speter printf( "[cyclelink] " ); 3104508Speter printname( nlp ); 3114508Speter printf( " is the head of cycle %d\n" , cycle ); 3124508Speter } 3134508Speter # endif DEBUG 3147172Speter for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 3157172Speter memberp -> cycleno = cycle; 3167172Speter memberp -> cyclehead = cyclenlp; 3177172Speter } 3187172Speter } 3197172Speter } 3207172Speter 3217172Speter cycletime() 3227172Speter { 3237172Speter int cycle; 3247172Speter nltype *cyclenlp; 3257172Speter nltype *childp; 3267172Speter arctype *arcp; 327*7221Speter nltype *parentp; 3287172Speter 3297172Speter for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 3307172Speter cyclenlp = &cyclenl[ cycle ]; 331*7221Speter for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 332*7221Speter if ( childp -> propfraction == 0.0 ) { 333*7221Speter /* 334*7221Speter * all members have the same propfraction except those 335*7221Speter * that were excluded with -E 336*7221Speter */ 337*7221Speter continue; 338*7221Speter } 339*7221Speter cyclenlp -> time += childp -> time; 340*7221Speter for ( arcp=childp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 341*7221Speter parentp = arcp -> arc_parentp; 3424508Speter if ( parentp == childp ) { 3434508Speter continue; 3444508Speter } 345*7221Speter if ( parentp -> cyclehead == cyclenlp ) { 346*7221Speter cyclenlp -> selfcalls += arcp -> arc_count; 347*7221Speter } else { 348*7221Speter cyclenlp -> ncall += arcp -> arc_count; 3494508Speter } 3504508Speter } 3514508Speter } 352*7221Speter cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 3534508Speter } 3544508Speter } 3557172Speter 3567172Speter /* 3577172Speter * in one top to bottom pass over the topologically sorted namelist 358*7221Speter * propagate: 359*7221Speter * printflag as the union of parents' printflags 360*7221Speter * propfraction as the sum of fractional parents' propfractions 361*7221Speter * and while we're here, sum time for functions. 3627172Speter */ 3637172Speter doflags() 3647172Speter { 3657172Speter int index; 3667172Speter nltype *childp; 3677172Speter nltype *oldhead; 3687172Speter 3697172Speter oldhead = 0; 3707172Speter for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 3717172Speter childp = topsortnlp[ index ]; 3727172Speter /* 3737172Speter * if we haven't done this function or cycle, 374*7221Speter * inherit things from parent. 3757172Speter * this way, we are linear in the number of arcs 3767172Speter * since we do all members of a cycle (and the cycle itself) 3777172Speter * as we hit the first member of the cycle. 3787172Speter */ 3797172Speter if ( childp -> cyclehead != oldhead ) { 3807172Speter oldhead = childp -> cyclehead; 381*7221Speter inheritflags( childp ); 3827172Speter } 383*7221Speter # ifdef DEBUG 384*7221Speter if ( debug & PROPDEBUG ) { 385*7221Speter printf( "[doflags] " ); 386*7221Speter printname( childp ); 387*7221Speter printf( " inherits printflag %d and propfraction %f\n" , 388*7221Speter childp -> printflag , childp -> propfraction ); 389*7221Speter } 390*7221Speter # endif DEBUG 3917172Speter if ( ! childp -> printflag ) { 3927172Speter /* 393*7221Speter * printflag is off 394*7221Speter * it gets turned on by 395*7221Speter * being on -f list, 396*7221Speter * or there not being any -f list and not being on -e list. 3977172Speter */ 398*7221Speter if ( onlist( flist , childp -> name ) 399*7221Speter || ( !fflag && !onlist( elist , childp -> name ) ) ) { 4007172Speter childp -> printflag = TRUE; 4017172Speter } 402*7221Speter } else { 403*7221Speter /* 404*7221Speter * this function has printing parents: 405*7221Speter * maybe someone wants to shut it up 406*7221Speter * by putting it on -e list. (but favor -f over -e) 407*7221Speter */ 408*7221Speter if ( ( !onlist( flist , childp -> name ) ) 409*7221Speter && onlist( elist , childp -> name ) ) { 410*7221Speter childp -> printflag = FALSE; 4117172Speter } 412*7221Speter } 413*7221Speter if ( childp -> propfraction == 0.0 ) { 414*7221Speter /* 415*7221Speter * no parents to pass time to. 416*7221Speter * collect time from children if 417*7221Speter * its on -F list, 418*7221Speter * or there isn't any -F list and its not on -E list. 419*7221Speter */ 420*7221Speter if ( onlist( Flist , childp -> name ) 421*7221Speter || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 422*7221Speter childp -> propfraction = 1.0; 4237172Speter } 424*7221Speter } else { 425*7221Speter /* 426*7221Speter * it has parents to pass time to, 427*7221Speter * but maybe someone wants to shut it up 428*7221Speter * by puttting it on -E list. (but favor -F over -E) 429*7221Speter */ 430*7221Speter if ( !onlist( Flist , childp -> name ) 431*7221Speter && onlist( Elist , childp -> name ) ) { 432*7221Speter childp -> propfraction = 0.0; 433*7221Speter } 4347172Speter } 435*7221Speter childp -> propself = childp -> time * childp -> propfraction; 436*7221Speter printtime += childp -> propself; 437*7221Speter # ifdef DEBUG 438*7221Speter if ( debug & PROPDEBUG ) { 439*7221Speter printf( "[doflags] " ); 440*7221Speter printname( childp ); 441*7221Speter printf( " ends up with printflag %d and propfraction %f\n" , 442*7221Speter childp -> printflag , childp -> propfraction ); 443*7221Speter printf( "time %f propself %f\n" , 444*7221Speter childp -> time , childp -> propself ); 445*7221Speter } 446*7221Speter # endif DEBUG 4477172Speter } 4487172Speter } 4497172Speter 4507172Speter /* 4517172Speter * check if any parent of this child 4527172Speter * (or outside parents of this cycle) 4537172Speter * have their print flags on and set the 4547172Speter * print flag of the child (cycle) appropriately. 455*7221Speter * similarly, deal with propagation fractions from parents. 4567172Speter */ 457*7221Speter inheritflags( childp ) 4587172Speter nltype *childp; 4597172Speter { 4607172Speter nltype *headp; 461*7221Speter arctype *arcp; 462*7221Speter nltype *parentp; 4637172Speter nltype *memp; 4647172Speter 4657172Speter headp = childp -> cyclehead; 4667172Speter if ( childp == headp ) { 4677172Speter /* 4687172Speter * just a regular child, check its parents 4697172Speter */ 470*7221Speter childp -> printflag = FALSE; 471*7221Speter childp -> propfraction = 0.0; 472*7221Speter for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 473*7221Speter parentp = arcp -> arc_parentp; 474*7221Speter childp -> printflag |= parentp -> printflag; 475*7221Speter childp -> propfraction += parentp -> propfraction 476*7221Speter * ( ( (double) arcp -> arc_count ) 477*7221Speter / ( (double) childp -> ncall) ); 4787172Speter } 479*7221Speter } else { 480*7221Speter /* 481*7221Speter * its a member of a cycle, look at all parents from 482*7221Speter * outside the cycle 483*7221Speter */ 484*7221Speter headp -> printflag = FALSE; 485*7221Speter headp -> propfraction = 0.0; 486*7221Speter for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 487*7221Speter for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 488*7221Speter if ( arcp -> arc_parentp -> cyclehead == headp ) { 489*7221Speter continue; 490*7221Speter } 491*7221Speter parentp = arcp -> arc_parentp; 492*7221Speter headp -> printflag |= parentp -> printflag; 493*7221Speter headp -> propfraction += parentp -> propfraction * 494*7221Speter (arcp -> arc_count / headp -> ncall); 4957172Speter } 4967172Speter } 497*7221Speter for ( memp = headp ; memp ; memp = memp -> cnext ) { 498*7221Speter memp -> printflag = headp -> printflag; 499*7221Speter memp -> propfraction = headp -> propfraction; 500*7221Speter } 5017172Speter } 5027172Speter } 503