xref: /onnv-gate/usr/src/cmd/sgs/gprof/common/printgprof.c (revision 211:37c8180b1ace)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*211Smike_s 
230Sstevel@tonic-gate /*
24*211Smike_s  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*211Smike_s  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include "gprof.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate extern int find_run_directory(char *, char *, char *, char **, char *);
370Sstevel@tonic-gate void print_demangled_name(int, nltype *);
380Sstevel@tonic-gate void striped_name(char *, nltype **);
390Sstevel@tonic-gate 
400Sstevel@tonic-gate extern long hz;
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * Symbols that must never be printed, no matter what.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate char *splsym[] = {
460Sstevel@tonic-gate 	PRF_ETEXT,
470Sstevel@tonic-gate 	PRF_EXTSYM,
480Sstevel@tonic-gate 	PRF_MEMTERM,
49*211Smike_s 	NULL
500Sstevel@tonic-gate };
510Sstevel@tonic-gate 
52*211Smike_s static bool is_special_sym(nltype *nlp);
53*211Smike_s 
540Sstevel@tonic-gate char *
550Sstevel@tonic-gate demangled_name(nltype *selfp)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	char *name;
580Sstevel@tonic-gate 	if (!Cflag)
590Sstevel@tonic-gate 		return (selfp->name);
600Sstevel@tonic-gate 
61*211Smike_s 	name = (char *)sgs_demangle(selfp->name);
620Sstevel@tonic-gate 	return (name);
630Sstevel@tonic-gate }
640Sstevel@tonic-gate 
650Sstevel@tonic-gate void
66*211Smike_s printprof(void)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate 	nltype	*np;
690Sstevel@tonic-gate 	nltype	**sortednlp;
700Sstevel@tonic-gate 	int	i, index;
710Sstevel@tonic-gate 	int 	print_count = number_funcs_toprint;
720Sstevel@tonic-gate 	bool	print_flag = TRUE;
730Sstevel@tonic-gate 	mod_info_t	*mi;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	actime = 0.0;
76*211Smike_s 	(void) printf("\f\n");
770Sstevel@tonic-gate 	flatprofheader();
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	/*
800Sstevel@tonic-gate 	 *	Sort the symbol table in by time
810Sstevel@tonic-gate 	 */
820Sstevel@tonic-gate 	sortednlp = (nltype **) calloc(total_names, sizeof (nltype *));
830Sstevel@tonic-gate 	if (sortednlp == (nltype **) 0) {
84*211Smike_s 		(void) fprintf(stderr,
850Sstevel@tonic-gate 		    "[printprof] ran out of memory for time sorting\n");
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	index = 0;
890Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
900Sstevel@tonic-gate 		for (i = 0; i < mi->nname; i++)
910Sstevel@tonic-gate 			sortednlp[index++] = &(mi->nl[i]);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 
94*211Smike_s 	qsort(sortednlp, total_names, sizeof (nltype *), timecmp);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	for (index = 0; (index < total_names) && print_flag; index += 1) {
970Sstevel@tonic-gate 		np = sortednlp[index];
980Sstevel@tonic-gate 		flatprofline(np);
990Sstevel@tonic-gate 		if (nflag) {
1000Sstevel@tonic-gate 			if (--print_count == 0)
1010Sstevel@tonic-gate 				print_flag = FALSE;
1020Sstevel@tonic-gate 		}
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 	actime = 0.0;
1050Sstevel@tonic-gate 	free(sortednlp);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate int
109*211Smike_s timecmp(const void *arg1, const void *arg2)
1100Sstevel@tonic-gate {
111*211Smike_s 	nltype **npp1 = (nltype **)arg1;
112*211Smike_s 	nltype **npp2 = (nltype **)arg2;
1130Sstevel@tonic-gate 	double	timediff;
1140Sstevel@tonic-gate 	long	calldiff;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	timediff = (*npp2)->time - (*npp1)->time;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if (timediff > 0.0)
1190Sstevel@tonic-gate 		return (1);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if (timediff < 0.0)
1220Sstevel@tonic-gate 		return (-1);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	calldiff = (*npp2)->ncall - (*npp1)->ncall;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (calldiff > 0)
1270Sstevel@tonic-gate 		return (1);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (calldiff < 0)
1300Sstevel@tonic-gate 		return (-1);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	return (strcmp((*npp1)->name, (*npp2)->name));
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate  *	header for flatprofline
1370Sstevel@tonic-gate  */
1380Sstevel@tonic-gate void
1390Sstevel@tonic-gate flatprofheader()
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (bflag)
1430Sstevel@tonic-gate 		printblurb(FLAT_BLURB);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (old_style) {
146*211Smike_s 		(void) printf(
147*211Smike_s 		    "\ngranularity: each sample hit covers %d byte(s)",
148*211Smike_s 		    (long)scale * sizeof (UNIT));
1490Sstevel@tonic-gate 		if (totime > 0.0) {
150*211Smike_s 			(void) printf(" for %.2f%% of %.2f seconds\n\n",
1510Sstevel@tonic-gate 			    100.0/totime, totime / hz);
1520Sstevel@tonic-gate 		} else {
153*211Smike_s 			(void) printf(" no time accumulated\n\n");
1540Sstevel@tonic-gate 			/*
1550Sstevel@tonic-gate 			 * this doesn't hurt since all the numerators will
1560Sstevel@tonic-gate 			 * be zero.
1570Sstevel@tonic-gate 			 */
1580Sstevel@tonic-gate 			totime = 1.0;
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
162*211Smike_s 	(void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
1630Sstevel@tonic-gate 	    "% ", "cumulative", "self ", "", "self ", "total ", "");
164*211Smike_s 	(void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
1650Sstevel@tonic-gate 	    "time", "seconds ", "seconds", "calls",
1660Sstevel@tonic-gate 	    "ms/call", "ms/call", "name");
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate void
1700Sstevel@tonic-gate flatprofline(nltype *np)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	if (zflag == 0 && np->ncall == 0 && np->time == 0)
1730Sstevel@tonic-gate 		return;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/*
1760Sstevel@tonic-gate 	 * Do not print certain special symbols, like PRF_EXTSYM, etc.
1770Sstevel@tonic-gate 	 * even if zflag was on.
1780Sstevel@tonic-gate 	 */
1790Sstevel@tonic-gate 	if (is_special_sym(np))
1800Sstevel@tonic-gate 		return;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	actime += np->time;
1830Sstevel@tonic-gate 
184*211Smike_s 	(void) printf("%5.1f %10.2f %8.2f",
1850Sstevel@tonic-gate 	    100 * np->time / totime, actime / hz, np->time / hz);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	if (np->ncall != 0) {
188*211Smike_s 		(void) printf(" %8lld %8.2f %8.2f  ", np->ncall,
1890Sstevel@tonic-gate 		    1000 * np->time / hz / np->ncall,
1900Sstevel@tonic-gate 		    1000 * (np->time + np->childtime) / hz / np->ncall);
1910Sstevel@tonic-gate 	} else {
1920Sstevel@tonic-gate 		if (!Cflag)
193*211Smike_s 			(void) printf(" %8.8s %8.8s %8.8s ", "", "", "");
1940Sstevel@tonic-gate 		else
195*211Smike_s 			(void) printf(" %8.8s %8.8s %8.8s  ", "", "", "");
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	printname(np);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if (Cflag)
2010Sstevel@tonic-gate 		print_demangled_name(55, np);
2020Sstevel@tonic-gate 
203*211Smike_s 	(void) printf("\n");
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate void
2070Sstevel@tonic-gate gprofheader()
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if (bflag)
2110Sstevel@tonic-gate 		printblurb(CALLG_BLURB);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (old_style) {
2140Sstevel@tonic-gate 
215*211Smike_s 		(void) printf(
216*211Smike_s 		    "\ngranularity: each sample hit covers %d byte(s)",
217*211Smike_s 		    (long)scale * sizeof (UNIT));
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 		if (printtime > 0.0) {
220*211Smike_s 			(void) printf(" for %.2f%% of %.2f seconds\n\n",
2210Sstevel@tonic-gate 			    100.0/printtime, printtime / hz);
2220Sstevel@tonic-gate 		} else {
223*211Smike_s 			(void) printf(" no time propagated\n\n");
2240Sstevel@tonic-gate 			/*
2250Sstevel@tonic-gate 			 * this doesn't hurt, since all the numerators
2260Sstevel@tonic-gate 			 * will be 0.0
2270Sstevel@tonic-gate 			 */
2280Sstevel@tonic-gate 			printtime = 1.0;
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 	} else {
231*211Smike_s 		(void) printf(
232*211Smike_s 		    "\ngranularity: each pc-hit is considered 1 tick");
2330Sstevel@tonic-gate 		if (hz != 1) {
234*211Smike_s 			(void) printf(" (@ %4.3f seconds per tick)",
235*211Smike_s 			    (double)1.0 / hz);
2360Sstevel@tonic-gate 		}
237*211Smike_s 		(void) puts("\n\n");
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
240*211Smike_s 	(void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
2410Sstevel@tonic-gate 	    "", "", "", "", "called", "total", "parents");
242*211Smike_s 	(void) printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
2430Sstevel@tonic-gate 	    "index", "%time", "self", "descendents",
2440Sstevel@tonic-gate 	    "called", "self", "name", "index");
245*211Smike_s 	(void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
2460Sstevel@tonic-gate 	    "", "", "", "", "called", "total", "children");
247*211Smike_s 	(void) printf("\n");
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate void
2510Sstevel@tonic-gate gprofline(nltype *np)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	char	kirkbuffer[BUFSIZ];
2540Sstevel@tonic-gate 
255*211Smike_s 	(void) sprintf(kirkbuffer, "[%d]", np->index);
256*211Smike_s 	(void) printf("%-6.6s %5.1f %7.2f %11.2f", kirkbuffer,
2570Sstevel@tonic-gate 	    100 * (np->propself + np->propchild) / printtime,
2580Sstevel@tonic-gate 	    np->propself / hz, np->propchild / hz);
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if ((np->ncall + np->selfcalls) != 0) {
261*211Smike_s 		(void) printf(" %7lld", np->ncall);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		if (np->selfcalls != 0)
264*211Smike_s 			(void) printf("+%-7lld ", np->selfcalls);
2650Sstevel@tonic-gate 		else
266*211Smike_s 			(void) printf(" %7.7s ", "");
2670Sstevel@tonic-gate 	} else {
268*211Smike_s 		(void) printf(" %7.7s %7.7s ", "", "");
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	printname(np);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	if (Cflag)
2740Sstevel@tonic-gate 		print_demangled_name(50, np);
2750Sstevel@tonic-gate 
276*211Smike_s 	(void) printf("\n");
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate static bool
2800Sstevel@tonic-gate is_special_sym(nltype *nlp)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	int	i;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (nlp->name == NULL)
2850Sstevel@tonic-gate 		return (FALSE);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	for (i = 0;  splsym[i]; i++)
2880Sstevel@tonic-gate 		if (strcmp(splsym[i], nlp->name) == 0)
2890Sstevel@tonic-gate 			return (TRUE);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (FALSE);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate void
2950Sstevel@tonic-gate printgprof(nltype **timesortnlp)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	int	index;
2980Sstevel@tonic-gate 	nltype	*parentp;
2990Sstevel@tonic-gate 	int 	print_count = number_funcs_toprint;
3000Sstevel@tonic-gate 	bool	count_flag = TRUE;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/*
3030Sstevel@tonic-gate 	 * Print out the structured profiling list
3040Sstevel@tonic-gate 	 */
3050Sstevel@tonic-gate 	gprofheader();
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	for (index = 0; index < total_names + ncycle && count_flag; index++) {
3080Sstevel@tonic-gate 		parentp = timesortnlp[index];
3090Sstevel@tonic-gate 		if (zflag == 0 && parentp->ncall == 0 &&
3100Sstevel@tonic-gate 		    parentp->selfcalls == 0 && parentp->propself == 0 &&
3110Sstevel@tonic-gate 		    parentp -> propchild == 0)
3120Sstevel@tonic-gate 			continue;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		if (!parentp->printflag)
3150Sstevel@tonic-gate 			continue;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 		/*
3180Sstevel@tonic-gate 		 * Do not print certain special symbols, like PRF_EXTSYM, etc.
3190Sstevel@tonic-gate 		 * even if zflag was on.
3200Sstevel@tonic-gate 		 */
3210Sstevel@tonic-gate 		if (is_special_sym(parentp))
3220Sstevel@tonic-gate 			continue;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		if (parentp->name == 0 && parentp->cycleno != 0) {
3250Sstevel@tonic-gate 			/*
3260Sstevel@tonic-gate 			 *	cycle header
3270Sstevel@tonic-gate 			 */
3280Sstevel@tonic-gate 			printcycle(parentp);
3290Sstevel@tonic-gate 			printmembers(parentp);
3300Sstevel@tonic-gate 		} else {
3310Sstevel@tonic-gate 			printparents(parentp);
3320Sstevel@tonic-gate 			gprofline(parentp);
3330Sstevel@tonic-gate 			printchildren(parentp);
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 
336*211Smike_s 		(void) printf("\n");
337*211Smike_s 		(void) printf(
338*211Smike_s 		    "-----------------------------------------------\n");
339*211Smike_s 		(void) printf("\n");
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		if (nflag) {
3420Sstevel@tonic-gate 			--print_count;
3430Sstevel@tonic-gate 			if (print_count == 0)
3440Sstevel@tonic-gate 				count_flag = FALSE;
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	free(timesortnlp);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate /*
3510Sstevel@tonic-gate  *	sort by decreasing propagated time
3520Sstevel@tonic-gate  *	if times are equal, but one is a cycle header,
3530Sstevel@tonic-gate  *		say that's first (e.g. less, i.e. -1).
3540Sstevel@tonic-gate  *	if one's name doesn't have an underscore and the other does,
3550Sstevel@tonic-gate  *		say the one is first.
3560Sstevel@tonic-gate  *	all else being equal, sort by names.
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate int
359*211Smike_s totalcmp(const void *arg1, const void *arg2)
3600Sstevel@tonic-gate {
361*211Smike_s 	nltype **npp1 = (nltype **)arg1;
362*211Smike_s 	nltype **npp2 = (nltype **)arg2;
3630Sstevel@tonic-gate 	nltype	*np1 = *npp1;
3640Sstevel@tonic-gate 	nltype	*np2 = *npp2;
3650Sstevel@tonic-gate 	double	diff;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	diff = (np1->propself + np1->propchild) -
3680Sstevel@tonic-gate 	    (np2->propself + np2->propchild);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (diff < 0.0)
3710Sstevel@tonic-gate 		return (1);
3720Sstevel@tonic-gate 	if (diff > 0.0)
3730Sstevel@tonic-gate 		return (-1);
3740Sstevel@tonic-gate 	if (np1->name == 0 && np1->cycleno != 0)
3750Sstevel@tonic-gate 		return (-1);
3760Sstevel@tonic-gate 	if (np2->name == 0 && np2->cycleno != 0)
3770Sstevel@tonic-gate 		return (1);
3780Sstevel@tonic-gate 	if (np1->name == 0)
3790Sstevel@tonic-gate 		return (-1);
3800Sstevel@tonic-gate 	if (np2->name == 0)
3810Sstevel@tonic-gate 		return (1);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if (*(np1->name) != '_' && *(np2->name) == '_')
3840Sstevel@tonic-gate 		return (-1);
3850Sstevel@tonic-gate 	if (*(np1->name) == '_' && *(np2->name) != '_')
3860Sstevel@tonic-gate 		return (1);
3870Sstevel@tonic-gate 	if (np1->ncall > np2->ncall)
3880Sstevel@tonic-gate 		return (-1);
3890Sstevel@tonic-gate 	if (np1->ncall < np2->ncall)
3900Sstevel@tonic-gate 		return (1);
3910Sstevel@tonic-gate 	return (strcmp(np1->name, np2->name));
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate void
3950Sstevel@tonic-gate printparents(nltype *childp)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	nltype	*parentp;
3980Sstevel@tonic-gate 	arctype	*arcp;
3990Sstevel@tonic-gate 	nltype	*cycleheadp;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	if (childp->cyclehead != 0)
4020Sstevel@tonic-gate 		cycleheadp = childp -> cyclehead;
4030Sstevel@tonic-gate 	else
4040Sstevel@tonic-gate 		cycleheadp = childp;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	if (childp->parents == 0) {
407*211Smike_s 		(void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s"
4080Sstevel@tonic-gate 		    "     <spontaneous>\n", "", "", "", "", "", "");
4090Sstevel@tonic-gate 		return;
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	sortparents(childp);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	for (arcp = childp->parents; arcp; arcp = arcp->arc_parentlist) {
4150Sstevel@tonic-gate 		parentp = arcp -> arc_parentp;
4160Sstevel@tonic-gate 		if (childp == parentp || (childp->cycleno != 0 &&
4170Sstevel@tonic-gate 		    parentp->cycleno == childp->cycleno)) {
4180Sstevel@tonic-gate 			/*
4190Sstevel@tonic-gate 			 *	selfcall or call among siblings
4200Sstevel@tonic-gate 			 */
421*211Smike_s 			(void) printf(
422*211Smike_s 			    "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
4230Sstevel@tonic-gate 			    "", "", "", "", arcp->arc_count, "");
4240Sstevel@tonic-gate 			printname(parentp);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 			if (Cflag)
4270Sstevel@tonic-gate 				print_demangled_name(54, parentp);
4280Sstevel@tonic-gate 
429*211Smike_s 			(void) printf("\n");
4300Sstevel@tonic-gate 		} else {
4310Sstevel@tonic-gate 			/*
4320Sstevel@tonic-gate 			 *	regular parent of child
4330Sstevel@tonic-gate 			 */
434*211Smike_s 			(void) printf(
435*211Smike_s 			    "%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld     ", "",
4360Sstevel@tonic-gate 			    "", arcp->arc_time / hz, arcp->arc_childtime / hz,
4370Sstevel@tonic-gate 			    arcp->arc_count, cycleheadp->ncall);
4380Sstevel@tonic-gate 			printname(parentp);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 			if (Cflag)
4410Sstevel@tonic-gate 				print_demangled_name(54, parentp);
4420Sstevel@tonic-gate 
443*211Smike_s 			(void) printf("\n");
4440Sstevel@tonic-gate 		}
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate void
4490Sstevel@tonic-gate printchildren(nltype *parentp)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	nltype	*childp;
4520Sstevel@tonic-gate 	arctype	*arcp;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	sortchildren(parentp);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) {
4570Sstevel@tonic-gate 		childp = arcp->arc_childp;
4580Sstevel@tonic-gate 		if (childp == parentp || (childp->cycleno != 0 &&
4590Sstevel@tonic-gate 		    childp->cycleno == parentp->cycleno)) {
4600Sstevel@tonic-gate 			/*
4610Sstevel@tonic-gate 			 * self call or call to sibling
4620Sstevel@tonic-gate 			 */
463*211Smike_s 			(void) printf(
464*211Smike_s 			    "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
4650Sstevel@tonic-gate 			    "", "", "", "", arcp->arc_count, "");
4660Sstevel@tonic-gate 			printname(childp);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 			if (Cflag)
4690Sstevel@tonic-gate 				print_demangled_name(54, childp);
4700Sstevel@tonic-gate 
471*211Smike_s 			(void) printf("\n");
4720Sstevel@tonic-gate 		} else {
4730Sstevel@tonic-gate 			/*
4740Sstevel@tonic-gate 			 *	regular child of parent
4750Sstevel@tonic-gate 			 */
4760Sstevel@tonic-gate 			if (childp->cyclehead)
477*211Smike_s 				(void) printf("%6.6s %5.5s %7.2f %11.2f "
4780Sstevel@tonic-gate 				    "%7lld/%-7lld     ", "", "",
4790Sstevel@tonic-gate 				    arcp->arc_time / hz,
4800Sstevel@tonic-gate 				    arcp->arc_childtime / hz, arcp->arc_count,
4810Sstevel@tonic-gate 				    childp->cyclehead->ncall);
4820Sstevel@tonic-gate 			else
483*211Smike_s 				(void) printf("%6.6s %5.5s %7.2f %11.2f "
4840Sstevel@tonic-gate 				    "%7lld %7.7s    ",
4850Sstevel@tonic-gate 				    "", "", arcp->arc_time / hz,
4860Sstevel@tonic-gate 				    arcp->arc_childtime / hz, arcp->arc_count,
4870Sstevel@tonic-gate 				    "");
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 			printname(childp);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 			if (Cflag)
4920Sstevel@tonic-gate 				print_demangled_name(54, childp);
4930Sstevel@tonic-gate 
494*211Smike_s 			(void) printf("\n");
4950Sstevel@tonic-gate 		}
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate void
5000Sstevel@tonic-gate printname(nltype *selfp)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	char  *c;
5030Sstevel@tonic-gate 	c = demangled_name(selfp);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (selfp->name != 0) {
5060Sstevel@tonic-gate 		if (!Cflag)
507*211Smike_s 			(void) printf("%s", selfp->name);
5080Sstevel@tonic-gate 		else
509*211Smike_s 			(void) printf("%s", c);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate #ifdef DEBUG
5120Sstevel@tonic-gate 		if (debug & DFNDEBUG)
513*211Smike_s 			(void) printf("{%d} ", selfp->toporder);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		if (debug & PROPDEBUG)
516*211Smike_s 			(void) printf("%5.2f%% ", selfp->propfraction);
517*211Smike_s #endif /* DEBUG */
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (selfp->cycleno != 0)
521*211Smike_s 		(void) printf("\t<cycle %d>", selfp->cycleno);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (selfp->index != 0) {
5240Sstevel@tonic-gate 		if (selfp->printflag)
525*211Smike_s 			(void) printf(" [%d]", selfp->index);
5260Sstevel@tonic-gate 		else
527*211Smike_s 			(void) printf(" (%d)", selfp->index);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate void
5320Sstevel@tonic-gate print_demangled_name(int n, nltype *selfp)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	char *c;
5350Sstevel@tonic-gate 	int i;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	c = selfp->name;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (strcmp(c, demangled_name(selfp)) == 0)
5400Sstevel@tonic-gate 		return;
5410Sstevel@tonic-gate 	else {
542*211Smike_s 		(void) printf("\n");
5430Sstevel@tonic-gate 		for (i = 1; i < n; i++)
544*211Smike_s 			(void) printf(" ");
545*211Smike_s 		(void) printf("[%s]", selfp->name);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate void
5500Sstevel@tonic-gate sortchildren(nltype *parentp)
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate 	arctype	*arcp;
5530Sstevel@tonic-gate 	arctype	*detachedp;
5540Sstevel@tonic-gate 	arctype	sorted;
5550Sstevel@tonic-gate 	arctype	*prevp;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	/*
5580Sstevel@tonic-gate 	 *	unlink children from parent,
5590Sstevel@tonic-gate 	 *	then insertion sort back on to sorted's children.
5600Sstevel@tonic-gate 	 *	    *arcp	the arc you have detached and are inserting.
5610Sstevel@tonic-gate 	 *	    *detachedp	the rest of the arcs to be sorted.
5620Sstevel@tonic-gate 	 *	    sorted	arc list onto which you insertion sort.
5630Sstevel@tonic-gate 	 *	    *prevp	arc before the arc you are comparing.
5640Sstevel@tonic-gate 	 */
5650Sstevel@tonic-gate 	sorted.arc_childlist = 0;
5660Sstevel@tonic-gate 
567*211Smike_s 	/* LINTED: warning: assignment operator */
5680Sstevel@tonic-gate 	for ((arcp = parentp->children) && (detachedp = arcp->arc_childlist);
5690Sstevel@tonic-gate 	    arcp;
570*211Smike_s 	    /* LINTED: warning: assignment operator */
5710Sstevel@tonic-gate 	    (arcp = detachedp) && (detachedp = detachedp->arc_childlist)) {
5720Sstevel@tonic-gate 		/*
5730Sstevel@tonic-gate 		 *	consider *arcp as disconnected
5740Sstevel@tonic-gate 		 *	insert it into sorted
5750Sstevel@tonic-gate 		 */
5760Sstevel@tonic-gate 		for (prevp = &sorted; prevp->arc_childlist;
5770Sstevel@tonic-gate 		    prevp = prevp->arc_childlist) {
5780Sstevel@tonic-gate 			if (arccmp(arcp, prevp->arc_childlist) != LESSTHAN)
5790Sstevel@tonic-gate 				break;
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		arcp->arc_childlist = prevp->arc_childlist;
5830Sstevel@tonic-gate 		prevp->arc_childlist = arcp;
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/*
5870Sstevel@tonic-gate 	 *	reattach sorted children to parent
5880Sstevel@tonic-gate 	 */
5890Sstevel@tonic-gate 	parentp->children = sorted.arc_childlist;
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate void
5930Sstevel@tonic-gate sortparents(nltype *childp)
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate 	arctype	*arcp;
5960Sstevel@tonic-gate 	arctype	*detachedp;
5970Sstevel@tonic-gate 	arctype	sorted;
5980Sstevel@tonic-gate 	arctype	*prevp;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/*
6010Sstevel@tonic-gate 	 *	unlink parents from child,
6020Sstevel@tonic-gate 	 *	then insertion sort back on to sorted's parents.
6030Sstevel@tonic-gate 	 *	    *arcp	the arc you have detached and are inserting.
6040Sstevel@tonic-gate 	 *	    *detachedp	the rest of the arcs to be sorted.
6050Sstevel@tonic-gate 	 *	    sorted	arc list onto which you insertion sort.
6060Sstevel@tonic-gate 	 *	    *prevp	arc before the arc you are comparing.
6070Sstevel@tonic-gate 	 */
6080Sstevel@tonic-gate 	sorted.arc_parentlist = 0;
6090Sstevel@tonic-gate 
610*211Smike_s 	/* LINTED: warning: assignment operator */
6110Sstevel@tonic-gate 	for ((arcp = childp->parents) && (detachedp = arcp->arc_parentlist);
6120Sstevel@tonic-gate 	    arcp;
613*211Smike_s 	    /* LINTED: warning: assignment operator */
6140Sstevel@tonic-gate 	    (arcp = detachedp) && (detachedp = detachedp->arc_parentlist)) {
6150Sstevel@tonic-gate 		/*
6160Sstevel@tonic-gate 		 *	consider *arcp as disconnected
6170Sstevel@tonic-gate 		 *	insert it into sorted
6180Sstevel@tonic-gate 		 */
6190Sstevel@tonic-gate 		for (prevp = &sorted; prevp->arc_parentlist;
6200Sstevel@tonic-gate 		    prevp = prevp->arc_parentlist) {
6210Sstevel@tonic-gate 			if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN)
6220Sstevel@tonic-gate 				break;
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 		arcp->arc_parentlist = prevp->arc_parentlist;
6250Sstevel@tonic-gate 		prevp->arc_parentlist = arcp;
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/*
6290Sstevel@tonic-gate 	 *	reattach sorted arcs to child
6300Sstevel@tonic-gate 	 */
6310Sstevel@tonic-gate 	childp->parents = sorted.arc_parentlist;
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate void
6350Sstevel@tonic-gate printcycle(nltype *cyclep)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	char	kirkbuffer[BUFSIZ];
6380Sstevel@tonic-gate 
639*211Smike_s 	(void) sprintf(kirkbuffer, "[%d]", cyclep->index);
640*211Smike_s 	(void) printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer,
6410Sstevel@tonic-gate 	    100 * (cyclep->propself + cyclep->propchild) / printtime,
6420Sstevel@tonic-gate 	    cyclep -> propself / hz, cyclep -> propchild / hz,
6430Sstevel@tonic-gate 	    cyclep -> ncall);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (cyclep->selfcalls != 0)
646*211Smike_s 		(void) printf("+%-7lld", cyclep->selfcalls);
6470Sstevel@tonic-gate 	else
648*211Smike_s 		(void) printf(" %7.7s", "");
6490Sstevel@tonic-gate 
650*211Smike_s 	(void) printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno,
6510Sstevel@tonic-gate 	    cyclep->index);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate  *	print the members of a cycle
6560Sstevel@tonic-gate  */
6570Sstevel@tonic-gate void
6580Sstevel@tonic-gate printmembers(nltype *cyclep)
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	nltype	*memberp;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	sortmembers(cyclep);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) {
665*211Smike_s 		(void) printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "",
6660Sstevel@tonic-gate 		    memberp->propself / hz, memberp->propchild / hz,
6670Sstevel@tonic-gate 		    memberp->ncall);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		if (memberp->selfcalls != 0)
670*211Smike_s 			(void) printf("+%-7lld", memberp->selfcalls);
6710Sstevel@tonic-gate 		else
672*211Smike_s 			(void) printf(" %7.7s", "");
6730Sstevel@tonic-gate 
674*211Smike_s 		(void) printf("     ");
6750Sstevel@tonic-gate 		printname(memberp);
6760Sstevel@tonic-gate 		if (Cflag)
6770Sstevel@tonic-gate 			print_demangled_name(54, memberp);
678*211Smike_s 		(void) printf("\n");
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate /*
6830Sstevel@tonic-gate  * sort members of a cycle
6840Sstevel@tonic-gate  */
6850Sstevel@tonic-gate void
6860Sstevel@tonic-gate sortmembers(nltype *cyclep)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	nltype	*todo;
6890Sstevel@tonic-gate 	nltype	*doing;
6900Sstevel@tonic-gate 	nltype	*prev;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/*
6930Sstevel@tonic-gate 	 *	detach cycle members from cyclehead,
6940Sstevel@tonic-gate 	 *	and insertion sort them back on.
6950Sstevel@tonic-gate 	 */
6960Sstevel@tonic-gate 	todo = cyclep->cnext;
6970Sstevel@tonic-gate 	cyclep->cnext = 0;
6980Sstevel@tonic-gate 
699*211Smike_s 	/* LINTED: warning: assignment operator */
7000Sstevel@tonic-gate 	for ((doing = todo) && (todo = doing->cnext);
701*211Smike_s 	    doing;
702*211Smike_s 	    /* LINTED: warning: assignment operator */
703*211Smike_s 	    (doing = todo) && (todo = doing->cnext)) {
7040Sstevel@tonic-gate 		for (prev = cyclep; prev->cnext; prev = prev->cnext) {
7050Sstevel@tonic-gate 			if (membercmp(doing, prev->cnext) == GREATERTHAN)
7060Sstevel@tonic-gate 				break;
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 		doing->cnext = prev->cnext;
7090Sstevel@tonic-gate 		prev->cnext = doing;
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate  *	major sort is on propself + propchild,
7150Sstevel@tonic-gate  *	next is sort on ncalls + selfcalls.
7160Sstevel@tonic-gate  */
7170Sstevel@tonic-gate int
7180Sstevel@tonic-gate membercmp(nltype *this, nltype *that)
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate 	double	thistime = this->propself + this->propchild;
7210Sstevel@tonic-gate 	double	thattime = that->propself + that->propchild;
7220Sstevel@tonic-gate 	actype	thiscalls = this->ncall + this->selfcalls;
7230Sstevel@tonic-gate 	actype	thatcalls = that->ncall + that->selfcalls;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	if (thistime > thattime)
7260Sstevel@tonic-gate 		return (GREATERTHAN);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (thistime < thattime)
7290Sstevel@tonic-gate 		return (LESSTHAN);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	if (thiscalls > thatcalls)
7320Sstevel@tonic-gate 		return (GREATERTHAN);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if (thiscalls < thatcalls)
7350Sstevel@tonic-gate 		return (LESSTHAN);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	return (EQUALTO);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate /*
7410Sstevel@tonic-gate  *	compare two arcs to/from the same child/parent.
7420Sstevel@tonic-gate  *	- if one arc is a self arc, it's least.
7430Sstevel@tonic-gate  *	- if one arc is within a cycle, it's less than.
7440Sstevel@tonic-gate  *	- if both arcs are within a cycle, compare arc counts.
7450Sstevel@tonic-gate  *	- if neither arc is within a cycle, compare with
7460Sstevel@tonic-gate  *		arc_time + arc_childtime as major key
7470Sstevel@tonic-gate  *		arc count as minor key
7480Sstevel@tonic-gate  */
7490Sstevel@tonic-gate int
7500Sstevel@tonic-gate arccmp(arctype *thisp, arctype *thatp)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	nltype	*thisparentp = thisp->arc_parentp;
7530Sstevel@tonic-gate 	nltype	*thischildp = thisp->arc_childp;
7540Sstevel@tonic-gate 	nltype	*thatparentp = thatp->arc_parentp;
7550Sstevel@tonic-gate 	nltype	*thatchildp = thatp->arc_childp;
7560Sstevel@tonic-gate 	double	thistime;
7570Sstevel@tonic-gate 	double	thattime;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate #ifdef DEBUG
7600Sstevel@tonic-gate 	if (debug & TIMEDEBUG) {
761*211Smike_s 		(void) printf("[arccmp] ");
7620Sstevel@tonic-gate 		printname(thisparentp);
763*211Smike_s 		(void) printf(" calls ");
7640Sstevel@tonic-gate 		printname(thischildp);
765*211Smike_s 		(void) printf(" %f + %f %lld/%lld\n", thisp->arc_time,
7660Sstevel@tonic-gate 		    thisp->arc_childtime, thisp->arc_count,
7670Sstevel@tonic-gate 		    thischildp->ncall);
768*211Smike_s 		(void) printf("[arccmp] ");
7690Sstevel@tonic-gate 		printname(thatparentp);
770*211Smike_s 		(void) printf(" calls ");
7710Sstevel@tonic-gate 		printname(thatchildp);
772*211Smike_s 		(void) printf(" %f + %f %lld/%lld\n", thatp->arc_time,
7730Sstevel@tonic-gate 		    thatp->arc_childtime, thatp->arc_count,
7740Sstevel@tonic-gate 		    thatchildp->ncall);
775*211Smike_s 		(void) printf("\n");
7760Sstevel@tonic-gate 	}
777*211Smike_s #endif /* DEBUG */
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	if (thisparentp == thischildp) {
7800Sstevel@tonic-gate 		/*
7810Sstevel@tonic-gate 		 * this is a self call
7820Sstevel@tonic-gate 		 */
7830Sstevel@tonic-gate 		return (LESSTHAN);
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (thatparentp == thatchildp) {
7870Sstevel@tonic-gate 		/*
7880Sstevel@tonic-gate 		 * that is a self call
7890Sstevel@tonic-gate 		 */
7900Sstevel@tonic-gate 		return (GREATERTHAN);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 &&
7940Sstevel@tonic-gate 	    thisparentp->cycleno == thischildp->cycleno) {
7950Sstevel@tonic-gate 		/*
7960Sstevel@tonic-gate 		 * this is a call within a cycle
7970Sstevel@tonic-gate 		 */
7980Sstevel@tonic-gate 		if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
7990Sstevel@tonic-gate 		    thatparentp->cycleno == thatchildp->cycleno) {
8000Sstevel@tonic-gate 			/*
8010Sstevel@tonic-gate 			 * that is a call within the cycle, too
8020Sstevel@tonic-gate 			 */
8030Sstevel@tonic-gate 			if (thisp->arc_count < thatp->arc_count)
8040Sstevel@tonic-gate 				return (LESSTHAN);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 			if (thisp->arc_count > thatp->arc_count)
8070Sstevel@tonic-gate 				return (GREATERTHAN);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 			return (EQUALTO);
8100Sstevel@tonic-gate 		} else {
8110Sstevel@tonic-gate 			/*
8120Sstevel@tonic-gate 			 * that isn't a call within the cycle
8130Sstevel@tonic-gate 			 */
8140Sstevel@tonic-gate 			return (LESSTHAN);
8150Sstevel@tonic-gate 		}
8160Sstevel@tonic-gate 	} else {
8170Sstevel@tonic-gate 		/*
8180Sstevel@tonic-gate 		 * this isn't a call within a cycle
8190Sstevel@tonic-gate 		 */
8200Sstevel@tonic-gate 		if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
8210Sstevel@tonic-gate 		    thatparentp->cycleno == thatchildp->cycleno) {
8220Sstevel@tonic-gate 			/*
8230Sstevel@tonic-gate 			 * that is a call within a cycle
8240Sstevel@tonic-gate 			 */
8250Sstevel@tonic-gate 			return (GREATERTHAN);
8260Sstevel@tonic-gate 		} else {
8270Sstevel@tonic-gate 			/*
8280Sstevel@tonic-gate 			 * neither is a call within a cycle
8290Sstevel@tonic-gate 			 */
8300Sstevel@tonic-gate 			thistime = thisp->arc_time + thisp->arc_childtime;
8310Sstevel@tonic-gate 			thattime = thatp->arc_time + thatp->arc_childtime;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 			if (thistime < thattime)
8340Sstevel@tonic-gate 				return (LESSTHAN);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 			if (thistime > thattime)
8370Sstevel@tonic-gate 				return (GREATERTHAN);
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 			if (thisp->arc_count < thatp->arc_count)
8400Sstevel@tonic-gate 				return (LESSTHAN);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 			if (thisp->arc_count > thatp->arc_count)
8430Sstevel@tonic-gate 				return (GREATERTHAN);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 			return (EQUALTO);
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate void
8510Sstevel@tonic-gate printblurb(char *blurbname)
8520Sstevel@tonic-gate {
8530Sstevel@tonic-gate 	FILE	*blurbfile;
8540Sstevel@tonic-gate 	int	input;
8550Sstevel@tonic-gate 	char	blurb_directory[MAXPATHLEN];
8560Sstevel@tonic-gate 	char	cwd[MAXPATHLEN];
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	cwd[0] = '.';
8590Sstevel@tonic-gate 	cwd[1] = '\0';
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (find_run_directory(prog_name, cwd, blurb_directory,
8620Sstevel@tonic-gate 	    NULL, getenv("PATH")) != 0) {
8630Sstevel@tonic-gate 		(void) fprintf(stderr, "Error in finding run directory.");
8640Sstevel@tonic-gate 		return;
8650Sstevel@tonic-gate 	} else {
866*211Smike_s 		(void) strcat(blurb_directory, blurbname);
8670Sstevel@tonic-gate 	}
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	blurbfile = fopen(blurb_directory, "r");
8700Sstevel@tonic-gate 	if (blurbfile == NULL) {
8710Sstevel@tonic-gate 		perror(blurb_directory);
8720Sstevel@tonic-gate 		return;
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	while ((input = getc(blurbfile)) != EOF)
876*211Smike_s 		(void) putchar(input);
8770Sstevel@tonic-gate 
878*211Smike_s 	(void) fclose(blurbfile);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate char *s1, *s2;
8820Sstevel@tonic-gate 
883*211Smike_s static int
884*211Smike_s namecmp(const void *arg1, const void *arg2)
8850Sstevel@tonic-gate {
886*211Smike_s 	nltype **npp1 = (nltype **)arg1;
887*211Smike_s 	nltype **npp2 = (nltype **)arg2;
888*211Smike_s 
8890Sstevel@tonic-gate 	if (!Cflag)
8900Sstevel@tonic-gate 		return (strcmp((*npp1)->name, (*npp2)->name));
8910Sstevel@tonic-gate 	else {
8920Sstevel@tonic-gate 		striped_name(s1, npp1);
8930Sstevel@tonic-gate 		striped_name(s2, npp2);
8940Sstevel@tonic-gate 		return (strcmp(s1, s2));
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate void
8990Sstevel@tonic-gate striped_name(char *s, nltype **npp)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate 	char *d, *c;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	c = (char *)s;
9040Sstevel@tonic-gate 	d = demangled_name(*npp);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	while ((*d != '(') && (*d != '\0')) {
9070Sstevel@tonic-gate 		if (*d != ':')
9080Sstevel@tonic-gate 			*c++ = *d++;
9090Sstevel@tonic-gate 		else
9100Sstevel@tonic-gate 			d++;
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 	*c = '\0';
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate /*
9160Sstevel@tonic-gate  * Checks if the current symbol name is the same as its neighbour and
9170Sstevel@tonic-gate  * returns TRUE if it is.
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate static bool
9200Sstevel@tonic-gate does_clash(nltype **nlp, int ndx, int nnames)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	/*
9230Sstevel@tonic-gate 	 * same as previous (if there's one) ?
9240Sstevel@tonic-gate 	 */
9250Sstevel@tonic-gate 	if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0))
9260Sstevel@tonic-gate 		return (TRUE);
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	/*
9290Sstevel@tonic-gate 	 * same as next (if there's one) ?
9300Sstevel@tonic-gate 	 */
9310Sstevel@tonic-gate 	if ((ndx < (nnames - 1)) &&
9320Sstevel@tonic-gate 			    (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) {
9330Sstevel@tonic-gate 		return (TRUE);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	return (FALSE);
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate void
9400Sstevel@tonic-gate printmodules()
9410Sstevel@tonic-gate {
9420Sstevel@tonic-gate 	mod_info_t	*mi;
9430Sstevel@tonic-gate 
944*211Smike_s 	(void) printf("\f\nObject modules\n\n");
9450Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next)
946*211Smike_s 		(void) printf(" %d: %s\n", mi->id, mi->name);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate #define	IDFMT(id)	((id) < 10 ? 1 : 2)
9500Sstevel@tonic-gate #define	NMFMT(id)	((id) < 10 ? 17 : 16)
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate void
9530Sstevel@tonic-gate printindex()
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate 	nltype	**namesortnlp;
9560Sstevel@tonic-gate 	nltype	*nlp;
9570Sstevel@tonic-gate 	int	index, nnames, todo, i, j;
9580Sstevel@tonic-gate 	char	peterbuffer[BUFSIZ];
9590Sstevel@tonic-gate 	mod_info_t	*mi;
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	/*
9620Sstevel@tonic-gate 	 *	Now, sort regular function name alphabetically
9630Sstevel@tonic-gate 	 *	to create an index.
9640Sstevel@tonic-gate 	 */
9650Sstevel@tonic-gate 	namesortnlp = calloc(total_names + ncycle, sizeof (nltype *));
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	if (namesortnlp == NULL)
968*211Smike_s 		(void) fprintf(stderr, "%s: ran out of memory for sorting\n",
969*211Smike_s 		    whoami);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	nnames = 0;
9720Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
9730Sstevel@tonic-gate 		for (index = 0; index < mi->nname; index++) {
9740Sstevel@tonic-gate 			if (zflag == 0 && (mi->nl[index]).ncall == 0 &&
9750Sstevel@tonic-gate 						(mi->nl[index]).time == 0) {
9760Sstevel@tonic-gate 				continue;
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 			/*
9800Sstevel@tonic-gate 			 * Do not print certain special symbols, like
9810Sstevel@tonic-gate 			 * PRF_EXTSYM, etc. even if zflag was on.
9820Sstevel@tonic-gate 			 */
9830Sstevel@tonic-gate 			if (is_special_sym(&(mi->nl[index])))
9840Sstevel@tonic-gate 				continue;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 			namesortnlp[nnames++] = &(mi->nl[index]);
9870Sstevel@tonic-gate 		}
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	if (Cflag) {
9910Sstevel@tonic-gate 		s1 = malloc(500 * sizeof (char));
9920Sstevel@tonic-gate 		s2 = malloc(500 * sizeof (char));
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
995*211Smike_s 	qsort(namesortnlp, nnames, sizeof (nltype *), namecmp);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	for (index = 1, todo = nnames; index <= ncycle; index++)
9980Sstevel@tonic-gate 		namesortnlp[todo++] = &cyclenl[index];
9990Sstevel@tonic-gate 
1000*211Smike_s 	(void) printf("\f\nIndex by function name\n\n");
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	if (!Cflag)
10030Sstevel@tonic-gate 		index = (todo + 2) / 3;
10040Sstevel@tonic-gate 	else
10050Sstevel@tonic-gate 		index = todo;
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	for (i = 0; i < index; i++) {
10080Sstevel@tonic-gate 		if (!Cflag) {
10090Sstevel@tonic-gate 			for (j = i; j < todo; j += index) {
10100Sstevel@tonic-gate 				nlp = namesortnlp[j];
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 				if (nlp->printflag) {
1013*211Smike_s 					(void) sprintf(peterbuffer,
10140Sstevel@tonic-gate 					    "[%d]", nlp->index);
10150Sstevel@tonic-gate 				} else {
1016*211Smike_s 					(void) sprintf(peterbuffer,
10170Sstevel@tonic-gate 					    "(%d)", nlp->index);
10180Sstevel@tonic-gate 				}
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 				if (j < nnames) {
10210Sstevel@tonic-gate 					if (does_clash(namesortnlp,
10220Sstevel@tonic-gate 								j, nnames)) {
1023*211Smike_s 						(void) printf(
1024*211Smike_s 						    "%6.6s %*d:%-*.*s",
10250Sstevel@tonic-gate 							peterbuffer,
10260Sstevel@tonic-gate 							IDFMT(nlp->module->id),
10270Sstevel@tonic-gate 							nlp->module->id,
10280Sstevel@tonic-gate 							NMFMT(nlp->module->id),
10290Sstevel@tonic-gate 							NMFMT(nlp->module->id),
10300Sstevel@tonic-gate 							nlp->name);
10310Sstevel@tonic-gate 					} else {
1032*211Smike_s 						(void) printf("%6.6s %-19.19s",
10330Sstevel@tonic-gate 						    peterbuffer, nlp->name);
10340Sstevel@tonic-gate 					}
10350Sstevel@tonic-gate 				} else {
1036*211Smike_s 					(void) printf("%6.6s ", peterbuffer);
1037*211Smike_s 					(void) sprintf(peterbuffer,
10380Sstevel@tonic-gate 					    "<cycle %d>", nlp->cycleno);
1039*211Smike_s 					(void) printf("%-19.19s", peterbuffer);
10400Sstevel@tonic-gate 				}
10410Sstevel@tonic-gate 			}
10420Sstevel@tonic-gate 		} else {
10430Sstevel@tonic-gate 			nlp = namesortnlp[i];
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 			if (nlp->printflag)
1046*211Smike_s 				(void) sprintf(peterbuffer, "[%d]", nlp->index);
10470Sstevel@tonic-gate 			else
1048*211Smike_s 				(void) sprintf(peterbuffer, "(%d)", nlp->index);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 			if (i < nnames) {
10510Sstevel@tonic-gate 				char *d = demangled_name(nlp);
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 				if (does_clash(namesortnlp, i, nnames)) {
1054*211Smike_s 					(void) printf("%6.6s %d:%s\n",
1055*211Smike_s 					    peterbuffer, nlp->module->id, d);
10560Sstevel@tonic-gate 				} else
1057*211Smike_s 					(void) printf("%6.6s %s\n", peterbuffer,
1058*211Smike_s 					    d);
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 				if (d != nlp->name)
1061*211Smike_s 					(void) printf("%6.6s   [%s]", "",
1062*211Smike_s 					    nlp->name);
10630Sstevel@tonic-gate 			} else {
1064*211Smike_s 				(void) printf("%6.6s ", peterbuffer);
1065*211Smike_s 				(void) sprintf(peterbuffer, "<cycle %d>",
10660Sstevel@tonic-gate 				    nlp->cycleno);
1067*211Smike_s 				(void) printf("%-33.33s", peterbuffer);
10680Sstevel@tonic-gate 			}
10690Sstevel@tonic-gate 		}
1070*211Smike_s 		(void) printf("\n");
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 	free(namesortnlp);
10730Sstevel@tonic-gate }
1074