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