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 *
demangled_name(nltype * selfp)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
printprof(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
timecmp(const void * arg1,const void * arg2)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
flatprofheader()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
flatprofline(nltype * np)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
gprofheader()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
gprofline(nltype * np)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
is_special_sym(nltype * nlp)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
printgprof(nltype ** timesortnlp)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
totalcmp(const void * arg1,const void * arg2)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
printparents(nltype * childp)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
printchildren(nltype * parentp)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
printname(nltype * selfp)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
print_demangled_name(int n,nltype * selfp)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
sortchildren(nltype * parentp)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
sortparents(nltype * childp)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
printcycle(nltype * cyclep)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
printmembers(nltype * cyclep)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
sortmembers(nltype * cyclep)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
membercmp(nltype * this,nltype * that)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
arccmp(arctype * thisp,arctype * thatp)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
printblurb(char * blurbname)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
namecmp(const void * arg1,const void * arg2)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
adjust_size(char ** pp,size_t * lenp,const char * name)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
stripped_name(char ** sp,size_t * slenp,nltype ** npp)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
does_clash(nltype ** nlp,int ndx,int nnames)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
printmodules()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
printindex()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