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