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