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