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