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  */
  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                 (void) printf("%s", c);
 504 
 505 #ifdef DEBUG
 506                 if (debug & DFNDEBUG)
 507                         (void) printf("{%d} ", selfp->toporder);
 508 
 509                 if (debug & PROPDEBUG)
 510                         (void) printf("%5.2f%% ", selfp->propfraction);
 511 #endif /* DEBUG */
 512         }
 513 
 514         if (selfp->cycleno != 0)
 515                 (void) printf("\t<cycle %d>", selfp->cycleno);
 516 
 517         if (selfp->index != 0) {
 518                 if (selfp->printflag)
 519                         (void) printf(" [%d]", selfp->index);
 520                 else
 521                         (void) printf(" (%d)", selfp->index);
 522         }
 523 
 524         if (c != selfp->name)
 525                 free((void *)c);
 526 }
 527 
 528 void
 529 print_demangled_name(int n, nltype *selfp)
 530 {
 531         char *c = demangled_name(selfp);
 532         int i;
 533 
 534         if (c == selfp->name)
 535                 return;
 536 
 537         (void) printf("\n");
 538         for (i = 1; i < n; i++)
 539                 (void) printf(" ");
 540         (void) printf("[%s]", selfp->name);
 541 
 542         free((void *)c);
 543 }
 544 
 545 void
 546 sortchildren(nltype *parentp)
 547 {
 548         arctype *arcp;
 549         arctype *detachedp;
 550         arctype sorted;
 551         arctype *prevp;
 552 
 553         /*
 554          *      unlink children from parent,
 555          *      then insertion sort back on to sorted's children.
 556          *          *arcp       the arc you have detached and are inserting.
 557          *          *detachedp  the rest of the arcs to be sorted.
 558          *          sorted      arc list onto which you insertion sort.
 559          *          *prevp      arc before the arc you are comparing.
 560          */
 561         sorted.arc_childlist = 0;
 562 
 563         /* LINTED: warning: assignment operator */
 564         for ((arcp = parentp->children) && (detachedp = arcp->arc_childlist);
 565             arcp;
 566             /* LINTED: warning: assignment operator */
 567             (arcp = detachedp) && (detachedp = detachedp->arc_childlist)) {
 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 
 582         /*
 583          *      reattach sorted children to parent
 584          */
 585         parentp->children = sorted.arc_childlist;
 586 }
 587 
 588 void
 589 sortparents(nltype *childp)
 590 {
 591         arctype *arcp;
 592         arctype *detachedp;
 593         arctype sorted;
 594         arctype *prevp;
 595 
 596         /*
 597          *      unlink parents from child,
 598          *      then insertion sort back on to sorted's parents.
 599          *          *arcp       the arc you have detached and are inserting.
 600          *          *detachedp  the rest of the arcs to be sorted.
 601          *          sorted      arc list onto which you insertion sort.
 602          *          *prevp      arc before the arc you are comparing.
 603          */
 604         sorted.arc_parentlist = 0;
 605 
 606         /* LINTED: warning: assignment operator */
 607         for ((arcp = childp->parents) && (detachedp = arcp->arc_parentlist);
 608             arcp;
 609             /* LINTED: warning: assignment operator */
 610             (arcp = detachedp) && (detachedp = detachedp->arc_parentlist)) {
 611                 /*
 612                  *      consider *arcp as disconnected
 613                  *      insert it into sorted
 614                  */
 615                 for (prevp = &sorted; prevp->arc_parentlist;
 616                     prevp = prevp->arc_parentlist) {
 617                         if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN)
 618                                 break;
 619                 }
 620                 arcp->arc_parentlist = prevp->arc_parentlist;
 621                 prevp->arc_parentlist = arcp;
 622         }
 623 
 624         /*
 625          *      reattach sorted arcs to child
 626          */
 627         childp->parents = sorted.arc_parentlist;
 628 }
 629 
 630 void
 631 printcycle(nltype *cyclep)
 632 {
 633         char    kirkbuffer[BUFSIZ];
 634 
 635         (void) sprintf(kirkbuffer, "[%d]", cyclep->index);
 636         (void) printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer,
 637             100 * (cyclep->propself + cyclep->propchild) / printtime,
 638             cyclep -> propself / hz, cyclep -> propchild / hz,
 639             cyclep -> ncall);
 640 
 641         if (cyclep->selfcalls != 0)
 642                 (void) printf("+%-7lld", cyclep->selfcalls);
 643         else
 644                 (void) printf(" %7.7s", "");
 645 
 646         (void) printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno,
 647             cyclep->index);
 648 }
 649 
 650 /*
 651  *      print the members of a cycle
 652  */
 653 void
 654 printmembers(nltype *cyclep)
 655 {
 656         nltype  *memberp;
 657 
 658         sortmembers(cyclep);
 659 
 660         for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) {
 661                 (void) printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "",
 662                     memberp->propself / hz, memberp->propchild / hz,
 663                     memberp->ncall);
 664 
 665                 if (memberp->selfcalls != 0)
 666                         (void) printf("+%-7lld", memberp->selfcalls);
 667                 else
 668                         (void) printf(" %7.7s", "");
 669 
 670                 (void) printf("     ");
 671                 printname(memberp);
 672                 if (Cflag)
 673                         print_demangled_name(54, memberp);
 674                 (void) printf("\n");
 675         }
 676 }
 677 
 678 /*
 679  * sort members of a cycle
 680  */
 681 void
 682 sortmembers(nltype *cyclep)
 683 {
 684         nltype  *todo;
 685         nltype  *doing;
 686         nltype  *prev;
 687 
 688         /*
 689          *      detach cycle members from cyclehead,
 690          *      and insertion sort them back on.
 691          */
 692         todo = cyclep->cnext;
 693         cyclep->cnext = 0;
 694 
 695         /* LINTED: warning: assignment operator */
 696         for ((doing = todo) && (todo = doing->cnext);
 697             doing;
 698             /* LINTED: warning: assignment operator */
 699             (doing = todo) && (todo = doing->cnext)) {
 700                 for (prev = cyclep; prev->cnext; prev = prev->cnext) {
 701                         if (membercmp(doing, prev->cnext) == GREATERTHAN)
 702                                 break;
 703                 }
 704                 doing->cnext = prev->cnext;
 705                 prev->cnext = doing;
 706         }
 707 }
 708 
 709 /*
 710  *      major sort is on propself + propchild,
 711  *      next is sort on ncalls + selfcalls.
 712  */
 713 int
 714 membercmp(nltype *this, nltype *that)
 715 {
 716         double  thistime = this->propself + this->propchild;
 717         double  thattime = that->propself + that->propchild;
 718         actype  thiscalls = this->ncall + this->selfcalls;
 719         actype  thatcalls = that->ncall + that->selfcalls;
 720 
 721         if (thistime > thattime)
 722                 return (GREATERTHAN);
 723 
 724         if (thistime < thattime)
 725                 return (LESSTHAN);
 726 
 727         if (thiscalls > thatcalls)
 728                 return (GREATERTHAN);
 729 
 730         if (thiscalls < thatcalls)
 731                 return (LESSTHAN);
 732 
 733         return (EQUALTO);
 734 }
 735 
 736 /*
 737  *      compare two arcs to/from the same child/parent.
 738  *      - if one arc is a self arc, it's least.
 739  *      - if one arc is within a cycle, it's less than.
 740  *      - if both arcs are within a cycle, compare arc counts.
 741  *      - if neither arc is within a cycle, compare with
 742  *              arc_time + arc_childtime as major key
 743  *              arc count as minor key
 744  */
 745 int
 746 arccmp(arctype *thisp, arctype *thatp)
 747 {
 748         nltype  *thisparentp = thisp->arc_parentp;
 749         nltype  *thischildp = thisp->arc_childp;
 750         nltype  *thatparentp = thatp->arc_parentp;
 751         nltype  *thatchildp = thatp->arc_childp;
 752         double  thistime;
 753         double  thattime;
 754 
 755 #ifdef DEBUG
 756         if (debug & TIMEDEBUG) {
 757                 (void) printf("[arccmp] ");
 758                 printname(thisparentp);
 759                 (void) printf(" calls ");
 760                 printname(thischildp);
 761                 (void) printf(" %f + %f %lld/%lld\n", thisp->arc_time,
 762                     thisp->arc_childtime, thisp->arc_count,
 763                     thischildp->ncall);
 764                 (void) printf("[arccmp] ");
 765                 printname(thatparentp);
 766                 (void) printf(" calls ");
 767                 printname(thatchildp);
 768                 (void) printf(" %f + %f %lld/%lld\n", thatp->arc_time,
 769                     thatp->arc_childtime, thatp->arc_count,
 770                     thatchildp->ncall);
 771                 (void) printf("\n");
 772         }
 773 #endif /* DEBUG */
 774 
 775         if (thisparentp == thischildp) {
 776                 /*
 777                  * this is a self call
 778                  */
 779                 return (LESSTHAN);
 780         }
 781 
 782         if (thatparentp == thatchildp) {
 783                 /*
 784                  * that is a self call
 785                  */
 786                 return (GREATERTHAN);
 787         }
 788 
 789         if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 &&
 790             thisparentp->cycleno == thischildp->cycleno) {
 791                 /*
 792                  * this is a call within a cycle
 793                  */
 794                 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
 795                     thatparentp->cycleno == thatchildp->cycleno) {
 796                         /*
 797                          * that is a call within the cycle, too
 798                          */
 799                         if (thisp->arc_count < thatp->arc_count)
 800                                 return (LESSTHAN);
 801 
 802                         if (thisp->arc_count > thatp->arc_count)
 803                                 return (GREATERTHAN);
 804 
 805                         return (EQUALTO);
 806                 } else {
 807                         /*
 808                          * that isn't a call within the cycle
 809                          */
 810                         return (LESSTHAN);
 811                 }
 812         } else {
 813                 /*
 814                  * this isn't a call within a cycle
 815                  */
 816                 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
 817                     thatparentp->cycleno == thatchildp->cycleno) {
 818                         /*
 819                          * that is a call within a cycle
 820                          */
 821                         return (GREATERTHAN);
 822                 } else {
 823                         /*
 824                          * neither is a call within a cycle
 825                          */
 826                         thistime = thisp->arc_time + thisp->arc_childtime;
 827                         thattime = thatp->arc_time + thatp->arc_childtime;
 828 
 829                         if (thistime < thattime)
 830                                 return (LESSTHAN);
 831 
 832                         if (thistime > thattime)
 833                                 return (GREATERTHAN);
 834 
 835                         if (thisp->arc_count < thatp->arc_count)
 836                                 return (LESSTHAN);
 837 
 838                         if (thisp->arc_count > thatp->arc_count)
 839                                 return (GREATERTHAN);
 840 
 841                         return (EQUALTO);
 842                 }
 843         }
 844 }
 845 
 846 void
 847 printblurb(char *blurbname)
 848 {
 849         FILE    *blurbfile;
 850         int     input;
 851 
 852         blurbfile = fopen(blurbname, "r");
 853         if (blurbfile == NULL) {
 854                 perror(blurbname);
 855                 return;
 856         }
 857 
 858         while ((input = getc(blurbfile)) != EOF)
 859                 (void) putchar(input);
 860 
 861         (void) fclose(blurbfile);
 862 }
 863 
 864 char *s1, *s2;
 865 
 866 static int
 867 namecmp(const void *arg1, const void *arg2)
 868 {
 869         nltype **npp1 = (nltype **)arg1;
 870         nltype **npp2 = (nltype **)arg2;
 871 
 872         if (!Cflag)
 873                 return (strcmp((*npp1)->name, (*npp2)->name));
 874         else {
 875                 striped_name(s1, npp1);
 876                 striped_name(s2, npp2);
 877                 return (strcmp(s1, s2));
 878         }
 879 }
 880 
 881 void
 882 striped_name(char *s, nltype **npp)
 883 {
 884         const char *name, *d;
 885         char *c;
 886 
 887         c = (char *)s;
 888         name = d = demangled_name(*npp);
 889 
 890         while ((*d != '(') && (*d != '\0')) {
 891                 if (*d != ':')
 892                         *c++ = *d++;
 893                 else
 894                         d++;
 895         }
 896         *c = '\0';
 897 
 898         if ((*npp)->name != name)
 899                 free((void *)name);
 900 }
 901 
 902 /*
 903  * Checks if the current symbol name is the same as its neighbour and
 904  * returns TRUE if it is.
 905  */
 906 static bool
 907 does_clash(nltype **nlp, int ndx, int nnames)
 908 {
 909         /*
 910          * same as previous (if there's one) ?
 911          */
 912         if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0))
 913                 return (TRUE);
 914 
 915         /*
 916          * same as next (if there's one) ?
 917          */
 918         if ((ndx < (nnames - 1)) &&
 919             (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) {
 920                 return (TRUE);
 921         }
 922 
 923         return (FALSE);
 924 }
 925 
 926 void
 927 printmodules()
 928 {
 929         mod_info_t      *mi;
 930 
 931         (void) printf("\f\nObject modules\n\n");
 932         for (mi = &modules; mi; mi = mi->next)
 933                 (void) printf(" %d: %s\n", mi->id, mi->name);
 934 }
 935 
 936 #define IDFMT(id)       ((id) < 10 ? 1 : 2)
 937 #define NMFMT(id)       ((id) < 10 ? 17 : 16)
 938 
 939 void
 940 printindex()
 941 {
 942         nltype  **namesortnlp;
 943         nltype  *nlp;
 944         int     index, nnames, todo, i, j;
 945         char    peterbuffer[BUFSIZ];
 946         mod_info_t      *mi;
 947 
 948         /*
 949          *      Now, sort regular function name alphabetically
 950          *      to create an index.
 951          */
 952         namesortnlp = calloc(total_names + ncycle, sizeof (nltype *));
 953 
 954         if (namesortnlp == NULL)
 955                 (void) fprintf(stderr, "%s: ran out of memory for sorting\n",
 956                     whoami);
 957 
 958         nnames = 0;
 959         for (mi = &modules; mi; mi = mi->next) {
 960                 for (index = 0; index < mi->nname; index++) {
 961                         if (zflag == 0 && (mi->nl[index]).ncall == 0 &&
 962                             (mi->nl[index]).time == 0) {
 963                                 continue;
 964                         }
 965 
 966                         /*
 967                          * Do not print certain special symbols, like
 968                          * PRF_EXTSYM, etc. even if zflag was on.
 969                          */
 970                         if (is_special_sym(&(mi->nl[index])))
 971                                 continue;
 972 
 973                         namesortnlp[nnames++] = &(mi->nl[index]);
 974                 }
 975         }
 976 
 977         if (Cflag) {
 978                 s1 = malloc(500 * sizeof (char));
 979                 s2 = malloc(500 * sizeof (char));
 980         }
 981 
 982         qsort(namesortnlp, nnames, sizeof (nltype *), namecmp);
 983 
 984         for (index = 1, todo = nnames; index <= ncycle; index++)
 985                 namesortnlp[todo++] = &cyclenl[index];
 986 
 987         (void) printf("\f\nIndex by function name\n\n");
 988 
 989         if (!Cflag)
 990                 index = (todo + 2) / 3;
 991         else
 992                 index = todo;
 993 
 994         for (i = 0; i < index; i++) {
 995                 if (!Cflag) {
 996                         for (j = i; j < todo; j += index) {
 997                                 nlp = namesortnlp[j];
 998 
 999                                 if (nlp->printflag) {
1000                                         (void) sprintf(peterbuffer,
1001                                             "[%d]", nlp->index);
1002                                 } else {
1003                                         (void) sprintf(peterbuffer,
1004                                             "(%d)", nlp->index);
1005                                 }
1006 
1007                                 if (j < nnames) {
1008                                         if (does_clash(namesortnlp,
1009                                             j, nnames)) {
1010                                                 (void) printf(
1011                                                     "%6.6s %*d:%-*.*s",
1012                                                     peterbuffer,
1013                                                     IDFMT(nlp->module->id),
1014                                                     nlp->module->id,
1015                                                     NMFMT(nlp->module->id),
1016                                                     NMFMT(nlp->module->id),
1017                                                     nlp->name);
1018                                         } else {
1019                                         (void) printf("%6.6s %-19.19s",
1020                                             peterbuffer, nlp->name);
1021                                         }
1022                                 } else {
1023                                         (void) printf("%6.6s ", peterbuffer);
1024                                         (void) sprintf(peterbuffer,
1025                                             "<cycle %d>", nlp->cycleno);
1026                                         (void) printf("%-19.19s", peterbuffer);
1027                                 }
1028                         }
1029                 } else {
1030                         nlp = namesortnlp[i];
1031 
1032                         if (nlp->printflag)
1033                                 (void) sprintf(peterbuffer, "[%d]", nlp->index);
1034                         else
1035                                 (void) sprintf(peterbuffer, "(%d)", nlp->index);
1036 
1037                         if (i < nnames) {
1038                                 const char *d = demangled_name(nlp);
1039 
1040                                 if (does_clash(namesortnlp, i, nnames)) {
1041                                         (void) printf("%6.6s %d:%s\n",
1042                                             peterbuffer, nlp->module->id, d);
1043                                 } else
1044                                         (void) printf("%6.6s %s\n", peterbuffer,
1045                                             d);
1046 
1047                                 if (d != nlp->name)
1048                                         (void) printf("%6.6s   [%s]", "",
1049                                             nlp->name);
1050                         } else {
1051                                 (void) printf("%6.6s ", peterbuffer);
1052                                 (void) sprintf(peterbuffer, "<cycle %d>",
1053                                     nlp->cycleno);
1054                                 (void) printf("%-33.33s", peterbuffer);
1055                         }
1056                 }
1057                 (void) printf("\n");
1058         }
1059         free(namesortnlp);
1060 }