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