1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)printgprof.c 5.4 (Berkeley) 05/05/88"; 15 #endif /* not lint */ 16 17 #include "gprof.h" 18 19 printprof() 20 { 21 register nltype *np; 22 nltype **sortednlp; 23 int index, timecmp(); 24 25 actime = 0.0; 26 printf( "\f\n" ); 27 flatprofheader(); 28 /* 29 * Sort the symbol table in by time 30 */ 31 sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); 32 if ( sortednlp == (nltype **) 0 ) { 33 fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); 34 } 35 for ( index = 0 ; index < nname ; index += 1 ) { 36 sortednlp[ index ] = &nl[ index ]; 37 } 38 qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); 39 for ( index = 0 ; index < nname ; index += 1 ) { 40 np = sortednlp[ index ]; 41 flatprofline( np ); 42 } 43 actime = 0.0; 44 cfree( sortednlp ); 45 } 46 47 timecmp( npp1 , npp2 ) 48 nltype **npp1, **npp2; 49 { 50 double timediff; 51 long calldiff; 52 53 timediff = (*npp2) -> time - (*npp1) -> time; 54 if ( timediff > 0.0 ) 55 return 1 ; 56 if ( timediff < 0.0 ) 57 return -1; 58 calldiff = (*npp2) -> ncall - (*npp1) -> ncall; 59 if ( calldiff > 0 ) 60 return 1; 61 if ( calldiff < 0 ) 62 return -1; 63 return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); 64 } 65 66 /* 67 * header for flatprofline 68 */ 69 flatprofheader() 70 { 71 72 if ( bflag ) { 73 printblurb( FLAT_BLURB ); 74 } 75 printf( "\ngranularity: each sample hit covers %d byte(s)" , 76 (long) scale * sizeof(UNIT) ); 77 if ( totime > 0.0 ) { 78 printf( " for %.2f%% of %.2f seconds\n\n" , 79 100.0/totime , totime / hz ); 80 } else { 81 printf( " no time accumulated\n\n" ); 82 /* 83 * this doesn't hurt sinc eall the numerators will be zero. 84 */ 85 totime = 1.0; 86 } 87 printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , 88 "% " , "cumulative" , "self " , "" , "self " , "total " , "" ); 89 printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , 90 "time" , "seconds " , "seconds" , "calls" , 91 "ms/call" , "ms/call" , "name" ); 92 } 93 94 flatprofline( np ) 95 register nltype *np; 96 { 97 98 if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) { 99 return; 100 } 101 actime += np -> time; 102 printf( "%5.1f %10.2f %8.2f" , 103 100 * np -> time / totime , actime / hz , np -> time / hz ); 104 if ( np -> ncall != 0 ) { 105 printf( " %8d %8.2f %8.2f " , np -> ncall , 106 1000 * np -> time / hz / np -> ncall , 107 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall ); 108 } else { 109 printf( " %8.8s %8.8s %8.8s " , "" , "" , "" ); 110 } 111 printname( np ); 112 printf( "\n" ); 113 } 114 115 gprofheader() 116 { 117 118 if ( bflag ) { 119 printblurb( CALLG_BLURB ); 120 } 121 printf( "\ngranularity: each sample hit covers %d byte(s)" , 122 (long) scale * sizeof(UNIT) ); 123 if ( printtime > 0.0 ) { 124 printf( " for %.2f%% of %.2f seconds\n\n" , 125 100.0/printtime , printtime / hz ); 126 } else { 127 printf( " no time propagated\n\n" ); 128 /* 129 * this doesn't hurt, since all the numerators will be 0.0 130 */ 131 printtime = 1.0; 132 } 133 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , 134 "" , "" , "" , "" , "called" , "total" , "parents"); 135 printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" , 136 "index" , "%time" , "self" , "descendents" , 137 "called" , "self" , "name" , "index" ); 138 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , 139 "" , "" , "" , "" , "called" , "total" , "children"); 140 printf( "\n" ); 141 } 142 143 gprofline( np ) 144 register nltype *np; 145 { 146 char kirkbuffer[ BUFSIZ ]; 147 148 sprintf( kirkbuffer , "[%d]" , np -> index ); 149 printf( "%-6.6s %5.1f %7.2f %11.2f" , 150 kirkbuffer , 151 100 * ( np -> propself + np -> propchild ) / printtime , 152 np -> propself / hz , 153 np -> propchild / hz ); 154 if ( ( np -> ncall + np -> selfcalls ) != 0 ) { 155 printf( " %7d" , np -> ncall ); 156 if ( np -> selfcalls != 0 ) { 157 printf( "+%-7d " , np -> selfcalls ); 158 } else { 159 printf( " %7.7s " , "" ); 160 } 161 } else { 162 printf( " %7.7s %7.7s " , "" , "" ); 163 } 164 printname( np ); 165 printf( "\n" ); 166 } 167 168 printgprof(timesortnlp) 169 nltype **timesortnlp; 170 { 171 int index; 172 nltype *parentp; 173 174 /* 175 * Print out the structured profiling list 176 */ 177 gprofheader(); 178 for ( index = 0 ; index < nname + ncycle ; index ++ ) { 179 parentp = timesortnlp[ index ]; 180 if ( zflag == 0 && 181 parentp -> ncall == 0 && 182 parentp -> selfcalls == 0 && 183 parentp -> propself == 0 && 184 parentp -> propchild == 0 ) { 185 continue; 186 } 187 if ( ! parentp -> printflag ) { 188 continue; 189 } 190 if ( parentp -> name == 0 && parentp -> cycleno != 0 ) { 191 /* 192 * cycle header 193 */ 194 printcycle( parentp ); 195 printmembers( parentp ); 196 } else { 197 printparents( parentp ); 198 gprofline( parentp ); 199 printchildren( parentp ); 200 } 201 printf( "\n" ); 202 printf( "-----------------------------------------------\n" ); 203 printf( "\n" ); 204 } 205 cfree( timesortnlp ); 206 } 207 208 /* 209 * sort by decreasing propagated time 210 * if times are equal, but one is a cycle header, 211 * say that's first (e.g. less, i.e. -1). 212 * if one's name doesn't have an underscore and the other does, 213 * say the one is first. 214 * all else being equal, sort by names. 215 */ 216 int 217 totalcmp( npp1 , npp2 ) 218 nltype **npp1; 219 nltype **npp2; 220 { 221 register nltype *np1 = *npp1; 222 register nltype *np2 = *npp2; 223 double diff; 224 225 diff = ( np1 -> propself + np1 -> propchild ) 226 - ( np2 -> propself + np2 -> propchild ); 227 if ( diff < 0.0 ) 228 return 1; 229 if ( diff > 0.0 ) 230 return -1; 231 if ( np1 -> name == 0 && np1 -> cycleno != 0 ) 232 return -1; 233 if ( np2 -> name == 0 && np2 -> cycleno != 0 ) 234 return 1; 235 if ( np1 -> name == 0 ) 236 return -1; 237 if ( np2 -> name == 0 ) 238 return 1; 239 if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' ) 240 return -1; 241 if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' ) 242 return 1; 243 if ( np1 -> ncall > np2 -> ncall ) 244 return -1; 245 if ( np1 -> ncall < np2 -> ncall ) 246 return 1; 247 return strcmp( np1 -> name , np2 -> name ); 248 } 249 250 printparents( childp ) 251 nltype *childp; 252 { 253 nltype *parentp; 254 arctype *arcp; 255 nltype *cycleheadp; 256 257 if ( childp -> cyclehead != 0 ) { 258 cycleheadp = childp -> cyclehead; 259 } else { 260 cycleheadp = childp; 261 } 262 if ( childp -> parents == 0 ) { 263 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n" , 264 "" , "" , "" , "" , "" , "" ); 265 return; 266 } 267 sortparents( childp ); 268 for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) { 269 parentp = arcp -> arc_parentp; 270 if ( childp == parentp || 271 ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) { 272 /* 273 * selfcall or call among siblings 274 */ 275 printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , 276 "" , "" , "" , "" , 277 arcp -> arc_count , "" ); 278 printname( parentp ); 279 printf( "\n" ); 280 } else { 281 /* 282 * regular parent of child 283 */ 284 printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , 285 "" , "" , 286 arcp -> arc_time / hz , arcp -> arc_childtime / hz , 287 arcp -> arc_count , cycleheadp -> ncall ); 288 printname( parentp ); 289 printf( "\n" ); 290 } 291 } 292 } 293 294 printchildren( parentp ) 295 nltype *parentp; 296 { 297 nltype *childp; 298 arctype *arcp; 299 300 sortchildren( parentp ); 301 arcp = parentp -> children; 302 for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 303 childp = arcp -> arc_childp; 304 if ( childp == parentp || 305 ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) { 306 /* 307 * self call or call to sibling 308 */ 309 printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , 310 "" , "" , "" , "" , arcp -> arc_count , "" ); 311 printname( childp ); 312 printf( "\n" ); 313 } else { 314 /* 315 * regular child of parent 316 */ 317 printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , 318 "" , "" , 319 arcp -> arc_time / hz , arcp -> arc_childtime / hz , 320 arcp -> arc_count , childp -> cyclehead -> ncall ); 321 printname( childp ); 322 printf( "\n" ); 323 } 324 } 325 } 326 327 printname( selfp ) 328 nltype *selfp; 329 { 330 331 if ( selfp -> name != 0 ) { 332 printf( "%s" , selfp -> name ); 333 # ifdef DEBUG 334 if ( debug & DFNDEBUG ) { 335 printf( "{%d} " , selfp -> toporder ); 336 } 337 if ( debug & PROPDEBUG ) { 338 printf( "%5.2f%% " , selfp -> propfraction ); 339 } 340 # endif DEBUG 341 } 342 if ( selfp -> cycleno != 0 ) { 343 printf( " <cycle %d>" , selfp -> cycleno ); 344 } 345 if ( selfp -> index != 0 ) { 346 if ( selfp -> printflag ) { 347 printf( " [%d]" , selfp -> index ); 348 } else { 349 printf( " (%d)" , selfp -> index ); 350 } 351 } 352 } 353 354 sortchildren( parentp ) 355 nltype *parentp; 356 { 357 arctype *arcp; 358 arctype *detachedp; 359 arctype sorted; 360 arctype *prevp; 361 362 /* 363 * unlink children from parent, 364 * then insertion sort back on to sorted's children. 365 * *arcp the arc you have detached and are inserting. 366 * *detachedp the rest of the arcs to be sorted. 367 * sorted arc list onto which you insertion sort. 368 * *prevp arc before the arc you are comparing. 369 */ 370 sorted.arc_childlist = 0; 371 for ( (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist); 372 arcp ; 373 (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) { 374 /* 375 * consider *arcp as disconnected 376 * insert it into sorted 377 */ 378 for ( prevp = &sorted ; 379 prevp -> arc_childlist ; 380 prevp = prevp -> arc_childlist ) { 381 if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) { 382 break; 383 } 384 } 385 arcp -> arc_childlist = prevp -> arc_childlist; 386 prevp -> arc_childlist = arcp; 387 } 388 /* 389 * reattach sorted children to parent 390 */ 391 parentp -> children = sorted.arc_childlist; 392 } 393 394 sortparents( childp ) 395 nltype *childp; 396 { 397 arctype *arcp; 398 arctype *detachedp; 399 arctype sorted; 400 arctype *prevp; 401 402 /* 403 * unlink parents from child, 404 * then insertion sort back on to sorted's parents. 405 * *arcp the arc you have detached and are inserting. 406 * *detachedp the rest of the arcs to be sorted. 407 * sorted arc list onto which you insertion sort. 408 * *prevp arc before the arc you are comparing. 409 */ 410 sorted.arc_parentlist = 0; 411 for ( (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist); 412 arcp ; 413 (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) { 414 /* 415 * consider *arcp as disconnected 416 * insert it into sorted 417 */ 418 for ( prevp = &sorted ; 419 prevp -> arc_parentlist ; 420 prevp = prevp -> arc_parentlist ) { 421 if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) { 422 break; 423 } 424 } 425 arcp -> arc_parentlist = prevp -> arc_parentlist; 426 prevp -> arc_parentlist = arcp; 427 } 428 /* 429 * reattach sorted arcs to child 430 */ 431 childp -> parents = sorted.arc_parentlist; 432 } 433 434 /* 435 * print a cycle header 436 */ 437 printcycle( cyclep ) 438 nltype *cyclep; 439 { 440 char kirkbuffer[ BUFSIZ ]; 441 442 sprintf( kirkbuffer , "[%d]" , cyclep -> index ); 443 printf( "%-6.6s %5.1f %7.2f %11.2f %7d" , 444 kirkbuffer , 445 100 * ( cyclep -> propself + cyclep -> propchild ) / printtime , 446 cyclep -> propself / hz , 447 cyclep -> propchild / hz , 448 cyclep -> ncall ); 449 if ( cyclep -> selfcalls != 0 ) { 450 printf( "+%-7d" , cyclep -> selfcalls ); 451 } else { 452 printf( " %7.7s" , "" ); 453 } 454 printf( " <cycle %d as a whole>\t[%d]\n" , 455 cyclep -> cycleno , cyclep -> index ); 456 } 457 458 /* 459 * print the members of a cycle 460 */ 461 printmembers( cyclep ) 462 nltype *cyclep; 463 { 464 nltype *memberp; 465 466 sortmembers( cyclep ); 467 for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) { 468 printf( "%6.6s %5.5s %7.2f %11.2f %7d" , 469 "" , "" , memberp -> propself / hz , memberp -> propchild / hz , 470 memberp -> ncall ); 471 if ( memberp -> selfcalls != 0 ) { 472 printf( "+%-7d" , memberp -> selfcalls ); 473 } else { 474 printf( " %7.7s" , "" ); 475 } 476 printf( " " ); 477 printname( memberp ); 478 printf( "\n" ); 479 } 480 } 481 482 /* 483 * sort members of a cycle 484 */ 485 sortmembers( cyclep ) 486 nltype *cyclep; 487 { 488 nltype *todo; 489 nltype *doing; 490 nltype *prev; 491 492 /* 493 * detach cycle members from cyclehead, 494 * and insertion sort them back on. 495 */ 496 todo = cyclep -> cnext; 497 cyclep -> cnext = 0; 498 for ( (doing = todo)&&(todo = doing -> cnext); 499 doing ; 500 (doing = todo )&&(todo = doing -> cnext )){ 501 for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) { 502 if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) { 503 break; 504 } 505 } 506 doing -> cnext = prev -> cnext; 507 prev -> cnext = doing; 508 } 509 } 510 511 /* 512 * major sort is on propself + propchild, 513 * next is sort on ncalls + selfcalls. 514 */ 515 int 516 membercmp( this , that ) 517 nltype *this; 518 nltype *that; 519 { 520 double thistime = this -> propself + this -> propchild; 521 double thattime = that -> propself + that -> propchild; 522 long thiscalls = this -> ncall + this -> selfcalls; 523 long thatcalls = that -> ncall + that -> selfcalls; 524 525 if ( thistime > thattime ) { 526 return GREATERTHAN; 527 } 528 if ( thistime < thattime ) { 529 return LESSTHAN; 530 } 531 if ( thiscalls > thatcalls ) { 532 return GREATERTHAN; 533 } 534 if ( thiscalls < thatcalls ) { 535 return LESSTHAN; 536 } 537 return EQUALTO; 538 } 539 /* 540 * compare two arcs to/from the same child/parent. 541 * - if one arc is a self arc, it's least. 542 * - if one arc is within a cycle, it's less than. 543 * - if both arcs are within a cycle, compare arc counts. 544 * - if neither arc is within a cycle, compare with 545 * arc_time + arc_childtime as major key 546 * arc count as minor key 547 */ 548 int 549 arccmp( thisp , thatp ) 550 arctype *thisp; 551 arctype *thatp; 552 { 553 nltype *thisparentp = thisp -> arc_parentp; 554 nltype *thischildp = thisp -> arc_childp; 555 nltype *thatparentp = thatp -> arc_parentp; 556 nltype *thatchildp = thatp -> arc_childp; 557 double thistime; 558 double thattime; 559 560 # ifdef DEBUG 561 if ( debug & TIMEDEBUG ) { 562 printf( "[arccmp] " ); 563 printname( thisparentp ); 564 printf( " calls " ); 565 printname ( thischildp ); 566 printf( " %f + %f %d/%d\n" , 567 thisp -> arc_time , thisp -> arc_childtime , 568 thisp -> arc_count , thischildp -> ncall ); 569 printf( "[arccmp] " ); 570 printname( thatparentp ); 571 printf( " calls " ); 572 printname( thatchildp ); 573 printf( " %f + %f %d/%d\n" , 574 thatp -> arc_time , thatp -> arc_childtime , 575 thatp -> arc_count , thatchildp -> ncall ); 576 printf( "\n" ); 577 } 578 # endif DEBUG 579 if ( thisparentp == thischildp ) { 580 /* this is a self call */ 581 return LESSTHAN; 582 } 583 if ( thatparentp == thatchildp ) { 584 /* that is a self call */ 585 return GREATERTHAN; 586 } 587 if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 && 588 thisparentp -> cycleno == thischildp -> cycleno ) { 589 /* this is a call within a cycle */ 590 if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && 591 thatparentp -> cycleno == thatchildp -> cycleno ) { 592 /* that is a call within the cycle, too */ 593 if ( thisp -> arc_count < thatp -> arc_count ) { 594 return LESSTHAN; 595 } 596 if ( thisp -> arc_count > thatp -> arc_count ) { 597 return GREATERTHAN; 598 } 599 return EQUALTO; 600 } else { 601 /* that isn't a call within the cycle */ 602 return LESSTHAN; 603 } 604 } else { 605 /* this isn't a call within a cycle */ 606 if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && 607 thatparentp -> cycleno == thatchildp -> cycleno ) { 608 /* that is a call within a cycle */ 609 return GREATERTHAN; 610 } else { 611 /* neither is a call within a cycle */ 612 thistime = thisp -> arc_time + thisp -> arc_childtime; 613 thattime = thatp -> arc_time + thatp -> arc_childtime; 614 if ( thistime < thattime ) 615 return LESSTHAN; 616 if ( thistime > thattime ) 617 return GREATERTHAN; 618 if ( thisp -> arc_count < thatp -> arc_count ) 619 return LESSTHAN; 620 if ( thisp -> arc_count > thatp -> arc_count ) 621 return GREATERTHAN; 622 return EQUALTO; 623 } 624 } 625 } 626 627 printblurb( blurbname ) 628 char *blurbname; 629 { 630 FILE *blurbfile; 631 int input; 632 633 blurbfile = fopen( blurbname , "r" ); 634 if ( blurbfile == NULL ) { 635 perror( blurbname ); 636 return; 637 } 638 while ( ( input = getc( blurbfile ) ) != EOF ) { 639 putchar( input ); 640 } 641 fclose( blurbfile ); 642 } 643 644 int 645 namecmp( npp1 , npp2 ) 646 nltype **npp1, **npp2; 647 { 648 return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); 649 } 650 651 printindex() 652 { 653 nltype **namesortnlp; 654 register nltype *nlp; 655 int index, nnames, todo, i, j; 656 char peterbuffer[ BUFSIZ ]; 657 658 /* 659 * Now, sort regular function name alphbetically 660 * to create an index. 661 */ 662 namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); 663 if ( namesortnlp == (nltype **) 0 ) { 664 fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); 665 } 666 for ( index = 0 , nnames = 0 ; index < nname ; index++ ) { 667 if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 ) 668 continue; 669 namesortnlp[nnames++] = &nl[index]; 670 } 671 qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp ); 672 for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) { 673 namesortnlp[todo++] = &cyclenl[index]; 674 } 675 printf( "\f\nIndex by function name\n\n" ); 676 index = ( todo + 2 ) / 3; 677 for ( i = 0; i < index ; i++ ) { 678 for ( j = i; j < todo ; j += index ) { 679 nlp = namesortnlp[ j ]; 680 if ( nlp -> printflag ) { 681 sprintf( peterbuffer , "[%d]" , nlp -> index ); 682 } else { 683 sprintf( peterbuffer , "(%d)" , nlp -> index ); 684 } 685 if ( j < nnames ) { 686 printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name ); 687 } else { 688 printf( "%6.6s " , peterbuffer ); 689 sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno ); 690 printf( "%-19.19s" , peterbuffer ); 691 } 692 } 693 printf( "\n" ); 694 } 695 cfree( namesortnlp ); 696 } 697