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