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