xref: /onnv-gate/usr/src/cmd/sgs/gprof/common/arcs.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	<stdlib.h>
310Sstevel@tonic-gate #include	"gprof.h"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  *	add (or just increment) an arc
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate void
addarc(nltype * parentp,nltype * childp,actype count)370Sstevel@tonic-gate addarc(nltype *parentp, nltype *childp, actype count)
380Sstevel@tonic-gate {
390Sstevel@tonic-gate 	arctype		*arcp;
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #ifdef DEBUG
420Sstevel@tonic-gate 	if (debug & TALLYDEBUG) {
43*211Smike_s 		(void) printf("[addarc] %lld arcs from %s to %s\n",
440Sstevel@tonic-gate 		    count, parentp->name, childp->name);
450Sstevel@tonic-gate 	}
460Sstevel@tonic-gate #endif /* DEBUG */
470Sstevel@tonic-gate 	arcp = arclookup(parentp, childp);
480Sstevel@tonic-gate 	if (arcp != 0) {
490Sstevel@tonic-gate 		/*
500Sstevel@tonic-gate 		 *	a hit:  just increment the count.
510Sstevel@tonic-gate 		 */
520Sstevel@tonic-gate #ifdef DEBUG
530Sstevel@tonic-gate 		if (!Dflag) {
540Sstevel@tonic-gate 			if (debug & TALLYDEBUG) {
55*211Smike_s 				(void) printf("[tally] hit %lld += %lld\n",
560Sstevel@tonic-gate 				    arcp->arc_count, count);
570Sstevel@tonic-gate 			}
580Sstevel@tonic-gate 		} else {
590Sstevel@tonic-gate 			if (debug & TALLYDEBUG) {
60*211Smike_s 				(void) printf("[tally] hit %lld -= %lld\n",
610Sstevel@tonic-gate 				    arcp->arc_count, count);
620Sstevel@tonic-gate 			}
630Sstevel@tonic-gate 		}
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #endif /* DEBUG */
660Sstevel@tonic-gate 		if (!Dflag)
670Sstevel@tonic-gate 			arcp->arc_count += count;
680Sstevel@tonic-gate 		else {
690Sstevel@tonic-gate 			arcp->arc_count -= count;
700Sstevel@tonic-gate 			if (arcp->arc_count < 0)
710Sstevel@tonic-gate 				arcp->arc_count = 0;
720Sstevel@tonic-gate 		}
730Sstevel@tonic-gate 		return;
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 	arcp = (arctype *)calloc(1, sizeof (*arcp));
760Sstevel@tonic-gate 	arcp->arc_parentp = parentp;
770Sstevel@tonic-gate 	arcp->arc_childp = childp;
780Sstevel@tonic-gate 	arcp->arc_count = count;
790Sstevel@tonic-gate 	/*
800Sstevel@tonic-gate 	 *	prepend this child to the children of this parent
810Sstevel@tonic-gate 	 */
820Sstevel@tonic-gate 	arcp->arc_childlist = parentp->children;
830Sstevel@tonic-gate 	parentp->children = arcp;
840Sstevel@tonic-gate 	/*
850Sstevel@tonic-gate 	 *	prepend this parent to the parents of this child
860Sstevel@tonic-gate 	 */
870Sstevel@tonic-gate 	arcp->arc_parentlist = childp->parents;
880Sstevel@tonic-gate 	childp->parents = arcp;
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  *	the code below topologically sorts the graph (collapsing cycles),
930Sstevel@tonic-gate  *	and propagates time bottom up and flags top down.
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate  *	the topologically sorted name list pointers
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate nltype	**topsortnlp;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static int
topcmp(const void * arg1,const void * arg2)102*211Smike_s topcmp(const void *arg1, const void *arg2)
1030Sstevel@tonic-gate {
104*211Smike_s 	nltype **npp1 = (nltype **)arg1;
105*211Smike_s 	nltype **npp2 = (nltype **)arg2;
106*211Smike_s 
1070Sstevel@tonic-gate 	return ((*npp1)->toporder - (*npp2)->toporder);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static void
timepropagate(nltype * parentp)1110Sstevel@tonic-gate timepropagate(nltype *parentp)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	arctype	*arcp;
1140Sstevel@tonic-gate 	nltype	*childp;
1150Sstevel@tonic-gate 	double	share;
1160Sstevel@tonic-gate 	double	propshare;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if (parentp->propfraction == 0.0) {
1190Sstevel@tonic-gate 		return;
1200Sstevel@tonic-gate 	}
1210Sstevel@tonic-gate 	/*
1220Sstevel@tonic-gate 	 *	gather time from children of this parent.
1230Sstevel@tonic-gate 	 */
1240Sstevel@tonic-gate 	for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) {
1250Sstevel@tonic-gate 		childp = arcp->arc_childp;
1260Sstevel@tonic-gate 		if (arcp->arc_count == 0) {
1270Sstevel@tonic-gate 			continue;
1280Sstevel@tonic-gate 		}
1290Sstevel@tonic-gate 		if (childp == parentp) {
1300Sstevel@tonic-gate 			continue;
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 		if (childp->propfraction == 0.0) {
1330Sstevel@tonic-gate 			continue;
1340Sstevel@tonic-gate 		}
1350Sstevel@tonic-gate 		if (childp->cyclehead != childp) {
1360Sstevel@tonic-gate 			if (parentp->cycleno == childp->cycleno) {
1370Sstevel@tonic-gate 				continue;
1380Sstevel@tonic-gate 			}
1390Sstevel@tonic-gate 			if (parentp->toporder <= childp->toporder) {
140*211Smike_s 				(void) fprintf(stderr,
1410Sstevel@tonic-gate 				    "[propagate] toporder botches\n");
1420Sstevel@tonic-gate 			}
1430Sstevel@tonic-gate 			childp = childp->cyclehead;
1440Sstevel@tonic-gate 		} else {
1450Sstevel@tonic-gate 			if (parentp->toporder <= childp->toporder) {
146*211Smike_s 				(void) fprintf(stderr,
1470Sstevel@tonic-gate 				    "[propagate] toporder botches\n");
1480Sstevel@tonic-gate 				continue;
1490Sstevel@tonic-gate 			}
1500Sstevel@tonic-gate 		}
1510Sstevel@tonic-gate 		if (childp->ncall == 0) {
1520Sstevel@tonic-gate 			continue;
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 		/*
1550Sstevel@tonic-gate 		 *	distribute time for this arc
1560Sstevel@tonic-gate 		 */
1570Sstevel@tonic-gate 		arcp->arc_time = childp->time
1580Sstevel@tonic-gate 		    * (((double)arcp->arc_count) /
1590Sstevel@tonic-gate 		    ((double)childp->ncall));
1600Sstevel@tonic-gate 		arcp->arc_childtime = childp->childtime
1610Sstevel@tonic-gate 		    * (((double)arcp->arc_count) /
1620Sstevel@tonic-gate 		    ((double)childp->ncall));
1630Sstevel@tonic-gate 		share = arcp->arc_time + arcp->arc_childtime;
1640Sstevel@tonic-gate 		parentp->childtime += share;
1650Sstevel@tonic-gate 		/*
1660Sstevel@tonic-gate 		 *	(1 - propfraction) gets lost along the way
1670Sstevel@tonic-gate 		 */
1680Sstevel@tonic-gate 		propshare = parentp->propfraction * share;
1690Sstevel@tonic-gate 		/*
1700Sstevel@tonic-gate 		 *	fix things for printing
1710Sstevel@tonic-gate 		 */
1720Sstevel@tonic-gate 		parentp->propchild += propshare;
1730Sstevel@tonic-gate 		arcp->arc_time *= parentp->propfraction;
1740Sstevel@tonic-gate 		arcp->arc_childtime *= parentp->propfraction;
1750Sstevel@tonic-gate 		/*
1760Sstevel@tonic-gate 		 *	add this share to the parent's cycle header, if any.
1770Sstevel@tonic-gate 		 */
1780Sstevel@tonic-gate 		if (parentp->cyclehead != parentp) {
1790Sstevel@tonic-gate 			parentp->cyclehead->childtime += share;
1800Sstevel@tonic-gate 			parentp->cyclehead->propchild += propshare;
1810Sstevel@tonic-gate 		}
1820Sstevel@tonic-gate #ifdef DEBUG
1830Sstevel@tonic-gate 		if (debug & PROPDEBUG) {
184*211Smike_s 			(void) printf("[dotime] child \t");
1850Sstevel@tonic-gate 			printname(childp);
186*211Smike_s 			(void) printf(" with %f %f %lld/%lld\n",
1870Sstevel@tonic-gate 			    childp->time, childp->childtime,
1880Sstevel@tonic-gate 			    arcp->arc_count, childp->ncall);
189*211Smike_s 			(void) printf("[dotime] parent\t");
1900Sstevel@tonic-gate 			printname(parentp);
191*211Smike_s 			(void) printf("\n[dotime] share %f\n", share);
1920Sstevel@tonic-gate 		}
1930Sstevel@tonic-gate #endif /* DEBUG */
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate static void
cycletime(void)199*211Smike_s cycletime(void)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	int		cycle;
2020Sstevel@tonic-gate 	nltype		*cyclenlp;
2030Sstevel@tonic-gate 	nltype		*childp;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	for (cycle = 1; cycle <= ncycle; cycle += 1) {
2060Sstevel@tonic-gate 		cyclenlp = &cyclenl[cycle];
2070Sstevel@tonic-gate 		for (childp = cyclenlp->cnext; childp; childp = childp->cnext) {
2080Sstevel@tonic-gate 			if (childp->propfraction == 0.0) {
2090Sstevel@tonic-gate 				/*
2100Sstevel@tonic-gate 				 * all members have the same propfraction
2110Sstevel@tonic-gate 				 * except those that were excluded with -E
2120Sstevel@tonic-gate 				 */
2130Sstevel@tonic-gate 				continue;
2140Sstevel@tonic-gate 			}
2150Sstevel@tonic-gate 			cyclenlp->time += childp->time;
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 		cyclenlp->propself = cyclenlp->propfraction * cyclenlp->time;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate static void
dotime(void)223*211Smike_s dotime(void)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	int	index;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	cycletime();
2280Sstevel@tonic-gate 	for (index = 0; index < total_names; index += 1) {
2290Sstevel@tonic-gate 		timepropagate(topsortnlp[index]);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate static void
cyclelink(void)235*211Smike_s cyclelink(void)
2360Sstevel@tonic-gate {
237*211Smike_s 	nltype	*nlp;
238*211Smike_s 	nltype	*cyclenlp;
2390Sstevel@tonic-gate 	int		cycle;
2400Sstevel@tonic-gate 	nltype		*memberp;
2410Sstevel@tonic-gate 	arctype		*arcp;
2420Sstevel@tonic-gate 	mod_info_t	*mi;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 *	Count the number of cycles, and initialize the cycle lists
2460Sstevel@tonic-gate 	 */
2470Sstevel@tonic-gate 	ncycle = 0;
2480Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
2490Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
2500Sstevel@tonic-gate 			/*
2510Sstevel@tonic-gate 			 *	this is how you find unattached cycles
2520Sstevel@tonic-gate 			 */
2530Sstevel@tonic-gate 			if (nlp->cyclehead == nlp && nlp->cnext != 0) {
2540Sstevel@tonic-gate 				ncycle += 1;
2550Sstevel@tonic-gate 			}
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	/*
2600Sstevel@tonic-gate 	 *	cyclenl is indexed by cycle number:
2610Sstevel@tonic-gate 	 *	i.e. it is origin 1, not origin 0.
2620Sstevel@tonic-gate 	 */
2630Sstevel@tonic-gate 	cyclenl = (nltype *) calloc(ncycle + 1, sizeof (nltype));
2640Sstevel@tonic-gate 	if (cyclenl == 0) {
265*211Smike_s 		(void) fprintf(stderr,
2660Sstevel@tonic-gate 		    "%s: No room for %d bytes of cycle headers\n",
2670Sstevel@tonic-gate 		    whoami, (ncycle + 1) * sizeof (nltype));
2680Sstevel@tonic-gate 		done();
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/*
2720Sstevel@tonic-gate 	 *	now link cycles to true cycleheads,
2730Sstevel@tonic-gate 	 *	number them, accumulate the data for the cycle
2740Sstevel@tonic-gate 	 */
2750Sstevel@tonic-gate 	cycle = 0;
2760Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
2770Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
2780Sstevel@tonic-gate 			if (!(nlp->cyclehead == nlp && nlp->cnext != 0)) {
2790Sstevel@tonic-gate 				continue;
2800Sstevel@tonic-gate 			}
2810Sstevel@tonic-gate 			cycle += 1;
2820Sstevel@tonic-gate 			cyclenlp = &cyclenl[cycle];
2830Sstevel@tonic-gate 			cyclenlp->name = 0;		/* the name */
2840Sstevel@tonic-gate 			cyclenlp->value = 0;		/* pc entry point */
2850Sstevel@tonic-gate 			cyclenlp->time = 0.0;		/* ticks in routine */
2860Sstevel@tonic-gate 			cyclenlp->childtime = 0.0;	/* cumulative ticks */
2870Sstevel@tonic-gate 							/*	in children */
2880Sstevel@tonic-gate 			cyclenlp->ncall = 0;		/* how many times */
2890Sstevel@tonic-gate 							/*	   called */
2900Sstevel@tonic-gate 			cyclenlp->selfcalls = 0;	/* how many calls */
2910Sstevel@tonic-gate 							/*	  to self */
2920Sstevel@tonic-gate 			cyclenlp->propfraction = 0.0;	/* what % of time */
2930Sstevel@tonic-gate 							/*	propagates */
2940Sstevel@tonic-gate 			cyclenlp->propself = 0.0;	/* how much self time */
2950Sstevel@tonic-gate 							/*	   propagates */
2960Sstevel@tonic-gate 			cyclenlp->propchild = 0.0;	/* how much of child */
2970Sstevel@tonic-gate 							/*   time propagates */
2980Sstevel@tonic-gate 			cyclenlp->printflag = TRUE;	/* should this be */
2990Sstevel@tonic-gate 							/*	 printed? */
3000Sstevel@tonic-gate 			cyclenlp->index = 0;		/* index in the */
3010Sstevel@tonic-gate 							/*   graph list */
3020Sstevel@tonic-gate 			cyclenlp->toporder = DFN_NAN;	/* graph call chain */
3030Sstevel@tonic-gate 							/*   top-sort order */
3040Sstevel@tonic-gate 			cyclenlp->cycleno = cycle;	/* internal number */
3050Sstevel@tonic-gate 							/*	of cycle on */
3060Sstevel@tonic-gate 			cyclenlp->cyclehead = cyclenlp;	/* head of cycle ptr */
3070Sstevel@tonic-gate 			cyclenlp->cnext = nlp;		/* ptr to next member */
3080Sstevel@tonic-gate 							/*	of cycle */
3090Sstevel@tonic-gate 			cyclenlp->parents = 0;		/* caller arcs list */
3100Sstevel@tonic-gate 			cyclenlp->children = 0;		/* callee arcs list */
3110Sstevel@tonic-gate #ifdef DEBUG
3120Sstevel@tonic-gate 			if (debug & CYCLEDEBUG) {
313*211Smike_s 				(void) printf("[cyclelink] ");
3140Sstevel@tonic-gate 				printname(nlp);
315*211Smike_s 				(void) printf(" is the head of cycle %d\n",
316*211Smike_s 				    cycle);
3170Sstevel@tonic-gate 			}
3180Sstevel@tonic-gate #endif /* DEBUG */
3190Sstevel@tonic-gate 			/*
3200Sstevel@tonic-gate 			 *	link members to cycle header
3210Sstevel@tonic-gate 			 */
3220Sstevel@tonic-gate 			for (memberp = nlp; memberp; memberp = memberp->cnext) {
3230Sstevel@tonic-gate 				memberp->cycleno = cycle;
3240Sstevel@tonic-gate 				memberp->cyclehead = cyclenlp;
3250Sstevel@tonic-gate 			}
3260Sstevel@tonic-gate 			/*
3270Sstevel@tonic-gate 			 *	count calls from outside the cycle
3280Sstevel@tonic-gate 			 *	and those among cycle members
3290Sstevel@tonic-gate 			 */
3300Sstevel@tonic-gate 			for (memberp = nlp; memberp; memberp = memberp->cnext) {
3310Sstevel@tonic-gate 				for (arcp = memberp->parents; arcp;
3320Sstevel@tonic-gate 				    arcp = arcp->arc_parentlist) {
3330Sstevel@tonic-gate 					if (arcp->arc_parentp == memberp)
3340Sstevel@tonic-gate 						continue;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 					if (arcp->arc_parentp->cycleno ==
3370Sstevel@tonic-gate 									cycle) {
3380Sstevel@tonic-gate 					    cyclenlp->selfcalls +=
3390Sstevel@tonic-gate 							arcp->arc_count;
3400Sstevel@tonic-gate 					} else
3410Sstevel@tonic-gate 					    cyclenlp->ncall += arcp->arc_count;
3420Sstevel@tonic-gate 				}
3430Sstevel@tonic-gate 			}
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate  *	check if any parent of this child
3510Sstevel@tonic-gate  *	(or outside parents of this cycle)
3520Sstevel@tonic-gate  *	have their print flags on and set the
3530Sstevel@tonic-gate  *	print flag of the child (cycle) appropriately.
3540Sstevel@tonic-gate  *	similarly, deal with propagation fractions from parents.
3550Sstevel@tonic-gate  */
3560Sstevel@tonic-gate static void
inheritflags(nltype * childp)3570Sstevel@tonic-gate inheritflags(nltype *childp)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	nltype	*headp;
3600Sstevel@tonic-gate 	arctype	*arcp;
3610Sstevel@tonic-gate 	nltype	*parentp;
3620Sstevel@tonic-gate 	nltype	*memp;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	headp = childp->cyclehead;
3650Sstevel@tonic-gate 	if (childp == headp) {
3660Sstevel@tonic-gate 		/*
3670Sstevel@tonic-gate 		 *	just a regular child, check its parents
3680Sstevel@tonic-gate 		 */
3690Sstevel@tonic-gate 		childp->printflag = FALSE;
3700Sstevel@tonic-gate 		childp->propfraction = 0.0;
3710Sstevel@tonic-gate 		for (arcp = childp->parents; arcp;
3720Sstevel@tonic-gate 		    arcp = arcp->arc_parentlist) {
3730Sstevel@tonic-gate 			parentp = arcp->arc_parentp;
3740Sstevel@tonic-gate 			if (childp == parentp) {
3750Sstevel@tonic-gate 				continue;
3760Sstevel@tonic-gate 			}
3770Sstevel@tonic-gate 			childp->printflag |= parentp->printflag;
3780Sstevel@tonic-gate 			/*
3790Sstevel@tonic-gate 			 *	if the child was never actually called
3800Sstevel@tonic-gate 			 *	(e.g. this arc is static (and all others
3810Sstevel@tonic-gate 			 *	are, too)) no time propagates along this arc.
3820Sstevel@tonic-gate 			 */
3830Sstevel@tonic-gate 			if (childp->ncall) {
3840Sstevel@tonic-gate 				childp->propfraction += parentp->propfraction
3850Sstevel@tonic-gate 				    * (((double)arcp->arc_count)
3860Sstevel@tonic-gate 				    / ((double)childp->ncall));
3870Sstevel@tonic-gate 			}
3880Sstevel@tonic-gate 		}
3890Sstevel@tonic-gate 	} else {
3900Sstevel@tonic-gate 		/*
3910Sstevel@tonic-gate 		 *	its a member of a cycle, look at all parents from
3920Sstevel@tonic-gate 		 *	outside the cycle
3930Sstevel@tonic-gate 		 */
3940Sstevel@tonic-gate 		headp->printflag = FALSE;
3950Sstevel@tonic-gate 		headp->propfraction = 0.0;
3960Sstevel@tonic-gate 		for (memp = headp->cnext; memp; memp = memp->cnext) {
3970Sstevel@tonic-gate 			for (arcp = memp->parents; arcp;
3980Sstevel@tonic-gate 			    arcp = arcp->arc_parentlist) {
3990Sstevel@tonic-gate 				if (arcp->arc_parentp->cyclehead == headp) {
4000Sstevel@tonic-gate 					continue;
4010Sstevel@tonic-gate 				}
4020Sstevel@tonic-gate 				parentp = arcp->arc_parentp;
4030Sstevel@tonic-gate 				headp->printflag |= parentp->printflag;
4040Sstevel@tonic-gate 				/*
4050Sstevel@tonic-gate 				 *	if the cycle was never actually called
4060Sstevel@tonic-gate 				 *	(e.g. this arc is static (and all
4070Sstevel@tonic-gate 				 *	others are, too)) no time propagates
4080Sstevel@tonic-gate 				 *	along this arc.
4090Sstevel@tonic-gate 				 */
4100Sstevel@tonic-gate 				if (headp->ncall) {
4110Sstevel@tonic-gate 					headp->propfraction +=
4120Sstevel@tonic-gate 					    parentp->propfraction
4130Sstevel@tonic-gate 					    * (((double)arcp->arc_count)
4140Sstevel@tonic-gate 					    / ((double)headp->ncall));
4150Sstevel@tonic-gate 				}
4160Sstevel@tonic-gate 			}
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 		for (memp = headp; memp; memp = memp->cnext) {
4190Sstevel@tonic-gate 			memp->printflag = headp->printflag;
4200Sstevel@tonic-gate 			memp->propfraction = headp->propfraction;
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate  * check here if *any* of its parents is printable
4280Sstevel@tonic-gate  * then return true else return false
4290Sstevel@tonic-gate  */
4300Sstevel@tonic-gate static int
check_ancestors(nltype * siblingp)4310Sstevel@tonic-gate check_ancestors(nltype *siblingp)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	arctype *parentsp;
4340Sstevel@tonic-gate 	if (!siblingp->parents)
4350Sstevel@tonic-gate 		return (1);
4360Sstevel@tonic-gate 	for (parentsp = siblingp->parents; parentsp;
4370Sstevel@tonic-gate 	    parentsp = parentsp->arc_parentlist) {
4380Sstevel@tonic-gate 		if (parentsp->arc_parentp->printflag)
4390Sstevel@tonic-gate 			return (1);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 	return (0);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate  * check if the parents it passes time are *all* on
4470Sstevel@tonic-gate  * the Elist in which case we do not pass the time
4480Sstevel@tonic-gate  */
4490Sstevel@tonic-gate static int
check_parents(nltype * siblingp)4500Sstevel@tonic-gate check_parents(nltype *siblingp)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	arctype *parentsp;
4530Sstevel@tonic-gate 	if (!siblingp->parents)
4540Sstevel@tonic-gate 		return (1);
4550Sstevel@tonic-gate 	for (parentsp = siblingp->parents; parentsp;
4560Sstevel@tonic-gate 	    parentsp = parentsp->arc_parentlist) {
4570Sstevel@tonic-gate 		if (!onlist(Elist, parentsp->arc_parentp->name))
4580Sstevel@tonic-gate 			return (1);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 	return (0);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  *	in one top to bottom pass over the topologically sorted namelist
4660Sstevel@tonic-gate  *	propagate:
4670Sstevel@tonic-gate  *		printflag as the union of parents' printflags
4680Sstevel@tonic-gate  *		propfraction as the sum of fractional parents' propfractions
4690Sstevel@tonic-gate  *	and while we're here, sum time for functions.
4700Sstevel@tonic-gate  */
4710Sstevel@tonic-gate static void
doflags(void)472*211Smike_s doflags(void)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate 	int	index;
4750Sstevel@tonic-gate 	nltype	*childp;
4760Sstevel@tonic-gate 	nltype	*oldhead;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	oldhead = 0;
4790Sstevel@tonic-gate 	for (index = total_names - 1; index >= 0; index -= 1) {
4800Sstevel@tonic-gate 		childp = topsortnlp[index];
4810Sstevel@tonic-gate 		/*
4820Sstevel@tonic-gate 		 *	if we haven't done this function or cycle,
4830Sstevel@tonic-gate 		 *	inherit things from parent.
4840Sstevel@tonic-gate 		 *	this way, we are linear in the number of arcs
4850Sstevel@tonic-gate 		 *	since we do all members of a cycle (and the
4860Sstevel@tonic-gate 		 *	cycle itself) as we hit the first member
4870Sstevel@tonic-gate 		 *	of the cycle.
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		if (childp->cyclehead != oldhead) {
4900Sstevel@tonic-gate 			oldhead = childp->cyclehead;
4910Sstevel@tonic-gate 			inheritflags(childp);
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate #ifdef DEBUG
4940Sstevel@tonic-gate 		if (debug & PROPDEBUG) {
495*211Smike_s 			(void) printf("[doflags] ");
4960Sstevel@tonic-gate 			printname(childp);
497*211Smike_s 			(void) printf(
498*211Smike_s 			    " inherits printflag %d and propfraction %f\n",
4990Sstevel@tonic-gate 			    childp->printflag, childp->propfraction);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate #endif /* DEBUG */
5020Sstevel@tonic-gate 		if (!childp->printflag) {
5030Sstevel@tonic-gate 			bool	on_flist;
5040Sstevel@tonic-gate 			/*
5050Sstevel@tonic-gate 			 *	printflag is off
5060Sstevel@tonic-gate 			 *	it gets turned on by
5070Sstevel@tonic-gate 			 *	being on -f list,
5080Sstevel@tonic-gate 			 *	or there not being any -f list
5090Sstevel@tonic-gate 			 *	and not being on -e list.
5100Sstevel@tonic-gate 			 */
5110Sstevel@tonic-gate 			if (((on_flist = onlist(flist, childp->name)) != 0) ||
5120Sstevel@tonic-gate 			    (!fflag && !onlist(elist, childp->name))) {
5130Sstevel@tonic-gate 				if (on_flist || check_ancestors(childp))
5140Sstevel@tonic-gate 					childp->printflag = TRUE;
5150Sstevel@tonic-gate 			}
5160Sstevel@tonic-gate 		} else {
5170Sstevel@tonic-gate 			/*
5180Sstevel@tonic-gate 			 *	this function has printing parents:
5190Sstevel@tonic-gate 			 *	maybe someone wants to shut it up
5200Sstevel@tonic-gate 			 *	by putting it on -e list.  (but favor -f
5210Sstevel@tonic-gate 			 *	over -e)
5220Sstevel@tonic-gate 			 */
5230Sstevel@tonic-gate 			if ((!onlist(flist, childp->name)) &&
5240Sstevel@tonic-gate 			    onlist(elist, childp->name)) {
5250Sstevel@tonic-gate 				childp->printflag = FALSE;
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 		if (childp->propfraction == 0.0) {
5290Sstevel@tonic-gate 			/*
5300Sstevel@tonic-gate 			 *	no parents to pass time to.
5310Sstevel@tonic-gate 			 *	collect time from children if
5320Sstevel@tonic-gate 			 *	its on -F list,
5330Sstevel@tonic-gate 			 *	or there isn't any -F list and its not
5340Sstevel@tonic-gate 			 *	on -E list.
5350Sstevel@tonic-gate 			 */
5360Sstevel@tonic-gate 			if (onlist(Flist, childp->name) ||
5370Sstevel@tonic-gate 			    (!Fflag && !onlist(Elist, childp->name))) {
5380Sstevel@tonic-gate 				childp->propfraction = 1.0;
5390Sstevel@tonic-gate 			}
5400Sstevel@tonic-gate 		} else {
5410Sstevel@tonic-gate 			/*
5420Sstevel@tonic-gate 			 *	it has parents to pass time to,
5430Sstevel@tonic-gate 			 *	but maybe someone wants to shut it up
5440Sstevel@tonic-gate 			 *	by putting it on -E list.  (but favor -F
5450Sstevel@tonic-gate 			 *	over -E)
5460Sstevel@tonic-gate 			 */
5470Sstevel@tonic-gate 			if (!onlist(Flist, childp->name) &&
5480Sstevel@tonic-gate 			    onlist(Elist, childp->name)) {
5490Sstevel@tonic-gate 				if (check_parents(childp))
5500Sstevel@tonic-gate 					childp->propfraction = 0.0;
5510Sstevel@tonic-gate 			}
5520Sstevel@tonic-gate 		}
5530Sstevel@tonic-gate 		childp->propself = childp->time * childp->propfraction;
5540Sstevel@tonic-gate 		printtime += childp->propself;
5550Sstevel@tonic-gate #ifdef DEBUG
5560Sstevel@tonic-gate 		if (debug & PROPDEBUG) {
557*211Smike_s 			(void) printf("[doflags] ");
5580Sstevel@tonic-gate 			printname(childp);
559*211Smike_s 			(void) printf(" ends up with printflag %d and "
5600Sstevel@tonic-gate 			    "propfraction %f\n",
5610Sstevel@tonic-gate 			    childp->printflag, childp->propfraction);
562*211Smike_s 			(void) printf("time %f propself %f printtime %f\n",
5630Sstevel@tonic-gate 			    childp->time, childp->propself, printtime);
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate #endif /* DEBUG */
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate nltype **
doarcs(void)571*211Smike_s doarcs(void)
5720Sstevel@tonic-gate {
5730Sstevel@tonic-gate 	nltype	*parentp, **timesortnlp;
5740Sstevel@tonic-gate 	arctype	*arcp;
5750Sstevel@tonic-gate 	long	i, index;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	extern mod_info_t	modules;
5780Sstevel@tonic-gate 	mod_info_t		*mi;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/*
5810Sstevel@tonic-gate 	 *	initialize various things:
5820Sstevel@tonic-gate 	 *	    zero out child times.
5830Sstevel@tonic-gate 	 *	    count self-recursive calls.
5840Sstevel@tonic-gate 	 *	    indicate that nothing is on cycles.
5850Sstevel@tonic-gate 	 */
5860Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
5870Sstevel@tonic-gate 		for (parentp = mi->nl; parentp < mi->npe; parentp++) {
5880Sstevel@tonic-gate 			parentp->childtime = 0.0;
5890Sstevel@tonic-gate 			arcp = arclookup(parentp, parentp);
5900Sstevel@tonic-gate 			if (arcp != 0) {
5910Sstevel@tonic-gate 				parentp->ncall -= arcp->arc_count;
5920Sstevel@tonic-gate 				parentp->selfcalls = arcp->arc_count;
5930Sstevel@tonic-gate 			} else {
5940Sstevel@tonic-gate 				parentp->selfcalls = 0;
5950Sstevel@tonic-gate 			}
5960Sstevel@tonic-gate 			parentp->propfraction = 0.0;
5970Sstevel@tonic-gate 			parentp->propself = 0.0;
5980Sstevel@tonic-gate 			parentp->propchild = 0.0;
5990Sstevel@tonic-gate 			parentp->printflag = FALSE;
6000Sstevel@tonic-gate 			parentp->toporder = DFN_NAN;
6010Sstevel@tonic-gate 			parentp->cycleno = 0;
6020Sstevel@tonic-gate 			parentp->cyclehead = parentp;
6030Sstevel@tonic-gate 			parentp->cnext = 0;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 			/*
6060Sstevel@tonic-gate 			 * Inspecting text space is valid only for
6070Sstevel@tonic-gate 			 * the program executable.
6080Sstevel@tonic-gate 			 */
6090Sstevel@tonic-gate 			if (cflag && (mi == &modules)) {
6100Sstevel@tonic-gate 				findcalls(
6110Sstevel@tonic-gate 					parentp,
6120Sstevel@tonic-gate 					parentp->value,
6130Sstevel@tonic-gate 					parentp->value + parentp->sz);
6140Sstevel@tonic-gate 			}
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/*
6190Sstevel@tonic-gate 	 *	topologically order things
6200Sstevel@tonic-gate 	 *	if any node is unnumbered,
6210Sstevel@tonic-gate 	 *	    number it and any of its descendents.
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
6240Sstevel@tonic-gate 		for (parentp = mi->nl; parentp < mi->npe; parentp++) {
6250Sstevel@tonic-gate 			if (parentp->toporder == DFN_NAN) {
6260Sstevel@tonic-gate 				dfn(parentp);
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 *	link together nodes on the same cycle
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	cyclelink();
6350Sstevel@tonic-gate 	/*
6360Sstevel@tonic-gate 	 *	Sort the symbol tables in reverse topological order
6370Sstevel@tonic-gate 	 */
6380Sstevel@tonic-gate 	topsortnlp = (nltype **) calloc(total_names, sizeof (nltype *));
6390Sstevel@tonic-gate 	if (topsortnlp == (nltype **) 0) {
640*211Smike_s 		(void) fprintf(stderr,
6410Sstevel@tonic-gate 		    "[doarcs] ran out of memory for topo sorting\n");
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 	index = 0;
6440Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
6450Sstevel@tonic-gate 		for (i = 0; i < mi->nname; i++)
6460Sstevel@tonic-gate 		    topsortnlp[index++] = &(mi->nl[i]);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
649*211Smike_s 	qsort(topsortnlp, total_names, sizeof (nltype *), topcmp);
6500Sstevel@tonic-gate #ifdef DEBUG
6510Sstevel@tonic-gate 	if (debug & DFNDEBUG) {
652*211Smike_s 		(void) printf("[doarcs] topological sort listing\n");
6530Sstevel@tonic-gate 		for (index = 0; index < total_names; index += 1) {
654*211Smike_s 			(void) printf("[doarcs] ");
655*211Smike_s 			(void) printf("%d:", topsortnlp[ index ]->toporder);
6560Sstevel@tonic-gate 			printname(topsortnlp[ index ]);
657*211Smike_s 			(void) printf("\n");
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate #endif /* DEBUG */
6610Sstevel@tonic-gate 	/*
6620Sstevel@tonic-gate 	 *	starting from the topological top,
6630Sstevel@tonic-gate 	 *	propagate print flags to children.
6640Sstevel@tonic-gate 	 *	also, calculate propagation fractions.
6650Sstevel@tonic-gate 	 *	this happens before time propagation
6660Sstevel@tonic-gate 	 *	since time propagation uses the fractions.
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	doflags();
6690Sstevel@tonic-gate 	/*
6700Sstevel@tonic-gate 	 *	starting from the topological bottom,
6710Sstevel@tonic-gate 	 *	propogate children times up to parents.
6720Sstevel@tonic-gate 	 */
6730Sstevel@tonic-gate 	dotime();
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 *	Now, sort by propself + propchild.
6760Sstevel@tonic-gate 	 *	sorting both the regular function names
6770Sstevel@tonic-gate 	 *	and cycle headers.
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	timesortnlp = (nltype **) calloc(total_names + ncycle,
6800Sstevel@tonic-gate 							sizeof (nltype *));
6810Sstevel@tonic-gate 	if (timesortnlp == (nltype **) 0) {
682*211Smike_s 		(void) fprintf(stderr,
683*211Smike_s 		    "%s: ran out of memory for sorting\n", whoami);
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	index = 0;
6870Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
6880Sstevel@tonic-gate 		for (i = 0; i < mi->nname; i++)
6890Sstevel@tonic-gate 		    timesortnlp[index++] = &(mi->nl[i]);
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	for (index = 1; index <= ncycle; index++)
6930Sstevel@tonic-gate 		timesortnlp[total_names+index-1] = &cyclenl[index];
6940Sstevel@tonic-gate 
695*211Smike_s 	qsort(timesortnlp, total_names + ncycle, sizeof (nltype *), totalcmp);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	for (index = 0; index < total_names + ncycle; index++)
6980Sstevel@tonic-gate 		timesortnlp[index]->index = index + 1;
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	return (timesortnlp);
7010Sstevel@tonic-gate }
702