1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright 2018 Jason King 27 * Copyright 2018, Joyent, Inc. 28 */ 29 30 #include <ctype.h> 31 #include <string.h> 32 #include <sys/param.h> 33 #include <stdlib.h> 34 #include "conv.h" 35 #include "gprof.h" 36 37 double actime; 38 39 void print_demangled_name(int, nltype *); 40 static void stripped_name(char **, size_t *, nltype **); 41 42 /* 43 * Symbols that must never be printed, no matter what. 44 */ 45 char *splsym[] = { 46 PRF_ETEXT, 47 PRF_EXTSYM, 48 PRF_MEMTERM, 49 NULL 50 }; 51 52 static bool is_special_sym(nltype *nlp); 53 54 const char * 55 demangled_name(nltype *selfp) 56 { 57 if (!Cflag) 58 return (selfp->name); 59 60 return (conv_demangle_name(selfp->name)); 61 } 62 63 void 64 printprof(void) 65 { 66 nltype *np; 67 nltype **sortednlp; 68 int i, index; 69 int print_count = number_funcs_toprint; 70 bool print_flag = TRUE; 71 mod_info_t *mi; 72 73 actime = 0.0; 74 (void) printf("\f\n"); 75 flatprofheader(); 76 77 /* 78 * Sort the symbol table in by time 79 */ 80 sortednlp = (nltype **) calloc(total_names, sizeof (nltype *)); 81 if (sortednlp == (nltype **) 0) { 82 (void) fprintf(stderr, 83 "[printprof] ran out of memory for time sorting\n"); 84 } 85 86 index = 0; 87 for (mi = &modules; mi; mi = mi->next) { 88 for (i = 0; i < mi->nname; i++) 89 sortednlp[index++] = &(mi->nl[i]); 90 } 91 92 qsort(sortednlp, total_names, sizeof (nltype *), timecmp); 93 94 for (index = 0; (index < total_names) && print_flag; index += 1) { 95 np = sortednlp[index]; 96 flatprofline(np); 97 if (nflag) { 98 if (--print_count == 0) 99 print_flag = FALSE; 100 } 101 } 102 actime = 0.0; 103 free(sortednlp); 104 } 105 106 int 107 timecmp(const void *arg1, const void *arg2) 108 { 109 nltype **npp1 = (nltype **)arg1; 110 nltype **npp2 = (nltype **)arg2; 111 double timediff; 112 long calldiff; 113 114 timediff = (*npp2)->time - (*npp1)->time; 115 116 if (timediff > 0.0) 117 return (1); 118 119 if (timediff < 0.0) 120 return (-1); 121 122 calldiff = (*npp2)->ncall - (*npp1)->ncall; 123 124 if (calldiff > 0) 125 return (1); 126 127 if (calldiff < 0) 128 return (-1); 129 130 return (strcmp((*npp1)->name, (*npp2)->name)); 131 } 132 133 /* 134 * header for flatprofline 135 */ 136 void 137 flatprofheader() 138 { 139 140 if (bflag) 141 printblurb(FLAT_BLURB); 142 143 if (old_style) { 144 (void) printf( 145 "\ngranularity: each sample hit covers %d byte(s)", 146 (long)scale * sizeof (UNIT)); 147 if (totime > 0.0) { 148 (void) printf(" for %.2f%% of %.2f seconds\n\n", 149 100.0/totime, totime / hz); 150 } else { 151 (void) printf(" no time accumulated\n\n"); 152 /* 153 * this doesn't hurt since all the numerators will 154 * be zero. 155 */ 156 totime = 1.0; 157 } 158 } 159 160 (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", 161 "% ", "cumulative", "self ", "", "self ", "total ", ""); 162 (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", 163 "time", "seconds ", "seconds", "calls", 164 "ms/call", "ms/call", "name"); 165 } 166 167 void 168 flatprofline(nltype *np) 169 { 170 if (zflag == 0 && np->ncall == 0 && np->time == 0) 171 return; 172 173 /* 174 * Do not print certain special symbols, like PRF_EXTSYM, etc. 175 * even if zflag was on. 176 */ 177 if (is_special_sym(np)) 178 return; 179 180 actime += np->time; 181 182 (void) printf("%5.1f %10.2f %8.2f", 183 100 * np->time / totime, actime / hz, np->time / hz); 184 185 if (np->ncall != 0) { 186 (void) printf(" %8lld %8.2f %8.2f ", np->ncall, 187 1000 * np->time / hz / np->ncall, 188 1000 * (np->time + np->childtime) / hz / np->ncall); 189 } else { 190 if (!Cflag) 191 (void) printf(" %8.8s %8.8s %8.8s ", "", "", ""); 192 else 193 (void) printf(" %8.8s %8.8s %8.8s ", "", "", ""); 194 } 195 196 printname(np); 197 198 if (Cflag) 199 print_demangled_name(55, np); 200 201 (void) printf("\n"); 202 } 203 204 void 205 gprofheader() 206 { 207 208 if (bflag) 209 printblurb(CALLG_BLURB); 210 211 if (old_style) { 212 213 (void) printf( 214 "\ngranularity: each sample hit covers %d byte(s)", 215 (long)scale * sizeof (UNIT)); 216 217 if (printtime > 0.0) { 218 (void) printf(" for %.2f%% of %.2f seconds\n\n", 219 100.0/printtime, printtime / hz); 220 } else { 221 (void) printf(" no time propagated\n\n"); 222 /* 223 * this doesn't hurt, since all the numerators 224 * will be 0.0 225 */ 226 printtime = 1.0; 227 } 228 } else { 229 (void) printf( 230 "\ngranularity: each pc-hit is considered 1 tick"); 231 if (hz != 1) { 232 (void) printf(" (@ %4.3f seconds per tick)", 233 (double)1.0 / hz); 234 } 235 (void) puts("\n\n"); 236 } 237 238 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", 239 "", "", "", "", "called", "total", "parents"); 240 (void) printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n", 241 "index", "%time", "self", "descendents", 242 "called", "self", "name", "index"); 243 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", 244 "", "", "", "", "called", "total", "children"); 245 (void) printf("\n"); 246 } 247 248 void 249 gprofline(nltype *np) 250 { 251 char kirkbuffer[BUFSIZ]; 252 253 (void) sprintf(kirkbuffer, "[%d]", np->index); 254 (void) printf("%-6.6s %5.1f %7.2f %11.2f", kirkbuffer, 255 100 * (np->propself + np->propchild) / printtime, 256 np->propself / hz, np->propchild / hz); 257 258 if ((np->ncall + np->selfcalls) != 0) { 259 (void) printf(" %7lld", np->ncall); 260 261 if (np->selfcalls != 0) 262 (void) printf("+%-7lld ", np->selfcalls); 263 else 264 (void) printf(" %7.7s ", ""); 265 } else { 266 (void) printf(" %7.7s %7.7s ", "", ""); 267 } 268 269 printname(np); 270 271 if (Cflag) 272 print_demangled_name(50, np); 273 274 (void) printf("\n"); 275 } 276 277 static bool 278 is_special_sym(nltype *nlp) 279 { 280 int i; 281 282 if (nlp->name == NULL) 283 return (FALSE); 284 285 for (i = 0; splsym[i]; i++) 286 if (strcmp(splsym[i], nlp->name) == 0) 287 return (TRUE); 288 289 return (FALSE); 290 } 291 292 void 293 printgprof(nltype **timesortnlp) 294 { 295 int index; 296 nltype *parentp; 297 int print_count = number_funcs_toprint; 298 bool count_flag = TRUE; 299 300 /* 301 * Print out the structured profiling list 302 */ 303 gprofheader(); 304 305 for (index = 0; index < total_names + ncycle && count_flag; index++) { 306 parentp = timesortnlp[index]; 307 if (zflag == 0 && parentp->ncall == 0 && 308 parentp->selfcalls == 0 && parentp->propself == 0 && 309 parentp -> propchild == 0) 310 continue; 311 312 if (!parentp->printflag) 313 continue; 314 315 /* 316 * Do not print certain special symbols, like PRF_EXTSYM, etc. 317 * even if zflag was on. 318 */ 319 if (is_special_sym(parentp)) 320 continue; 321 322 if (parentp->name == 0 && parentp->cycleno != 0) { 323 /* 324 * cycle header 325 */ 326 printcycle(parentp); 327 printmembers(parentp); 328 } else { 329 printparents(parentp); 330 gprofline(parentp); 331 printchildren(parentp); 332 } 333 334 (void) printf("\n"); 335 (void) printf( 336 "-----------------------------------------------\n"); 337 (void) printf("\n"); 338 339 if (nflag) { 340 --print_count; 341 if (print_count == 0) 342 count_flag = FALSE; 343 } 344 } 345 free(timesortnlp); 346 } 347 348 /* 349 * sort by decreasing propagated time 350 * if times are equal, but one is a cycle header, 351 * say that's first (e.g. less, i.e. -1). 352 * if one's name doesn't have an underscore and the other does, 353 * say the one is first. 354 * all else being equal, sort by names. 355 */ 356 int 357 totalcmp(const void *arg1, const void *arg2) 358 { 359 nltype **npp1 = (nltype **)arg1; 360 nltype **npp2 = (nltype **)arg2; 361 nltype *np1 = *npp1; 362 nltype *np2 = *npp2; 363 double diff; 364 365 diff = (np1->propself + np1->propchild) - 366 (np2->propself + np2->propchild); 367 368 if (diff < 0.0) 369 return (1); 370 if (diff > 0.0) 371 return (-1); 372 if (np1->name == 0 && np1->cycleno != 0) 373 return (-1); 374 if (np2->name == 0 && np2->cycleno != 0) 375 return (1); 376 if (np1->name == 0) 377 return (-1); 378 if (np2->name == 0) 379 return (1); 380 381 if (*(np1->name) != '_' && *(np2->name) == '_') 382 return (-1); 383 if (*(np1->name) == '_' && *(np2->name) != '_') 384 return (1); 385 if (np1->ncall > np2->ncall) 386 return (-1); 387 if (np1->ncall < np2->ncall) 388 return (1); 389 return (strcmp(np1->name, np2->name)); 390 } 391 392 void 393 printparents(nltype *childp) 394 { 395 nltype *parentp; 396 arctype *arcp; 397 nltype *cycleheadp; 398 399 if (childp->cyclehead != 0) 400 cycleheadp = childp -> cyclehead; 401 else 402 cycleheadp = childp; 403 404 if (childp->parents == 0) { 405 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s" 406 " <spontaneous>\n", "", "", "", "", "", ""); 407 return; 408 } 409 410 sortparents(childp); 411 412 for (arcp = childp->parents; arcp; arcp = arcp->arc_parentlist) { 413 parentp = arcp -> arc_parentp; 414 if (childp == parentp || (childp->cycleno != 0 && 415 parentp->cycleno == childp->cycleno)) { 416 /* 417 * selfcall or call among siblings 418 */ 419 (void) printf( 420 "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ", 421 "", "", "", "", arcp->arc_count, ""); 422 printname(parentp); 423 424 if (Cflag) 425 print_demangled_name(54, parentp); 426 427 (void) printf("\n"); 428 } else { 429 /* 430 * regular parent of child 431 */ 432 (void) printf( 433 "%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld ", "", 434 "", arcp->arc_time / hz, arcp->arc_childtime / hz, 435 arcp->arc_count, cycleheadp->ncall); 436 printname(parentp); 437 438 if (Cflag) 439 print_demangled_name(54, parentp); 440 441 (void) printf("\n"); 442 } 443 } 444 } 445 446 void 447 printchildren(nltype *parentp) 448 { 449 nltype *childp; 450 arctype *arcp; 451 452 sortchildren(parentp); 453 454 for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) { 455 childp = arcp->arc_childp; 456 if (childp == parentp || (childp->cycleno != 0 && 457 childp->cycleno == parentp->cycleno)) { 458 /* 459 * self call or call to sibling 460 */ 461 (void) printf( 462 "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ", 463 "", "", "", "", arcp->arc_count, ""); 464 printname(childp); 465 466 if (Cflag) 467 print_demangled_name(54, childp); 468 469 (void) printf("\n"); 470 } else { 471 /* 472 * regular child of parent 473 */ 474 if (childp->cyclehead) 475 (void) printf("%6.6s %5.5s %7.2f %11.2f " 476 "%7lld/%-7lld ", "", "", 477 arcp->arc_time / hz, 478 arcp->arc_childtime / hz, arcp->arc_count, 479 childp->cyclehead->ncall); 480 else 481 (void) printf("%6.6s %5.5s %7.2f %11.2f " 482 "%7lld %7.7s ", 483 "", "", arcp->arc_time / hz, 484 arcp->arc_childtime / hz, arcp->arc_count, 485 ""); 486 487 printname(childp); 488 489 if (Cflag) 490 print_demangled_name(54, childp); 491 492 (void) printf("\n"); 493 } 494 } 495 } 496 497 void 498 printname(nltype *selfp) 499 { 500 const char *c; 501 c = demangled_name(selfp); 502 503 if (selfp->name != 0) { 504 (void) printf("%s", c); 505 506 #ifdef DEBUG 507 if (debug & DFNDEBUG) 508 (void) printf("{%d} ", selfp->toporder); 509 510 if (debug & PROPDEBUG) 511 (void) printf("%5.2f%% ", selfp->propfraction); 512 #endif /* DEBUG */ 513 } 514 515 if (selfp->cycleno != 0) 516 (void) printf("\t<cycle %d>", selfp->cycleno); 517 518 if (selfp->index != 0) { 519 if (selfp->printflag) 520 (void) printf(" [%d]", selfp->index); 521 else 522 (void) printf(" (%d)", selfp->index); 523 } 524 525 if (c != selfp->name) 526 free((void *)c); 527 } 528 529 void 530 print_demangled_name(int n, nltype *selfp) 531 { 532 char *c = (char *)demangled_name(selfp); 533 int i; 534 535 if (c == selfp->name) 536 return; 537 538 (void) printf("\n"); 539 for (i = 1; i < n; i++) 540 (void) printf(" "); 541 (void) printf("[%s]", selfp->name); 542 543 free(c); 544 } 545 546 void 547 sortchildren(nltype *parentp) 548 { 549 arctype *arcp; 550 arctype *detachedp; 551 arctype sorted; 552 arctype *prevp; 553 554 /* 555 * unlink children from parent, 556 * then insertion sort back on to sorted's children. 557 * *arcp the arc you have detached and are inserting. 558 * *detachedp the rest of the arcs to be sorted. 559 * sorted arc list onto which you insertion sort. 560 * *prevp arc before the arc you are comparing. 561 */ 562 sorted.arc_childlist = 0; 563 564 arcp = parentp->children; 565 if (arcp != NULL) 566 detachedp = arcp->arc_childlist; 567 while (arcp != NULL) { 568 /* 569 * consider *arcp as disconnected 570 * insert it into sorted 571 */ 572 for (prevp = &sorted; prevp->arc_childlist; 573 prevp = prevp->arc_childlist) { 574 if (arccmp(arcp, prevp->arc_childlist) != LESSTHAN) 575 break; 576 } 577 578 arcp->arc_childlist = prevp->arc_childlist; 579 prevp->arc_childlist = arcp; 580 581 arcp = detachedp; 582 if (arcp != NULL) 583 detachedp = detachedp->arc_childlist; 584 } 585 586 /* 587 * reattach sorted children to parent 588 */ 589 parentp->children = sorted.arc_childlist; 590 } 591 592 void 593 sortparents(nltype *childp) 594 { 595 arctype *arcp; 596 arctype *detachedp; 597 arctype sorted; 598 arctype *prevp; 599 600 /* 601 * unlink parents from child, 602 * then insertion sort back on to sorted's parents. 603 * *arcp the arc you have detached and are inserting. 604 * *detachedp the rest of the arcs to be sorted. 605 * sorted arc list onto which you insertion sort. 606 * *prevp arc before the arc you are comparing. 607 */ 608 sorted.arc_parentlist = 0; 609 610 arcp = childp->parents; 611 if (arcp != NULL) 612 detachedp = arcp->arc_parentlist; 613 while (arcp != NULL) { 614 /* 615 * consider *arcp as disconnected 616 * insert it into sorted 617 */ 618 for (prevp = &sorted; prevp->arc_parentlist; 619 prevp = prevp->arc_parentlist) { 620 if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN) 621 break; 622 } 623 arcp->arc_parentlist = prevp->arc_parentlist; 624 prevp->arc_parentlist = arcp; 625 arcp = detachedp; 626 if (detachedp != NULL) 627 detachedp = detachedp->arc_parentlist; 628 } 629 630 /* 631 * reattach sorted arcs to child 632 */ 633 childp->parents = sorted.arc_parentlist; 634 } 635 636 void 637 printcycle(nltype *cyclep) 638 { 639 char kirkbuffer[BUFSIZ]; 640 641 (void) sprintf(kirkbuffer, "[%d]", cyclep->index); 642 (void) printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer, 643 100 * (cyclep->propself + cyclep->propchild) / printtime, 644 cyclep -> propself / hz, cyclep -> propchild / hz, 645 cyclep -> ncall); 646 647 if (cyclep->selfcalls != 0) 648 (void) printf("+%-7lld", cyclep->selfcalls); 649 else 650 (void) printf(" %7.7s", ""); 651 652 (void) printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno, 653 cyclep->index); 654 } 655 656 /* 657 * print the members of a cycle 658 */ 659 void 660 printmembers(nltype *cyclep) 661 { 662 nltype *memberp; 663 664 sortmembers(cyclep); 665 666 for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) { 667 (void) printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "", 668 memberp->propself / hz, memberp->propchild / hz, 669 memberp->ncall); 670 671 if (memberp->selfcalls != 0) 672 (void) printf("+%-7lld", memberp->selfcalls); 673 else 674 (void) printf(" %7.7s", ""); 675 676 (void) printf(" "); 677 printname(memberp); 678 if (Cflag) 679 print_demangled_name(54, memberp); 680 (void) printf("\n"); 681 } 682 } 683 684 /* 685 * sort members of a cycle 686 */ 687 void 688 sortmembers(nltype *cyclep) 689 { 690 nltype *todo; 691 nltype *doing; 692 nltype *prev; 693 694 /* 695 * detach cycle members from cyclehead, 696 * and insertion sort them back on. 697 */ 698 todo = cyclep->cnext; 699 cyclep->cnext = 0; 700 701 doing = todo; 702 if (doing != NULL) 703 todo = doing->cnext; 704 while (doing != NULL) { 705 for (prev = cyclep; prev->cnext; prev = prev->cnext) { 706 if (membercmp(doing, prev->cnext) == GREATERTHAN) 707 break; 708 } 709 doing->cnext = prev->cnext; 710 prev->cnext = doing; 711 doing = todo; 712 if (doing != NULL) 713 todo = doing->cnext; 714 } 715 } 716 717 /* 718 * major sort is on propself + propchild, 719 * next is sort on ncalls + selfcalls. 720 */ 721 int 722 membercmp(nltype *this, nltype *that) 723 { 724 double thistime = this->propself + this->propchild; 725 double thattime = that->propself + that->propchild; 726 actype thiscalls = this->ncall + this->selfcalls; 727 actype thatcalls = that->ncall + that->selfcalls; 728 729 if (thistime > thattime) 730 return (GREATERTHAN); 731 732 if (thistime < thattime) 733 return (LESSTHAN); 734 735 if (thiscalls > thatcalls) 736 return (GREATERTHAN); 737 738 if (thiscalls < thatcalls) 739 return (LESSTHAN); 740 741 return (EQUALTO); 742 } 743 744 /* 745 * compare two arcs to/from the same child/parent. 746 * - if one arc is a self arc, it's least. 747 * - if one arc is within a cycle, it's less than. 748 * - if both arcs are within a cycle, compare arc counts. 749 * - if neither arc is within a cycle, compare with 750 * arc_time + arc_childtime as major key 751 * arc count as minor key 752 */ 753 int 754 arccmp(arctype *thisp, arctype *thatp) 755 { 756 nltype *thisparentp = thisp->arc_parentp; 757 nltype *thischildp = thisp->arc_childp; 758 nltype *thatparentp = thatp->arc_parentp; 759 nltype *thatchildp = thatp->arc_childp; 760 double thistime; 761 double thattime; 762 763 #ifdef DEBUG 764 if (debug & TIMEDEBUG) { 765 (void) printf("[arccmp] "); 766 printname(thisparentp); 767 (void) printf(" calls "); 768 printname(thischildp); 769 (void) printf(" %f + %f %lld/%lld\n", thisp->arc_time, 770 thisp->arc_childtime, thisp->arc_count, 771 thischildp->ncall); 772 (void) printf("[arccmp] "); 773 printname(thatparentp); 774 (void) printf(" calls "); 775 printname(thatchildp); 776 (void) printf(" %f + %f %lld/%lld\n", thatp->arc_time, 777 thatp->arc_childtime, thatp->arc_count, 778 thatchildp->ncall); 779 (void) printf("\n"); 780 } 781 #endif /* DEBUG */ 782 783 if (thisparentp == thischildp) { 784 /* 785 * this is a self call 786 */ 787 return (LESSTHAN); 788 } 789 790 if (thatparentp == thatchildp) { 791 /* 792 * that is a self call 793 */ 794 return (GREATERTHAN); 795 } 796 797 if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 && 798 thisparentp->cycleno == thischildp->cycleno) { 799 /* 800 * this is a call within a cycle 801 */ 802 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 && 803 thatparentp->cycleno == thatchildp->cycleno) { 804 /* 805 * that is a call within the cycle, too 806 */ 807 if (thisp->arc_count < thatp->arc_count) 808 return (LESSTHAN); 809 810 if (thisp->arc_count > thatp->arc_count) 811 return (GREATERTHAN); 812 813 return (EQUALTO); 814 } else { 815 /* 816 * that isn't a call within the cycle 817 */ 818 return (LESSTHAN); 819 } 820 } else { 821 /* 822 * this isn't a call within a cycle 823 */ 824 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 && 825 thatparentp->cycleno == thatchildp->cycleno) { 826 /* 827 * that is a call within a cycle 828 */ 829 return (GREATERTHAN); 830 } else { 831 /* 832 * neither is a call within a cycle 833 */ 834 thistime = thisp->arc_time + thisp->arc_childtime; 835 thattime = thatp->arc_time + thatp->arc_childtime; 836 837 if (thistime < thattime) 838 return (LESSTHAN); 839 840 if (thistime > thattime) 841 return (GREATERTHAN); 842 843 if (thisp->arc_count < thatp->arc_count) 844 return (LESSTHAN); 845 846 if (thisp->arc_count > thatp->arc_count) 847 return (GREATERTHAN); 848 849 return (EQUALTO); 850 } 851 } 852 } 853 854 void 855 printblurb(char *blurbname) 856 { 857 FILE *blurbfile; 858 int input; 859 860 blurbfile = fopen(blurbname, "r"); 861 if (blurbfile == NULL) { 862 perror(blurbname); 863 return; 864 } 865 866 while ((input = getc(blurbfile)) != EOF) 867 (void) putchar(input); 868 869 (void) fclose(blurbfile); 870 } 871 872 static int 873 namecmp(const void *arg1, const void *arg2) 874 { 875 nltype **npp1 = (nltype **)arg1; 876 nltype **npp2 = (nltype **)arg2; 877 878 if (!Cflag) 879 return (strcmp((*npp1)->name, (*npp2)->name)); 880 else { 881 static char *s1 = NULL, *s2 = NULL; 882 static size_t s1len = 0, s2len = 0; 883 884 stripped_name(&s1, &s1len, npp1); 885 stripped_name(&s2, &s2len, npp2); 886 return (strcmp(s1, s2)); 887 } 888 } 889 890 #define NAME_CHUNK 512 891 #define ROUNDLEN(x) (((x) + NAME_CHUNK - 1) / NAME_CHUNK * NAME_CHUNK) 892 static void 893 adjust_size(char **pp, size_t *lenp, const char *name) 894 { 895 void *newp; 896 size_t nlen = strlen(name); 897 size_t buflen; 898 899 if (*lenp > nlen) { 900 (void) memset(*pp, '\0', *lenp); 901 return; 902 } 903 904 buflen = ROUNDLEN(nlen + 1); 905 if ((newp = realloc(*pp, buflen)) == NULL) { 906 (void) fprintf(stderr, 907 "gprof: out of memory comparing names\n"); 908 exit(EXIT_FAILURE); 909 } 910 (void) memset(newp, '\0', buflen); 911 912 *lenp = buflen; 913 *pp = newp; 914 } 915 916 static void 917 stripped_name(char **sp, size_t *slenp, nltype **npp) 918 { 919 const char *name, *d; 920 char *c; 921 922 name = d = demangled_name(*npp); 923 adjust_size(sp, slenp, name); 924 c = *sp; 925 926 while ((*d != '(') && (*d != '\0')) { 927 if (*d != ':') 928 *c++ = *d++; 929 else 930 d++; 931 } 932 *c = '\0'; 933 934 if ((*npp)->name != name) 935 free((void *)name); 936 } 937 938 /* 939 * Checks if the current symbol name is the same as its neighbour and 940 * returns TRUE if it is. 941 */ 942 static bool 943 does_clash(nltype **nlp, int ndx, int nnames) 944 { 945 /* 946 * same as previous (if there's one) ? 947 */ 948 if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0)) 949 return (TRUE); 950 951 /* 952 * same as next (if there's one) ? 953 */ 954 if ((ndx < (nnames - 1)) && 955 (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) { 956 return (TRUE); 957 } 958 959 return (FALSE); 960 } 961 962 void 963 printmodules() 964 { 965 mod_info_t *mi; 966 967 (void) printf("\f\nObject modules\n\n"); 968 for (mi = &modules; mi; mi = mi->next) 969 (void) printf(" %d: %s\n", mi->id, mi->name); 970 } 971 972 #define IDFMT(id) ((id) < 10 ? 1 : 2) 973 #define NMFMT(id) ((id) < 10 ? 17 : 16) 974 975 void 976 printindex() 977 { 978 nltype **namesortnlp; 979 nltype *nlp; 980 int index, nnames, todo, i, j; 981 char peterbuffer[BUFSIZ]; 982 mod_info_t *mi; 983 984 /* 985 * Now, sort regular function name alphabetically 986 * to create an index. 987 */ 988 namesortnlp = calloc(total_names + ncycle, sizeof (nltype *)); 989 990 if (namesortnlp == NULL) 991 (void) fprintf(stderr, "%s: ran out of memory for sorting\n", 992 whoami); 993 994 nnames = 0; 995 for (mi = &modules; mi; mi = mi->next) { 996 for (index = 0; index < mi->nname; index++) { 997 if (zflag == 0 && (mi->nl[index]).ncall == 0 && 998 (mi->nl[index]).time == 0) { 999 continue; 1000 } 1001 1002 /* 1003 * Do not print certain special symbols, like 1004 * PRF_EXTSYM, etc. even if zflag was on. 1005 */ 1006 if (is_special_sym(&(mi->nl[index]))) 1007 continue; 1008 1009 namesortnlp[nnames++] = &(mi->nl[index]); 1010 } 1011 } 1012 1013 qsort(namesortnlp, nnames, sizeof (nltype *), namecmp); 1014 1015 for (index = 1, todo = nnames; index <= ncycle; index++) 1016 namesortnlp[todo++] = &cyclenl[index]; 1017 1018 (void) printf("\f\nIndex by function name\n\n"); 1019 1020 if (!Cflag) 1021 index = (todo + 2) / 3; 1022 else 1023 index = todo; 1024 1025 for (i = 0; i < index; i++) { 1026 if (!Cflag) { 1027 for (j = i; j < todo; j += index) { 1028 nlp = namesortnlp[j]; 1029 1030 if (nlp->printflag) { 1031 (void) sprintf(peterbuffer, 1032 "[%d]", nlp->index); 1033 } else { 1034 (void) sprintf(peterbuffer, 1035 "(%d)", nlp->index); 1036 } 1037 1038 if (j < nnames) { 1039 if (does_clash(namesortnlp, 1040 j, nnames)) { 1041 (void) printf( 1042 "%6.6s %*d:%-*.*s", 1043 peterbuffer, 1044 IDFMT(nlp->module->id), 1045 nlp->module->id, 1046 NMFMT(nlp->module->id), 1047 NMFMT(nlp->module->id), 1048 nlp->name); 1049 } else { 1050 (void) printf("%6.6s %-19.19s", 1051 peterbuffer, nlp->name); 1052 } 1053 } else { 1054 (void) printf("%6.6s ", peterbuffer); 1055 (void) sprintf(peterbuffer, 1056 "<cycle %d>", nlp->cycleno); 1057 (void) printf("%-19.19s", peterbuffer); 1058 } 1059 } 1060 } else { 1061 nlp = namesortnlp[i]; 1062 1063 if (nlp->printflag) 1064 (void) sprintf(peterbuffer, "[%d]", nlp->index); 1065 else 1066 (void) sprintf(peterbuffer, "(%d)", nlp->index); 1067 1068 if (i < nnames) { 1069 const char *d = demangled_name(nlp); 1070 1071 if (does_clash(namesortnlp, i, nnames)) { 1072 (void) printf("%6.6s %d:%s\n", 1073 peterbuffer, nlp->module->id, d); 1074 } else { 1075 (void) printf("%6.6s %s\n", peterbuffer, 1076 d); 1077 } 1078 1079 if (d != nlp->name) { 1080 (void) printf("%6.6s [%s]", "", 1081 nlp->name); 1082 free((void *)d); 1083 } 1084 } else { 1085 (void) printf("%6.6s ", peterbuffer); 1086 (void) sprintf(peterbuffer, "<cycle %d>", 1087 nlp->cycleno); 1088 (void) printf("%-33.33s", peterbuffer); 1089 } 1090 } 1091 (void) printf("\n"); 1092 } 1093 free(namesortnlp); 1094 } 1095