14515Speter #ifndef lint 2*4753Speter static char *sccsid = "@(#)printgprof.c 1.3 (Berkeley) 11/06/81"; 34515Speter #endif lint 44515Speter 54562Speter #include "gprof.h" 64515Speter 7*4753Speter printprof() 8*4753Speter { 9*4753Speter register nltype *np; 10*4753Speter nltype **sortednlp; 11*4753Speter int index; 12*4753Speter 13*4753Speter actime = 0.0; 14*4753Speter flatprofheader(); 15*4753Speter /* 16*4753Speter * Sort the symbol table in by time 17*4753Speter */ 18*4753Speter sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); 19*4753Speter if ( sortednlp == (nltype **) 0 ) { 20*4753Speter fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); 21*4753Speter } 22*4753Speter for ( index = 0 ; index < nname ; index += 1 ) { 23*4753Speter sortednlp[ index ] = &nl[ index ]; 24*4753Speter } 25*4753Speter qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); 26*4753Speter for ( index = 0 ; index < nname ; index += 1 ) { 27*4753Speter np = sortednlp[ index ]; 28*4753Speter flatprofline( np ); 29*4753Speter } 30*4753Speter actime = 0.0; 31*4753Speter printf( "\ngranularity: each sample hit covers %.1f bytes" , scale ); 32*4753Speter printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ ); 33*4753Speter } 34*4753Speter 35*4753Speter timecmp( npp1 , npp2 ) 36*4753Speter nltype **npp1, **npp2; 37*4753Speter { 38*4753Speter double d; 39*4753Speter 40*4753Speter d = (*npp2) -> time - (*npp1) -> time; 41*4753Speter if ( d > 0.0 ) 42*4753Speter return 1 ; 43*4753Speter if ( d < 0.0 ) 44*4753Speter return -1; 45*4753Speter return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); 46*4753Speter } 47*4753Speter 48*4753Speter /* 49*4753Speter * header for flatprofline 50*4753Speter */ 51*4753Speter flatprofheader() 52*4753Speter { 53*4753Speter 54*4753Speter printf( "%5.5s %7.7s %7.7s %7.7s %-8.8s\n" , 55*4753Speter "%time" , "cumsecs" , "seconds" , "calls" , "name" ); 56*4753Speter } 57*4753Speter 58*4753Speter flatprofline( np ) 59*4753Speter register nltype *np; 60*4753Speter { 61*4753Speter 62*4753Speter if ( zflg == 0 && np -> ncall == 0 && np -> time == 0 ) { 63*4753Speter return; 64*4753Speter } 65*4753Speter actime += np -> time; 66*4753Speter printf( "%5.1f %7.2f %7.2f" , 67*4753Speter 100 * np -> time / totime , actime / HZ , np -> time / HZ ); 68*4753Speter if ( np -> ncall != 0 ) { 69*4753Speter printf( " %7d" , np -> ncall ); 70*4753Speter } else { 71*4753Speter printf( " %7.7s" , "" ); 72*4753Speter } 73*4753Speter printf( " %s\n" , np -> name ); 74*4753Speter } 75*4753Speter 76*4753Speter gprofheader() 77*4753Speter { 78*4753Speter printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , 79*4753Speter "" , "" , "" , "" , "called" , "total" , "parents" , "" ); 80*4753Speter printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" , 81*4753Speter "index" , "%time" , "self" , "descendents" , 82*4753Speter "called" , "self" , "name" , "index" ); 83*4753Speter printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , 84*4753Speter "" , "" , "" , "" , "called" , "total" , "children" , "" ); 85*4753Speter printf( "\n" ); 86*4753Speter } 87*4753Speter 88*4753Speter gprofline( np ) 89*4753Speter register nltype *np; 90*4753Speter { 91*4753Speter char kirkbuffer[ BUFSIZ ]; 92*4753Speter 93*4753Speter sprintf( kirkbuffer , "[%d]" , np -> index ); 94*4753Speter printf( "%-6.6s %5.1f %7.2f %11.2f" , 95*4753Speter kirkbuffer , 96*4753Speter 100 * ( np -> time + np -> childtime ) / totime , 97*4753Speter np -> time / HZ , 98*4753Speter np -> childtime / HZ ); 99*4753Speter if ( ( np -> ncall + np -> selfcalls ) != 0 ) { 100*4753Speter printf( " %7d" , np -> ncall ); 101*4753Speter if ( np -> selfcalls != 0 ) { 102*4753Speter printf( "+%-7d " , np -> selfcalls ); 103*4753Speter } else { 104*4753Speter printf( " %7.7s " , "" ); 105*4753Speter } 106*4753Speter } else { 107*4753Speter printf( " %7.7s %7.7s " , "" , "" ); 108*4753Speter } 109*4753Speter printname( np ); 110*4753Speter printf( "\n" ); 111*4753Speter } 112*4753Speter 1134562Speter printgprof() 1144515Speter { 1154515Speter nltype **timesortnlp; 1164515Speter int index; 1174515Speter nltype *parentp; 1184515Speter nltype *childp; 1194515Speter 1204515Speter /* 1214515Speter * Now, sort by time + childtime. 1224515Speter * include the cycle headers hiding out past nl[nname]. 123*4753Speter * don't include the dummy hiding at nl[nname]. 1244515Speter */ 125*4753Speter timesortnlp = (nltype **) calloc( nname + cyclemax , sizeof(nltype *) ); 1264515Speter if ( timesortnlp == (nltype **) 0 ) { 1274515Speter fprintf( stderr , "[doarcs] ran out of memory for sorting\n" ); 1284515Speter } 129*4753Speter for ( index = 0 ; index < nname ; index++ ) { 1304515Speter timesortnlp[index] = &nl[index]; 1314515Speter } 132*4753Speter for ( index = 1 ; index <= cyclemax ; index++ ) { 133*4753Speter timesortnlp[(nname-1)+index] = &nl[nname+index]; 134*4753Speter } 135*4753Speter qsort( timesortnlp , nname + cyclemax , sizeof(nltype *) , totalcmp ); 136*4753Speter for ( index = 0 ; index < nname + cyclemax ; index++ ) { 1374515Speter timesortnlp[ index ] -> index = index + 1; 1384515Speter } 1394515Speter /* 1404515Speter * Now, print out the structured profiling list 1414515Speter */ 142*4753Speter printf( "\f\n" ); 143*4753Speter gprofheader(); 144*4753Speter for ( index = 0 ; index < nname + cyclemax ; index ++ ) { 1454515Speter parentp = timesortnlp[ index ]; 1464515Speter if ( zflg == 0 && 1474515Speter parentp -> ncall == 0 && 1484515Speter parentp -> selfcalls == 0 && 1494515Speter parentp -> time == 0 && 1504515Speter parentp -> childtime == 0 ) { 1514515Speter continue; 1524515Speter } 1534515Speter if ( parentp -> name == 0 && parentp -> cycleno != 0 ) { 1544515Speter /* 1554515Speter * cycle header 1564515Speter */ 157*4753Speter printcycle( parentp ); 158*4753Speter printmembers( parentp ); 1594515Speter } else { 1604515Speter printparents( parentp ); 161*4753Speter gprofline( parentp ); 1624515Speter printchildren( parentp ); 1634515Speter } 1644515Speter printf( "\n" ); 165*4753Speter printf( "-----------------------------------------------\n" ); 166*4753Speter printf( "\n" ); 1674515Speter } 1684515Speter } 1694515Speter 1704515Speter printparents( childp ) 1714515Speter nltype *childp; 1724515Speter { 1734515Speter nltype *parentp; 1744515Speter arctype *arcp; 1754515Speter nltype *cycleheadp; 1764515Speter 1774515Speter if ( childp -> cyclehead != 0 ) { 1784515Speter cycleheadp = childp -> cyclehead; 1794515Speter } else { 1804515Speter cycleheadp = childp; 1814515Speter } 1824515Speter if ( childp -> parents == 0 ) { 183*4753Speter printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n" , 1844515Speter "" , "" , "" , "" , "" , "" ); 1854515Speter return; 1864515Speter } 1874515Speter sortparents( childp ); 1884515Speter for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) { 1894515Speter parentp = arcp -> arc_parentp; 1904515Speter if ( childp == parentp || 1914515Speter ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) { 1924515Speter /* 193*4753Speter * selfcall or call among siblings 1944515Speter */ 195*4753Speter printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , 1964515Speter "" , "" , "" , "" , 1974515Speter arcp -> arc_count , "" ); 1984515Speter printname( parentp ); 1994515Speter printf( "\n" ); 2004515Speter } else { 2014515Speter /* 2024515Speter * regular parent of child 2034515Speter */ 204*4753Speter printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , 205*4753Speter "" , "" , 2064515Speter arcp -> arc_time / HZ , arcp -> arc_childtime / HZ , 2074515Speter arcp -> arc_count , cycleheadp -> ncall ); 2084515Speter printname( parentp ); 2094515Speter printf( "\n" ); 2104515Speter } 2114515Speter } 2124515Speter } 2134515Speter 2144515Speter printchildren( parentp ) 2154515Speter nltype *parentp; 2164515Speter { 2174515Speter nltype *childp; 2184515Speter arctype *arcp; 2194515Speter 2204515Speter sortchildren( parentp ); 2214515Speter arcp = parentp -> children; 2224515Speter for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 2234515Speter childp = arcp -> arc_childp; 2244515Speter if ( childp == parentp || 2254515Speter ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) { 2264515Speter /* 2274515Speter * self call or call to sibling 2284515Speter */ 229*4753Speter printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , 230*4753Speter "" , "" , "" , "" , arcp -> arc_count , "" ); 2314515Speter printname( childp ); 2324515Speter printf( "\n" ); 2334515Speter } else { 2344515Speter /* 2354515Speter * regular child of parent 2364515Speter */ 237*4753Speter printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , 238*4753Speter "" , "" , 2394515Speter arcp -> arc_time / HZ , arcp -> arc_childtime / HZ , 2404515Speter arcp -> arc_count , childp -> cyclehead -> ncall ); 2414515Speter printname( childp ); 2424515Speter printf( "\n" ); 2434515Speter } 2444515Speter } 2454515Speter } 2464515Speter 2474515Speter printname( selfp ) 2484515Speter nltype *selfp; 2494515Speter { 2504515Speter 2514515Speter if ( selfp -> name != 0 ) { 252*4753Speter printf( "%s" , selfp -> name ); 2534515Speter # ifdef DEBUG 2544515Speter if ( debug & DFNDEBUG ) { 2554515Speter printf( "{%d} " , selfp -> toporder ); 2564515Speter } 2574515Speter # endif DEBUG 2584515Speter } 259*4753Speter if ( selfp -> index != 0 ) { 260*4753Speter printf( "\t[%d]" , selfp -> index ); 261*4753Speter } 2624515Speter if ( selfp -> cycleno != 0 ) { 263*4753Speter printf( " <cycle %d>" , selfp -> cycleno ); 2644515Speter } 2654515Speter } 2664515Speter 2674515Speter sortchildren( parentp ) 2684515Speter nltype *parentp; 2694515Speter { 2704515Speter arctype *arcp; 2714515Speter arctype *detachedp; 2724515Speter arctype sorted; 2734515Speter arctype *prevp; 2744515Speter 2754515Speter /* 2764515Speter * unlink children from parent, 2774515Speter * then insertion sort back on to sorted's children. 2784515Speter * *arcp the arc you have detached and are inserting. 2794515Speter * *detachedp the rest of the arcs to be sorted. 2804515Speter * sorted arc list onto which you insertion sort. 2814515Speter * *prevp arc before the arc you are comparing. 2824515Speter */ 2834515Speter sorted.arc_childlist = 0; 2844515Speter for ( arcp = parentp -> children , detachedp = arcp -> arc_childlist ; 2854515Speter arcp ; 2864515Speter arcp = detachedp , detachedp = detachedp -> arc_childlist ) { 2874515Speter /* 2884515Speter * consider *arcp as disconnected 2894515Speter * insert it into sorted 2904515Speter */ 2914515Speter for ( prevp = &sorted ; 2924515Speter prevp -> arc_childlist ; 2934515Speter prevp = prevp -> arc_childlist ) { 2944515Speter if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) { 2954515Speter break; 2964515Speter } 2974515Speter } 2984515Speter arcp -> arc_childlist = prevp -> arc_childlist; 2994515Speter prevp -> arc_childlist = arcp; 3004515Speter } 3014515Speter /* 3024515Speter * reattach sorted children to parent 3034515Speter */ 3044515Speter parentp -> children = sorted.arc_childlist; 3054515Speter } 3064515Speter 3074515Speter sortparents( childp ) 3084515Speter nltype *childp; 3094515Speter { 3104515Speter arctype *arcp; 3114515Speter arctype *detachedp; 3124515Speter arctype sorted; 3134515Speter arctype *prevp; 3144515Speter 3154515Speter /* 3164515Speter * unlink parents from child, 3174515Speter * then insertion sort back on to sorted's parents. 3184515Speter * *arcp the arc you have detached and are inserting. 3194515Speter * *detachedp the rest of the arcs to be sorted. 3204515Speter * sorted arc list onto which you insertion sort. 3214515Speter * *prevp arc before the arc you are comparing. 3224515Speter */ 3234515Speter sorted.arc_parentlist = 0; 3244515Speter for ( arcp = childp -> parents , detachedp = arcp -> arc_parentlist ; 3254515Speter arcp ; 3264515Speter arcp = detachedp , detachedp = detachedp -> arc_parentlist ) { 3274515Speter /* 3284515Speter * consider *arcp as disconnected 3294515Speter * insert it into sorted 3304515Speter */ 3314515Speter for ( prevp = &sorted ; 3324515Speter prevp -> arc_parentlist ; 3334515Speter prevp = prevp -> arc_parentlist ) { 3344515Speter if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) { 3354515Speter break; 3364515Speter } 3374515Speter } 3384515Speter arcp -> arc_parentlist = prevp -> arc_parentlist; 3394515Speter prevp -> arc_parentlist = arcp; 3404515Speter } 3414515Speter /* 3424515Speter * reattach sorted arcs to child 3434515Speter */ 3444515Speter childp -> parents = sorted.arc_parentlist; 3454515Speter } 3464515Speter 3474515Speter /* 348*4753Speter * print a cycle header 349*4753Speter */ 350*4753Speter printcycle( cyclep ) 351*4753Speter nltype *cyclep; 352*4753Speter { 353*4753Speter char kirkbuffer[ BUFSIZ ]; 354*4753Speter 355*4753Speter sprintf( kirkbuffer , "[%d]" , cyclep -> index ); 356*4753Speter printf( "%-6.6s %5.1f %7.2f %11.2f %7d" , 357*4753Speter kirkbuffer , 358*4753Speter 100 * ( cyclep -> time + cyclep -> childtime ) / totime , 359*4753Speter cyclep -> time / HZ , 360*4753Speter cyclep -> childtime / HZ , 361*4753Speter cyclep -> ncall ); 362*4753Speter if ( cyclep -> selfcalls != 0 ) { 363*4753Speter printf( "+%-7d" , cyclep -> selfcalls ); 364*4753Speter } else { 365*4753Speter printf( " %7.7s" , "" ); 366*4753Speter } 367*4753Speter printf( " <cycle %d as a whole>\t[%d]\n" , 368*4753Speter cyclep -> cycleno , cyclep -> index ); 369*4753Speter } 370*4753Speter 371*4753Speter /* 372*4753Speter * print the members of a cycle 373*4753Speter */ 374*4753Speter printmembers( cyclep ) 375*4753Speter nltype *cyclep; 376*4753Speter { 377*4753Speter nltype *memberp; 378*4753Speter 379*4753Speter sortmembers( cyclep ); 380*4753Speter for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) { 381*4753Speter printf( "%6.6s %5.5s %7.2f %11.2f %7d" , 382*4753Speter "" , "" , memberp -> time / HZ , memberp -> childtime / HZ , 383*4753Speter memberp -> ncall ); 384*4753Speter if ( memberp -> selfcalls != 0 ) { 385*4753Speter printf( "+%-7d" , memberp -> selfcalls ); 386*4753Speter } else { 387*4753Speter printf( " %7.7s" , "" ); 388*4753Speter } 389*4753Speter printf( " " ); 390*4753Speter printname( memberp ); 391*4753Speter printf( "\n" ); 392*4753Speter } 393*4753Speter } 394*4753Speter 395*4753Speter /* 396*4753Speter * sort members of a cycle 397*4753Speter */ 398*4753Speter sortmembers( cyclep ) 399*4753Speter nltype *cyclep; 400*4753Speter { 401*4753Speter nltype *todo; 402*4753Speter nltype *doing; 403*4753Speter nltype *prev; 404*4753Speter 405*4753Speter /* 406*4753Speter * detach cycle members from cyclehead, 407*4753Speter * and insertion sort them back on. 408*4753Speter */ 409*4753Speter todo = cyclep -> cnext; 410*4753Speter cyclep -> cnext = 0; 411*4753Speter for ( doing = todo , todo = doing -> cnext ; 412*4753Speter doing ; 413*4753Speter doing = todo , todo = doing -> cnext ) { 414*4753Speter for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) { 415*4753Speter if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) { 416*4753Speter break; 417*4753Speter } 418*4753Speter } 419*4753Speter doing -> cnext = prev -> cnext; 420*4753Speter prev -> cnext = doing; 421*4753Speter } 422*4753Speter } 423*4753Speter 424*4753Speter /* 425*4753Speter * major sort is on time + childtime, 426*4753Speter * next is sort on ncalls + selfcalls. 427*4753Speter */ 428*4753Speter long 429*4753Speter membercmp( this , that ) 430*4753Speter nltype *this; 431*4753Speter nltype *that; 432*4753Speter { 433*4753Speter double thistime = this -> time + this -> childtime; 434*4753Speter double thattime = that -> time + that -> childtime; 435*4753Speter long thiscalls = this -> ncall + this -> selfcalls; 436*4753Speter long thatcalls = that -> ncall + that -> selfcalls; 437*4753Speter 438*4753Speter if ( thistime > thattime ) { 439*4753Speter return GREATERTHAN; 440*4753Speter } 441*4753Speter if ( thistime < thattime ) { 442*4753Speter return LESSTHAN; 443*4753Speter } 444*4753Speter if ( thiscalls > thatcalls ) { 445*4753Speter return GREATERTHAN; 446*4753Speter } 447*4753Speter if ( thiscalls < thatcalls ) { 448*4753Speter return LESSTHAN; 449*4753Speter } 450*4753Speter return EQUALTO; 451*4753Speter } 452*4753Speter /* 4534515Speter * compare two arcs to/from the same child/parent. 4544515Speter * - if one arc is a self arc, it's least. 4554515Speter * - if one arc is within a cycle, it's less than. 4564515Speter * - if both arcs are within a cycle, compare arc counts. 4574515Speter * - if neither arc is within a cycle, compare with 4584515Speter * time + childtime as major key 4594515Speter * arc count as minor key 4604515Speter */ 4614515Speter int 4624515Speter arccmp( thisp , thatp ) 4634515Speter arctype *thisp; 4644515Speter arctype *thatp; 4654515Speter { 4664515Speter nltype *thisparentp = thisp -> arc_parentp; 4674515Speter nltype *thischildp = thisp -> arc_childp; 4684515Speter nltype *thatparentp = thatp -> arc_parentp; 4694515Speter nltype *thatchildp = thatp -> arc_childp; 4704515Speter double thistime; 4714515Speter double thattime; 4724515Speter 4734515Speter # ifdef DEBUG 4744515Speter if ( debug & TIMEDEBUG ) { 4754515Speter printf( "[arccmp] " ); 4764515Speter printname( thisparentp ); 4774515Speter printf( " calls " ); 4784515Speter printname ( thischildp ); 4794515Speter printf( " %f + %f %d/%d\n" , 4804515Speter thisp -> arc_time , thisp -> arc_childtime , 4814515Speter thisp -> arc_count , thischildp -> ncall ); 4824515Speter printf( "[arccmp] " ); 4834515Speter printname( thatparentp ); 4844515Speter printf( " calls " ); 4854515Speter printname( thatchildp ); 4864515Speter printf( " %f + %f %d/%d\n" , 4874515Speter thatp -> arc_time , thatp -> arc_childtime , 4884515Speter thatp -> arc_count , thatchildp -> ncall ); 4894515Speter printf( "\n" ); 4904515Speter } 4914515Speter # endif DEBUG 4924515Speter if ( thisparentp == thischildp ) { 4934515Speter /* this is a self call */ 4944515Speter return LESSTHAN; 4954515Speter } 4964515Speter if ( thatparentp == thatchildp ) { 4974515Speter /* that is a self call */ 4984515Speter return GREATERTHAN; 4994515Speter } 5004515Speter if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 && 5014515Speter thisparentp -> cycleno == thischildp -> cycleno ) { 5024515Speter /* this is a call within a cycle */ 5034515Speter if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && 5044515Speter thatparentp -> cycleno == thatchildp -> cycleno ) { 5054515Speter /* that is a call within the cycle, too */ 5064515Speter if ( thisp -> arc_count < thatp -> arc_count ) { 5074515Speter return LESSTHAN; 5084515Speter } 5094515Speter if ( thisp -> arc_count > thatp -> arc_count ) { 5104515Speter return GREATERTHAN; 5114515Speter } 5124515Speter return EQUALTO; 5134515Speter } else { 5144515Speter /* that isn't a call within the cycle */ 5154515Speter return LESSTHAN; 5164515Speter } 5174515Speter } else { 5184515Speter /* this isn't a call within a cycle */ 5194515Speter if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && 5204515Speter thatparentp -> cycleno == thatchildp -> cycleno ) { 5214515Speter /* that is a call within a cycle */ 5224515Speter return GREATERTHAN; 5234515Speter } else { 5244515Speter /* neither is a call within a cycle */ 5254515Speter thistime = thisp -> arc_time + thisp -> arc_childtime; 5264515Speter thattime = thatp -> arc_time + thatp -> arc_childtime; 5274515Speter if ( thistime < thattime ) 5284515Speter return LESSTHAN; 5294515Speter if ( thistime > thattime ) 5304515Speter return GREATERTHAN; 5314515Speter if ( thisp -> arc_count < thatp -> arc_count ) 5324515Speter return LESSTHAN; 5334515Speter if ( thisp -> arc_count > thatp -> arc_count ) 5344515Speter return GREATERTHAN; 5354515Speter return EQUALTO; 5364515Speter } 5374515Speter } 5384515Speter } 539