1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)arcs.c 5.2 (Berkeley) 6/4/85"; 9: #endif not lint 10: 11: #include "gprof.h" 12: 13: /* 14: * add (or just increment) an arc 15: */ 16: addarc( parentp , childp , count ) 17: nltype *parentp; 18: nltype *childp; 19: long count; 20: { 21: arctype *calloc(); 22: arctype *arcp; 23: 24: # ifdef DEBUG 25: if ( debug & TALLYDEBUG ) { 26: printf( "[addarc] %d arcs from %s to %s\n" , 27: count , parentp -> name , childp -> name ); 28: } 29: # endif DEBUG 30: arcp = arclookup( parentp , childp ); 31: if ( arcp != 0 ) { 32: /* 33: * a hit: just increment the count. 34: */ 35: # ifdef DEBUG 36: if ( debug & TALLYDEBUG ) { 37: printf( "[tally] hit %d += %d\n" , 38: arcp -> arc_count , count ); 39: } 40: # endif DEBUG 41: arcp -> arc_count += count; 42: return; 43: } 44: arcp = calloc( 1 , sizeof *arcp ); 45: arcp -> arc_parentp = parentp; 46: arcp -> arc_childp = childp; 47: arcp -> arc_count = count; 48: /* 49: * prepend this child to the children of this parent 50: */ 51: arcp -> arc_childlist = parentp -> children; 52: parentp -> children = arcp; 53: /* 54: * prepend this parent to the parents of this child 55: */ 56: arcp -> arc_parentlist = childp -> parents; 57: childp -> parents = arcp; 58: } 59: 60: /* 61: * the code below topologically sorts the graph (collapsing cycles), 62: * and propagates time bottom up and flags top down. 63: */ 64: 65: /* 66: * the topologically sorted name list pointers 67: */ 68: nltype **topsortnlp; 69: 70: topcmp( npp1 , npp2 ) 71: nltype **npp1; 72: nltype **npp2; 73: { 74: return (*npp1) -> toporder - (*npp2) -> toporder; 75: } 76: 77: nltype ** 78: doarcs() 79: { 80: nltype *parentp, **timesortnlp; 81: arctype *arcp; 82: long index; 83: 84: /* 85: * initialize various things: 86: * zero out child times. 87: * count self-recursive calls. 88: * indicate that nothing is on cycles. 89: */ 90: for ( parentp = nl ; parentp < npe ; parentp++ ) { 91: parentp -> childtime = 0.0; 92: arcp = arclookup( parentp , parentp ); 93: if ( arcp != 0 ) { 94: parentp -> ncall -= arcp -> arc_count; 95: parentp -> selfcalls = arcp -> arc_count; 96: } else { 97: parentp -> selfcalls = 0; 98: } 99: parentp -> propfraction = 0.0; 100: parentp -> propself = 0.0; 101: parentp -> propchild = 0.0; 102: parentp -> printflag = FALSE; 103: parentp -> toporder = DFN_NAN; 104: parentp -> cycleno = 0; 105: parentp -> cyclehead = parentp; 106: parentp -> cnext = 0; 107: if ( cflag ) { 108: findcalls( parentp , parentp -> value , (parentp+1) -> value ); 109: } 110: } 111: /* 112: * topologically order things 113: * if any node is unnumbered, 114: * number it and any of its descendents. 115: */ 116: for ( parentp = nl ; parentp < npe ; parentp++ ) { 117: if ( parentp -> toporder == DFN_NAN ) { 118: dfn( parentp ); 119: } 120: } 121: /* 122: * link together nodes on the same cycle 123: */ 124: cyclelink(); 125: /* 126: * Sort the symbol table in reverse topological order 127: */ 128: topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); 129: if ( topsortnlp == (nltype **) 0 ) { 130: fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); 131: } 132: for ( index = 0 ; index < nname ; index += 1 ) { 133: topsortnlp[ index ] = &nl[ index ]; 134: } 135: qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); 136: # ifdef DEBUG 137: if ( debug & DFNDEBUG ) { 138: printf( "[doarcs] topological sort listing\n" ); 139: for ( index = 0 ; index < nname ; index += 1 ) { 140: printf( "[doarcs] " ); 141: printf( "%d:" , topsortnlp[ index ] -> toporder ); 142: printname( topsortnlp[ index ] ); 143: printf( "\n" ); 144: } 145: } 146: # endif DEBUG 147: /* 148: * starting from the topological top, 149: * propagate print flags to children. 150: * also, calculate propagation fractions. 151: * this happens before time propagation 152: * since time propagation uses the fractions. 153: */ 154: doflags(); 155: /* 156: * starting from the topological bottom, 157: * propogate children times up to parents. 158: */ 159: dotime(); 160: /* 161: * Now, sort by propself + propchild. 162: * sorting both the regular function names 163: * and cycle headers. 164: */ 165: timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 166: if ( timesortnlp == (nltype **) 0 ) { 167: fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 168: } 169: for ( index = 0 ; index < nname ; index++ ) { 170: timesortnlp[index] = &nl[index]; 171: } 172: for ( index = 1 ; index <= ncycle ; index++ ) { 173: timesortnlp[nname+index-1] = &cyclenl[index]; 174: } 175: qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); 176: for ( index = 0 ; index < nname + ncycle ; index++ ) { 177: timesortnlp[ index ] -> index = index + 1; 178: } 179: return( timesortnlp ); 180: } 181: 182: dotime() 183: { 184: int index; 185: 186: cycletime(); 187: for ( index = 0 ; index < nname ; index += 1 ) { 188: timepropagate( topsortnlp[ index ] ); 189: } 190: } 191: 192: timepropagate( parentp ) 193: nltype *parentp; 194: { 195: arctype *arcp; 196: nltype *childp; 197: double share; 198: double propshare; 199: 200: if ( parentp -> propfraction == 0.0 ) { 201: return; 202: } 203: /* 204: * gather time from children of this parent. 205: */ 206: for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 207: childp = arcp -> arc_childp; 208: if ( arcp -> arc_count == 0 ) { 209: continue; 210: } 211: if ( childp == parentp ) { 212: continue; 213: } 214: if ( childp -> propfraction == 0.0 ) { 215: continue; 216: } 217: if ( childp -> cyclehead != childp ) { 218: if ( parentp -> cycleno == childp -> cycleno ) { 219: continue; 220: } 221: if ( parentp -> toporder <= childp -> toporder ) { 222: fprintf( stderr , "[propagate] toporder botches\n" ); 223: } 224: childp = childp -> cyclehead; 225: } else { 226: if ( parentp -> toporder <= childp -> toporder ) { 227: fprintf( stderr , "[propagate] toporder botches\n" ); 228: continue; 229: } 230: } 231: if ( childp -> ncall == 0 ) { 232: continue; 233: } 234: /* 235: * distribute time for this arc 236: */ 237: arcp -> arc_time = childp -> time 238: * ( ( (double) arcp -> arc_count ) / 239: ( (double) childp -> ncall ) ); 240: arcp -> arc_childtime = childp -> childtime 241: * ( ( (double) arcp -> arc_count ) / 242: ( (double) childp -> ncall ) ); 243: share = arcp -> arc_time + arcp -> arc_childtime; 244: parentp -> childtime += share; 245: /* 246: * ( 1 - propfraction ) gets lost along the way 247: */ 248: propshare = parentp -> propfraction * share; 249: /* 250: * fix things for printing 251: */ 252: parentp -> propchild += propshare; 253: arcp -> arc_time *= parentp -> propfraction; 254: arcp -> arc_childtime *= parentp -> propfraction; 255: /* 256: * add this share to the parent's cycle header, if any. 257: */ 258: if ( parentp -> cyclehead != parentp ) { 259: parentp -> cyclehead -> childtime += share; 260: parentp -> cyclehead -> propchild += propshare; 261: } 262: # ifdef DEBUG 263: if ( debug & PROPDEBUG ) { 264: printf( "[dotime] child \t" ); 265: printname( childp ); 266: printf( " with %f %f %d/%d\n" , 267: childp -> time , childp -> childtime , 268: arcp -> arc_count , childp -> ncall ); 269: printf( "[dotime] parent\t" ); 270: printname( parentp ); 271: printf( "\n[dotime] share %f\n" , share ); 272: } 273: # endif DEBUG 274: } 275: } 276: 277: cyclelink() 278: { 279: register nltype *nlp; 280: register nltype *cyclenlp; 281: int cycle; 282: nltype *memberp; 283: arctype *arcp; 284: 285: /* 286: * Count the number of cycles, and initialze the cycle lists 287: */ 288: ncycle = 0; 289: for ( nlp = nl ; nlp < npe ; nlp++ ) { 290: /* 291: * this is how you find unattached cycles 292: */ 293: if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { 294: ncycle += 1; 295: } 296: } 297: /* 298: * cyclenl is indexed by cycle number: 299: * i.e. it is origin 1, not origin 0. 300: */ 301: cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); 302: if ( cyclenl == 0 ) { 303: fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , 304: whoami , ( ncycle + 1 ) * sizeof( nltype ) ); 305: done(); 306: } 307: /* 308: * now link cycles to true cycleheads, 309: * number them, accumulate the data for the cycle 310: */ 311: cycle = 0; 312: for ( nlp = nl ; nlp < npe ; nlp++ ) { 313: if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { 314: continue; 315: } 316: cycle += 1; 317: cyclenlp = &cyclenl[cycle]; 318: cyclenlp -> name = 0; /* the name */ 319: cyclenlp -> value = 0; /* the pc entry point */ 320: cyclenlp -> time = 0.0; /* ticks in this routine */ 321: cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ 322: cyclenlp -> ncall = 0; /* how many times called */ 323: cyclenlp -> selfcalls = 0; /* how many calls to self */ 324: cyclenlp -> propfraction = 0.0; /* what % of time propagates */ 325: cyclenlp -> propself = 0.0; /* how much self time propagates */ 326: cyclenlp -> propchild = 0.0; /* how much child time propagates */ 327: cyclenlp -> printflag = TRUE; /* should this be printed? */ 328: cyclenlp -> index = 0; /* index in the graph list */ 329: cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ 330: cyclenlp -> cycleno = cycle; /* internal number of cycle on */ 331: cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ 332: cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ 333: cyclenlp -> parents = 0; /* list of caller arcs */ 334: cyclenlp -> children = 0; /* list of callee arcs */ 335: # ifdef DEBUG 336: if ( debug & CYCLEDEBUG ) { 337: printf( "[cyclelink] " ); 338: printname( nlp ); 339: printf( " is the head of cycle %d\n" , cycle ); 340: } 341: # endif DEBUG 342: /* 343: * link members to cycle header 344: */ 345: for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 346: memberp -> cycleno = cycle; 347: memberp -> cyclehead = cyclenlp; 348: } 349: /* 350: * count calls from outside the cycle 351: * and those among cycle members 352: */ 353: for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 354: for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { 355: if ( arcp -> arc_parentp == memberp ) { 356: continue; 357: } 358: if ( arcp -> arc_parentp -> cycleno == cycle ) { 359: cyclenlp -> selfcalls += arcp -> arc_count; 360: } else { 361: cyclenlp -> ncall += arcp -> arc_count; 362: } 363: } 364: } 365: } 366: } 367: 368: cycletime() 369: { 370: int cycle; 371: nltype *cyclenlp; 372: nltype *childp; 373: 374: for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { 375: cyclenlp = &cyclenl[ cycle ]; 376: for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { 377: if ( childp -> propfraction == 0.0 ) { 378: /* 379: * all members have the same propfraction except those 380: * that were excluded with -E 381: */ 382: continue; 383: } 384: cyclenlp -> time += childp -> time; 385: } 386: cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; 387: } 388: } 389: 390: /* 391: * in one top to bottom pass over the topologically sorted namelist 392: * propagate: 393: * printflag as the union of parents' printflags 394: * propfraction as the sum of fractional parents' propfractions 395: * and while we're here, sum time for functions. 396: */ 397: doflags() 398: { 399: int index; 400: nltype *childp; 401: nltype *oldhead; 402: 403: oldhead = 0; 404: for ( index = nname-1 ; index >= 0 ; index -= 1 ) { 405: childp = topsortnlp[ index ]; 406: /* 407: * if we haven't done this function or cycle, 408: * inherit things from parent. 409: * this way, we are linear in the number of arcs 410: * since we do all members of a cycle (and the cycle itself) 411: * as we hit the first member of the cycle. 412: */ 413: if ( childp -> cyclehead != oldhead ) { 414: oldhead = childp -> cyclehead; 415: inheritflags( childp ); 416: } 417: # ifdef DEBUG 418: if ( debug & PROPDEBUG ) { 419: printf( "[doflags] " ); 420: printname( childp ); 421: printf( " inherits printflag %d and propfraction %f\n" , 422: childp -> printflag , childp -> propfraction ); 423: } 424: # endif DEBUG 425: if ( ! childp -> printflag ) { 426: /* 427: * printflag is off 428: * it gets turned on by 429: * being on -f list, 430: * or there not being any -f list and not being on -e list. 431: */ 432: if ( onlist( flist , childp -> name ) 433: || ( !fflag && !onlist( elist , childp -> name ) ) ) { 434: childp -> printflag = TRUE; 435: } 436: } else { 437: /* 438: * this function has printing parents: 439: * maybe someone wants to shut it up 440: * by putting it on -e list. (but favor -f over -e) 441: */ 442: if ( ( !onlist( flist , childp -> name ) ) 443: && onlist( elist , childp -> name ) ) { 444: childp -> printflag = FALSE; 445: } 446: } 447: if ( childp -> propfraction == 0.0 ) { 448: /* 449: * no parents to pass time to. 450: * collect time from children if 451: * its on -F list, 452: * or there isn't any -F list and its not on -E list. 453: */ 454: if ( onlist( Flist , childp -> name ) 455: || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { 456: childp -> propfraction = 1.0; 457: } 458: } else { 459: /* 460: * it has parents to pass time to, 461: * but maybe someone wants to shut it up 462: * by puttting it on -E list. (but favor -F over -E) 463: */ 464: if ( !onlist( Flist , childp -> name ) 465: && onlist( Elist , childp -> name ) ) { 466: childp -> propfraction = 0.0; 467: } 468: } 469: childp -> propself = childp -> time * childp -> propfraction; 470: printtime += childp -> propself; 471: # ifdef DEBUG 472: if ( debug & PROPDEBUG ) { 473: printf( "[doflags] " ); 474: printname( childp ); 475: printf( " ends up with printflag %d and propfraction %f\n" , 476: childp -> printflag , childp -> propfraction ); 477: printf( "time %f propself %f printtime %f\n" , 478: childp -> time , childp -> propself , printtime ); 479: } 480: # endif DEBUG 481: } 482: } 483: 484: /* 485: * check if any parent of this child 486: * (or outside parents of this cycle) 487: * have their print flags on and set the 488: * print flag of the child (cycle) appropriately. 489: * similarly, deal with propagation fractions from parents. 490: */ 491: inheritflags( childp ) 492: nltype *childp; 493: { 494: nltype *headp; 495: arctype *arcp; 496: nltype *parentp; 497: nltype *memp; 498: 499: headp = childp -> cyclehead; 500: if ( childp == headp ) { 501: /* 502: * just a regular child, check its parents 503: */ 504: childp -> printflag = FALSE; 505: childp -> propfraction = 0.0; 506: for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { 507: parentp = arcp -> arc_parentp; 508: if ( childp == parentp ) { 509: continue; 510: } 511: childp -> printflag |= parentp -> printflag; 512: /* 513: * if the child was never actually called 514: * (e.g. this arc is static (and all others are, too)) 515: * no time propagates along this arc. 516: */ 517: if ( childp -> ncall ) { 518: childp -> propfraction += parentp -> propfraction 519: * ( ( (double) arcp -> arc_count ) 520: / ( (double) childp -> ncall ) ); 521: } 522: } 523: } else { 524: /* 525: * its a member of a cycle, look at all parents from 526: * outside the cycle 527: */ 528: headp -> printflag = FALSE; 529: headp -> propfraction = 0.0; 530: for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { 531: for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { 532: if ( arcp -> arc_parentp -> cyclehead == headp ) { 533: continue; 534: } 535: parentp = arcp -> arc_parentp; 536: headp -> printflag |= parentp -> printflag; 537: /* 538: * if the cycle was never actually called 539: * (e.g. this arc is static (and all others are, too)) 540: * no time propagates along this arc. 541: */ 542: if ( headp -> ncall ) { 543: headp -> propfraction += parentp -> propfraction 544: * ( ( (double) arcp -> arc_count ) 545: / ( (double) headp -> ncall ) ); 546: } 547: } 548: } 549: for ( memp = headp ; memp ; memp = memp -> cnext ) { 550: memp -> printflag = headp -> printflag; 551: memp -> propfraction = headp -> propfraction; 552: } 553: } 554: }