xref: /openbsd-src/gnu/usr.bin/binutils-2.17/gprof/cg_arcs.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /*
2*3d8817e4Smiod  * Copyright (c) 1983, 1993, 2001
3*3d8817e4Smiod  *      The Regents of the University of California.  All rights reserved.
4*3d8817e4Smiod  *
5*3d8817e4Smiod  * Redistribution and use in source and binary forms, with or without
6*3d8817e4Smiod  * modification, are permitted provided that the following conditions
7*3d8817e4Smiod  * are met:
8*3d8817e4Smiod  * 1. Redistributions of source code must retain the above copyright
9*3d8817e4Smiod  *    notice, this list of conditions and the following disclaimer.
10*3d8817e4Smiod  * 2. Redistributions in binary form must reproduce the above copyright
11*3d8817e4Smiod  *    notice, this list of conditions and the following disclaimer in the
12*3d8817e4Smiod  *    documentation and/or other materials provided with the distribution.
13*3d8817e4Smiod  * 3. Neither the name of the University nor the names of its contributors
14*3d8817e4Smiod  *    may be used to endorse or promote products derived from this software
15*3d8817e4Smiod  *    without specific prior written permission.
16*3d8817e4Smiod  *
17*3d8817e4Smiod  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18*3d8817e4Smiod  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*3d8817e4Smiod  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*3d8817e4Smiod  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21*3d8817e4Smiod  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*3d8817e4Smiod  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*3d8817e4Smiod  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*3d8817e4Smiod  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*3d8817e4Smiod  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*3d8817e4Smiod  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*3d8817e4Smiod  * SUCH DAMAGE.
28*3d8817e4Smiod  */
29*3d8817e4Smiod #include "libiberty.h"
30*3d8817e4Smiod #include "gprof.h"
31*3d8817e4Smiod #include "search_list.h"
32*3d8817e4Smiod #include "source.h"
33*3d8817e4Smiod #include "symtab.h"
34*3d8817e4Smiod #include "call_graph.h"
35*3d8817e4Smiod #include "cg_arcs.h"
36*3d8817e4Smiod #include "cg_dfn.h"
37*3d8817e4Smiod #include "cg_print.h"
38*3d8817e4Smiod #include "utils.h"
39*3d8817e4Smiod #include "sym_ids.h"
40*3d8817e4Smiod 
41*3d8817e4Smiod static int cmp_topo (const PTR, const PTR);
42*3d8817e4Smiod static void propagate_time (Sym *);
43*3d8817e4Smiod static void cycle_time (void);
44*3d8817e4Smiod static void cycle_link (void);
45*3d8817e4Smiod static void inherit_flags (Sym *);
46*3d8817e4Smiod static void propagate_flags (Sym **);
47*3d8817e4Smiod static int cmp_total (const PTR, const PTR);
48*3d8817e4Smiod 
49*3d8817e4Smiod Sym *cycle_header;
50*3d8817e4Smiod unsigned int num_cycles;
51*3d8817e4Smiod Arc **arcs;
52*3d8817e4Smiod unsigned int numarcs;
53*3d8817e4Smiod 
54*3d8817e4Smiod /*
55*3d8817e4Smiod  * Return TRUE iff PARENT has an arc to covers the address
56*3d8817e4Smiod  * range covered by CHILD.
57*3d8817e4Smiod  */
58*3d8817e4Smiod Arc *
arc_lookup(Sym * parent,Sym * child)59*3d8817e4Smiod arc_lookup (Sym *parent, Sym *child)
60*3d8817e4Smiod {
61*3d8817e4Smiod   Arc *arc;
62*3d8817e4Smiod 
63*3d8817e4Smiod   if (!parent || !child)
64*3d8817e4Smiod     {
65*3d8817e4Smiod       printf ("[arc_lookup] parent == 0 || child == 0\n");
66*3d8817e4Smiod       return 0;
67*3d8817e4Smiod     }
68*3d8817e4Smiod   DBG (LOOKUPDEBUG, printf ("[arc_lookup] parent %s child %s\n",
69*3d8817e4Smiod 			    parent->name, child->name));
70*3d8817e4Smiod   for (arc = parent->cg.children; arc; arc = arc->next_child)
71*3d8817e4Smiod     {
72*3d8817e4Smiod       DBG (LOOKUPDEBUG, printf ("[arc_lookup]\t parent %s child %s\n",
73*3d8817e4Smiod 				arc->parent->name, arc->child->name));
74*3d8817e4Smiod       if (child->addr >= arc->child->addr
75*3d8817e4Smiod 	  && child->end_addr <= arc->child->end_addr)
76*3d8817e4Smiod 	{
77*3d8817e4Smiod 	  return arc;
78*3d8817e4Smiod 	}
79*3d8817e4Smiod     }
80*3d8817e4Smiod   return 0;
81*3d8817e4Smiod }
82*3d8817e4Smiod 
83*3d8817e4Smiod 
84*3d8817e4Smiod /*
85*3d8817e4Smiod  * Add (or just increment) an arc:
86*3d8817e4Smiod  */
87*3d8817e4Smiod void
arc_add(Sym * parent,Sym * child,unsigned long count)88*3d8817e4Smiod arc_add (Sym *parent, Sym *child, unsigned long count)
89*3d8817e4Smiod {
90*3d8817e4Smiod   static unsigned int maxarcs = 0;
91*3d8817e4Smiod   Arc *arc, **newarcs;
92*3d8817e4Smiod 
93*3d8817e4Smiod   DBG (TALLYDEBUG, printf ("[arc_add] %lu arcs from %s to %s\n",
94*3d8817e4Smiod 			   count, parent->name, child->name));
95*3d8817e4Smiod   arc = arc_lookup (parent, child);
96*3d8817e4Smiod   if (arc)
97*3d8817e4Smiod     {
98*3d8817e4Smiod       /*
99*3d8817e4Smiod        * A hit: just increment the count.
100*3d8817e4Smiod        */
101*3d8817e4Smiod       DBG (TALLYDEBUG, printf ("[tally] hit %lu += %lu\n",
102*3d8817e4Smiod 			       arc->count, count));
103*3d8817e4Smiod       arc->count += count;
104*3d8817e4Smiod       return;
105*3d8817e4Smiod     }
106*3d8817e4Smiod   arc = (Arc *) xmalloc (sizeof (*arc));
107*3d8817e4Smiod   memset (arc, 0, sizeof (*arc));
108*3d8817e4Smiod   arc->parent = parent;
109*3d8817e4Smiod   arc->child = child;
110*3d8817e4Smiod   arc->count = count;
111*3d8817e4Smiod 
112*3d8817e4Smiod   /* If this isn't an arc for a recursive call to parent, then add it
113*3d8817e4Smiod      to the array of arcs.  */
114*3d8817e4Smiod   if (parent != child)
115*3d8817e4Smiod     {
116*3d8817e4Smiod       /* If we've exhausted space in our current array, get a new one
117*3d8817e4Smiod 	 and copy the contents.   We might want to throttle the doubling
118*3d8817e4Smiod 	 factor one day.  */
119*3d8817e4Smiod       if (numarcs == maxarcs)
120*3d8817e4Smiod 	{
121*3d8817e4Smiod 	  /* Determine how much space we want to allocate.  */
122*3d8817e4Smiod 	  if (maxarcs == 0)
123*3d8817e4Smiod 	    maxarcs = 1;
124*3d8817e4Smiod 	  maxarcs *= 2;
125*3d8817e4Smiod 
126*3d8817e4Smiod 	  /* Allocate the new array.  */
127*3d8817e4Smiod 	  newarcs = (Arc **)xmalloc(sizeof (Arc *) * maxarcs);
128*3d8817e4Smiod 
129*3d8817e4Smiod 	  /* Copy the old array's contents into the new array.  */
130*3d8817e4Smiod 	  memcpy (newarcs, arcs, numarcs * sizeof (Arc *));
131*3d8817e4Smiod 
132*3d8817e4Smiod 	  /* Free up the old array.  */
133*3d8817e4Smiod 	  free (arcs);
134*3d8817e4Smiod 
135*3d8817e4Smiod 	  /* And make the new array be the current array.  */
136*3d8817e4Smiod 	  arcs = newarcs;
137*3d8817e4Smiod 	}
138*3d8817e4Smiod 
139*3d8817e4Smiod       /* Place this arc in the arc array.  */
140*3d8817e4Smiod       arcs[numarcs++] = arc;
141*3d8817e4Smiod     }
142*3d8817e4Smiod 
143*3d8817e4Smiod   /* prepend this child to the children of this parent: */
144*3d8817e4Smiod   arc->next_child = parent->cg.children;
145*3d8817e4Smiod   parent->cg.children = arc;
146*3d8817e4Smiod 
147*3d8817e4Smiod   /* prepend this parent to the parents of this child: */
148*3d8817e4Smiod   arc->next_parent = child->cg.parents;
149*3d8817e4Smiod   child->cg.parents = arc;
150*3d8817e4Smiod }
151*3d8817e4Smiod 
152*3d8817e4Smiod 
153*3d8817e4Smiod static int
cmp_topo(const PTR lp,const PTR rp)154*3d8817e4Smiod cmp_topo (const PTR lp, const PTR rp)
155*3d8817e4Smiod {
156*3d8817e4Smiod   const Sym *left = *(const Sym **) lp;
157*3d8817e4Smiod   const Sym *right = *(const Sym **) rp;
158*3d8817e4Smiod 
159*3d8817e4Smiod   return left->cg.top_order - right->cg.top_order;
160*3d8817e4Smiod }
161*3d8817e4Smiod 
162*3d8817e4Smiod 
163*3d8817e4Smiod static void
propagate_time(Sym * parent)164*3d8817e4Smiod propagate_time (Sym *parent)
165*3d8817e4Smiod {
166*3d8817e4Smiod   Arc *arc;
167*3d8817e4Smiod   Sym *child;
168*3d8817e4Smiod   double share, prop_share;
169*3d8817e4Smiod 
170*3d8817e4Smiod   if (parent->cg.prop.fract == 0.0)
171*3d8817e4Smiod     {
172*3d8817e4Smiod       return;
173*3d8817e4Smiod     }
174*3d8817e4Smiod 
175*3d8817e4Smiod   /* gather time from children of this parent: */
176*3d8817e4Smiod 
177*3d8817e4Smiod   for (arc = parent->cg.children; arc; arc = arc->next_child)
178*3d8817e4Smiod     {
179*3d8817e4Smiod       child = arc->child;
180*3d8817e4Smiod       if (arc->count == 0 || child == parent || child->cg.prop.fract == 0)
181*3d8817e4Smiod 	{
182*3d8817e4Smiod 	  continue;
183*3d8817e4Smiod 	}
184*3d8817e4Smiod       if (child->cg.cyc.head != child)
185*3d8817e4Smiod 	{
186*3d8817e4Smiod 	  if (parent->cg.cyc.num == child->cg.cyc.num)
187*3d8817e4Smiod 	    {
188*3d8817e4Smiod 	      continue;
189*3d8817e4Smiod 	    }
190*3d8817e4Smiod 	  if (parent->cg.top_order <= child->cg.top_order)
191*3d8817e4Smiod 	    {
192*3d8817e4Smiod 	      fprintf (stderr, "[propagate] toporder botches\n");
193*3d8817e4Smiod 	    }
194*3d8817e4Smiod 	  child = child->cg.cyc.head;
195*3d8817e4Smiod 	}
196*3d8817e4Smiod       else
197*3d8817e4Smiod 	{
198*3d8817e4Smiod 	  if (parent->cg.top_order <= child->cg.top_order)
199*3d8817e4Smiod 	    {
200*3d8817e4Smiod 	      fprintf (stderr, "[propagate] toporder botches\n");
201*3d8817e4Smiod 	      continue;
202*3d8817e4Smiod 	    }
203*3d8817e4Smiod 	}
204*3d8817e4Smiod       if (child->ncalls == 0)
205*3d8817e4Smiod 	{
206*3d8817e4Smiod 	  continue;
207*3d8817e4Smiod 	}
208*3d8817e4Smiod 
209*3d8817e4Smiod       /* distribute time for this arc: */
210*3d8817e4Smiod       arc->time = child->hist.time * (((double) arc->count)
211*3d8817e4Smiod 				      / ((double) child->ncalls));
212*3d8817e4Smiod       arc->child_time = child->cg.child_time
213*3d8817e4Smiod 	* (((double) arc->count) / ((double) child->ncalls));
214*3d8817e4Smiod       share = arc->time + arc->child_time;
215*3d8817e4Smiod       parent->cg.child_time += share;
216*3d8817e4Smiod 
217*3d8817e4Smiod       /* (1 - cg.prop.fract) gets lost along the way: */
218*3d8817e4Smiod       prop_share = parent->cg.prop.fract * share;
219*3d8817e4Smiod 
220*3d8817e4Smiod       /* fix things for printing: */
221*3d8817e4Smiod       parent->cg.prop.child += prop_share;
222*3d8817e4Smiod       arc->time *= parent->cg.prop.fract;
223*3d8817e4Smiod       arc->child_time *= parent->cg.prop.fract;
224*3d8817e4Smiod 
225*3d8817e4Smiod       /* add this share to the parent's cycle header, if any: */
226*3d8817e4Smiod       if (parent->cg.cyc.head != parent)
227*3d8817e4Smiod 	{
228*3d8817e4Smiod 	  parent->cg.cyc.head->cg.child_time += share;
229*3d8817e4Smiod 	  parent->cg.cyc.head->cg.prop.child += prop_share;
230*3d8817e4Smiod 	}
231*3d8817e4Smiod       DBG (PROPDEBUG,
232*3d8817e4Smiod 	   printf ("[prop_time] child \t");
233*3d8817e4Smiod 	   print_name (child);
234*3d8817e4Smiod 	   printf (" with %f %f %lu/%lu\n", child->hist.time,
235*3d8817e4Smiod 		   child->cg.child_time, arc->count, child->ncalls);
236*3d8817e4Smiod 	   printf ("[prop_time] parent\t");
237*3d8817e4Smiod 	   print_name (parent);
238*3d8817e4Smiod 	   printf ("\n[prop_time] share %f\n", share));
239*3d8817e4Smiod     }
240*3d8817e4Smiod }
241*3d8817e4Smiod 
242*3d8817e4Smiod 
243*3d8817e4Smiod /*
244*3d8817e4Smiod  * Compute the time of a cycle as the sum of the times of all
245*3d8817e4Smiod  * its members.
246*3d8817e4Smiod  */
247*3d8817e4Smiod static void
cycle_time()248*3d8817e4Smiod cycle_time ()
249*3d8817e4Smiod {
250*3d8817e4Smiod   Sym *member, *cyc;
251*3d8817e4Smiod 
252*3d8817e4Smiod   for (cyc = &cycle_header[1]; cyc <= &cycle_header[num_cycles]; ++cyc)
253*3d8817e4Smiod     {
254*3d8817e4Smiod       for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next)
255*3d8817e4Smiod 	{
256*3d8817e4Smiod 	  if (member->cg.prop.fract == 0.0)
257*3d8817e4Smiod 	    {
258*3d8817e4Smiod 	      /*
259*3d8817e4Smiod 	       * All members have the same propfraction except those
260*3d8817e4Smiod 	       * that were excluded with -E.
261*3d8817e4Smiod 	       */
262*3d8817e4Smiod 	      continue;
263*3d8817e4Smiod 	    }
264*3d8817e4Smiod 	  cyc->hist.time += member->hist.time;
265*3d8817e4Smiod 	}
266*3d8817e4Smiod       cyc->cg.prop.self = cyc->cg.prop.fract * cyc->hist.time;
267*3d8817e4Smiod     }
268*3d8817e4Smiod }
269*3d8817e4Smiod 
270*3d8817e4Smiod 
271*3d8817e4Smiod static void
cycle_link()272*3d8817e4Smiod cycle_link ()
273*3d8817e4Smiod {
274*3d8817e4Smiod   Sym *sym, *cyc, *member;
275*3d8817e4Smiod   Arc *arc;
276*3d8817e4Smiod   int num;
277*3d8817e4Smiod 
278*3d8817e4Smiod   /* count the number of cycles, and initialize the cycle lists: */
279*3d8817e4Smiod 
280*3d8817e4Smiod   num_cycles = 0;
281*3d8817e4Smiod   for (sym = symtab.base; sym < symtab.limit; ++sym)
282*3d8817e4Smiod     {
283*3d8817e4Smiod       /* this is how you find unattached cycles: */
284*3d8817e4Smiod       if (sym->cg.cyc.head == sym && sym->cg.cyc.next)
285*3d8817e4Smiod 	{
286*3d8817e4Smiod 	  ++num_cycles;
287*3d8817e4Smiod 	}
288*3d8817e4Smiod     }
289*3d8817e4Smiod 
290*3d8817e4Smiod   /*
291*3d8817e4Smiod    * cycle_header is indexed by cycle number: i.e. it is origin 1,
292*3d8817e4Smiod    * not origin 0.
293*3d8817e4Smiod    */
294*3d8817e4Smiod   cycle_header = (Sym *) xmalloc ((num_cycles + 1) * sizeof (Sym));
295*3d8817e4Smiod 
296*3d8817e4Smiod   /*
297*3d8817e4Smiod    * Now link cycles to true cycle-heads, number them, accumulate
298*3d8817e4Smiod    * the data for the cycle.
299*3d8817e4Smiod    */
300*3d8817e4Smiod   num = 0;
301*3d8817e4Smiod   cyc = cycle_header;
302*3d8817e4Smiod   for (sym = symtab.base; sym < symtab.limit; ++sym)
303*3d8817e4Smiod     {
304*3d8817e4Smiod       if (!(sym->cg.cyc.head == sym && sym->cg.cyc.next != 0))
305*3d8817e4Smiod 	{
306*3d8817e4Smiod 	  continue;
307*3d8817e4Smiod 	}
308*3d8817e4Smiod       ++num;
309*3d8817e4Smiod       ++cyc;
310*3d8817e4Smiod       sym_init (cyc);
311*3d8817e4Smiod       cyc->cg.print_flag = TRUE;	/* should this be printed? */
312*3d8817e4Smiod       cyc->cg.top_order = DFN_NAN;	/* graph call chain top-sort order */
313*3d8817e4Smiod       cyc->cg.cyc.num = num;	/* internal number of cycle on */
314*3d8817e4Smiod       cyc->cg.cyc.head = cyc;	/* pointer to head of cycle */
315*3d8817e4Smiod       cyc->cg.cyc.next = sym;	/* pointer to next member of cycle */
316*3d8817e4Smiod       DBG (CYCLEDEBUG, printf ("[cycle_link] ");
317*3d8817e4Smiod 	   print_name (sym);
318*3d8817e4Smiod 	   printf (" is the head of cycle %d\n", num));
319*3d8817e4Smiod 
320*3d8817e4Smiod       /* link members to cycle header: */
321*3d8817e4Smiod       for (member = sym; member; member = member->cg.cyc.next)
322*3d8817e4Smiod 	{
323*3d8817e4Smiod 	  member->cg.cyc.num = num;
324*3d8817e4Smiod 	  member->cg.cyc.head = cyc;
325*3d8817e4Smiod 	}
326*3d8817e4Smiod 
327*3d8817e4Smiod       /*
328*3d8817e4Smiod        * Count calls from outside the cycle and those among cycle
329*3d8817e4Smiod        * members:
330*3d8817e4Smiod        */
331*3d8817e4Smiod       for (member = sym; member; member = member->cg.cyc.next)
332*3d8817e4Smiod 	{
333*3d8817e4Smiod 	  for (arc = member->cg.parents; arc; arc = arc->next_parent)
334*3d8817e4Smiod 	    {
335*3d8817e4Smiod 	      if (arc->parent == member)
336*3d8817e4Smiod 		{
337*3d8817e4Smiod 		  continue;
338*3d8817e4Smiod 		}
339*3d8817e4Smiod 	      if (arc->parent->cg.cyc.num == num)
340*3d8817e4Smiod 		{
341*3d8817e4Smiod 		  cyc->cg.self_calls += arc->count;
342*3d8817e4Smiod 		}
343*3d8817e4Smiod 	      else
344*3d8817e4Smiod 		{
345*3d8817e4Smiod 		  cyc->ncalls += arc->count;
346*3d8817e4Smiod 		}
347*3d8817e4Smiod 	    }
348*3d8817e4Smiod 	}
349*3d8817e4Smiod     }
350*3d8817e4Smiod }
351*3d8817e4Smiod 
352*3d8817e4Smiod 
353*3d8817e4Smiod /*
354*3d8817e4Smiod  * Check if any parent of this child (or outside parents of this
355*3d8817e4Smiod  * cycle) have their print flags on and set the print flag of the
356*3d8817e4Smiod  * child (cycle) appropriately.  Similarly, deal with propagation
357*3d8817e4Smiod  * fractions from parents.
358*3d8817e4Smiod  */
359*3d8817e4Smiod static void
inherit_flags(Sym * child)360*3d8817e4Smiod inherit_flags (Sym *child)
361*3d8817e4Smiod {
362*3d8817e4Smiod   Sym *head, *parent, *member;
363*3d8817e4Smiod   Arc *arc;
364*3d8817e4Smiod 
365*3d8817e4Smiod   head = child->cg.cyc.head;
366*3d8817e4Smiod   if (child == head)
367*3d8817e4Smiod     {
368*3d8817e4Smiod       /* just a regular child, check its parents: */
369*3d8817e4Smiod       child->cg.print_flag = FALSE;
370*3d8817e4Smiod       child->cg.prop.fract = 0.0;
371*3d8817e4Smiod       for (arc = child->cg.parents; arc; arc = arc->next_parent)
372*3d8817e4Smiod 	{
373*3d8817e4Smiod 	  parent = arc->parent;
374*3d8817e4Smiod 	  if (child == parent)
375*3d8817e4Smiod 	    {
376*3d8817e4Smiod 	      continue;
377*3d8817e4Smiod 	    }
378*3d8817e4Smiod 	  child->cg.print_flag |= parent->cg.print_flag;
379*3d8817e4Smiod 	  /*
380*3d8817e4Smiod 	   * If the child was never actually called (e.g., this arc
381*3d8817e4Smiod 	   * is static (and all others are, too)) no time propagates
382*3d8817e4Smiod 	   * along this arc.
383*3d8817e4Smiod 	   */
384*3d8817e4Smiod 	  if (child->ncalls != 0)
385*3d8817e4Smiod 	    {
386*3d8817e4Smiod 	      child->cg.prop.fract += parent->cg.prop.fract
387*3d8817e4Smiod 		* (((double) arc->count) / ((double) child->ncalls));
388*3d8817e4Smiod 	    }
389*3d8817e4Smiod 	}
390*3d8817e4Smiod     }
391*3d8817e4Smiod   else
392*3d8817e4Smiod     {
393*3d8817e4Smiod       /*
394*3d8817e4Smiod        * Its a member of a cycle, look at all parents from outside
395*3d8817e4Smiod        * the cycle.
396*3d8817e4Smiod        */
397*3d8817e4Smiod       head->cg.print_flag = FALSE;
398*3d8817e4Smiod       head->cg.prop.fract = 0.0;
399*3d8817e4Smiod       for (member = head->cg.cyc.next; member; member = member->cg.cyc.next)
400*3d8817e4Smiod 	{
401*3d8817e4Smiod 	  for (arc = member->cg.parents; arc; arc = arc->next_parent)
402*3d8817e4Smiod 	    {
403*3d8817e4Smiod 	      if (arc->parent->cg.cyc.head == head)
404*3d8817e4Smiod 		{
405*3d8817e4Smiod 		  continue;
406*3d8817e4Smiod 		}
407*3d8817e4Smiod 	      parent = arc->parent;
408*3d8817e4Smiod 	      head->cg.print_flag |= parent->cg.print_flag;
409*3d8817e4Smiod 	      /*
410*3d8817e4Smiod 	       * If the cycle was never actually called (e.g. this
411*3d8817e4Smiod 	       * arc is static (and all others are, too)) no time
412*3d8817e4Smiod 	       * propagates along this arc.
413*3d8817e4Smiod 	       */
414*3d8817e4Smiod 	      if (head->ncalls != 0)
415*3d8817e4Smiod 		{
416*3d8817e4Smiod 		  head->cg.prop.fract += parent->cg.prop.fract
417*3d8817e4Smiod 		    * (((double) arc->count) / ((double) head->ncalls));
418*3d8817e4Smiod 		}
419*3d8817e4Smiod 	    }
420*3d8817e4Smiod 	}
421*3d8817e4Smiod       for (member = head; member; member = member->cg.cyc.next)
422*3d8817e4Smiod 	{
423*3d8817e4Smiod 	  member->cg.print_flag = head->cg.print_flag;
424*3d8817e4Smiod 	  member->cg.prop.fract = head->cg.prop.fract;
425*3d8817e4Smiod 	}
426*3d8817e4Smiod     }
427*3d8817e4Smiod }
428*3d8817e4Smiod 
429*3d8817e4Smiod 
430*3d8817e4Smiod /*
431*3d8817e4Smiod  * In one top-to-bottom pass over the topologically sorted symbols
432*3d8817e4Smiod  * propagate:
433*3d8817e4Smiod  *      cg.print_flag as the union of parents' print_flags
434*3d8817e4Smiod  *      propfraction as the sum of fractional parents' propfractions
435*3d8817e4Smiod  * and while we're here, sum time for functions.
436*3d8817e4Smiod  */
437*3d8817e4Smiod static void
propagate_flags(Sym ** symbols)438*3d8817e4Smiod propagate_flags (Sym **symbols)
439*3d8817e4Smiod {
440*3d8817e4Smiod   int index;
441*3d8817e4Smiod   Sym *old_head, *child;
442*3d8817e4Smiod 
443*3d8817e4Smiod   old_head = 0;
444*3d8817e4Smiod   for (index = symtab.len - 1; index >= 0; --index)
445*3d8817e4Smiod     {
446*3d8817e4Smiod       child = symbols[index];
447*3d8817e4Smiod       /*
448*3d8817e4Smiod        * If we haven't done this function or cycle, inherit things
449*3d8817e4Smiod        * from parent.  This way, we are linear in the number of arcs
450*3d8817e4Smiod        * since we do all members of a cycle (and the cycle itself)
451*3d8817e4Smiod        * as we hit the first member of the cycle.
452*3d8817e4Smiod        */
453*3d8817e4Smiod       if (child->cg.cyc.head != old_head)
454*3d8817e4Smiod 	{
455*3d8817e4Smiod 	  old_head = child->cg.cyc.head;
456*3d8817e4Smiod 	  inherit_flags (child);
457*3d8817e4Smiod 	}
458*3d8817e4Smiod       DBG (PROPDEBUG,
459*3d8817e4Smiod 	   printf ("[prop_flags] ");
460*3d8817e4Smiod 	   print_name (child);
461*3d8817e4Smiod 	   printf ("inherits print-flag %d and prop-fract %f\n",
462*3d8817e4Smiod 		   child->cg.print_flag, child->cg.prop.fract));
463*3d8817e4Smiod       if (!child->cg.print_flag)
464*3d8817e4Smiod 	{
465*3d8817e4Smiod 	  /*
466*3d8817e4Smiod 	   * Printflag is off. It gets turned on by being in the
467*3d8817e4Smiod 	   * INCL_GRAPH table, or there being an empty INCL_GRAPH
468*3d8817e4Smiod 	   * table and not being in the EXCL_GRAPH table.
469*3d8817e4Smiod 	   */
470*3d8817e4Smiod 	  if (sym_lookup (&syms[INCL_GRAPH], child->addr)
471*3d8817e4Smiod 	      || (syms[INCL_GRAPH].len == 0
472*3d8817e4Smiod 		  && !sym_lookup (&syms[EXCL_GRAPH], child->addr)))
473*3d8817e4Smiod 	    {
474*3d8817e4Smiod 	      child->cg.print_flag = TRUE;
475*3d8817e4Smiod 	    }
476*3d8817e4Smiod 	}
477*3d8817e4Smiod       else
478*3d8817e4Smiod 	{
479*3d8817e4Smiod 	  /*
480*3d8817e4Smiod 	   * This function has printing parents: maybe someone wants
481*3d8817e4Smiod 	   * to shut it up by putting it in the EXCL_GRAPH table.
482*3d8817e4Smiod 	   * (But favor INCL_GRAPH over EXCL_GRAPH.)
483*3d8817e4Smiod 	   */
484*3d8817e4Smiod 	  if (!sym_lookup (&syms[INCL_GRAPH], child->addr)
485*3d8817e4Smiod 	      && sym_lookup (&syms[EXCL_GRAPH], child->addr))
486*3d8817e4Smiod 	    {
487*3d8817e4Smiod 	      child->cg.print_flag = FALSE;
488*3d8817e4Smiod 	    }
489*3d8817e4Smiod 	}
490*3d8817e4Smiod       if (child->cg.prop.fract == 0.0)
491*3d8817e4Smiod 	{
492*3d8817e4Smiod 	  /*
493*3d8817e4Smiod 	   * No parents to pass time to.  Collect time from children
494*3d8817e4Smiod 	   * if its in the INCL_TIME table, or there is an empty
495*3d8817e4Smiod 	   * INCL_TIME table and its not in the EXCL_TIME table.
496*3d8817e4Smiod 	   */
497*3d8817e4Smiod 	  if (sym_lookup (&syms[INCL_TIME], child->addr)
498*3d8817e4Smiod 	      || (syms[INCL_TIME].len == 0
499*3d8817e4Smiod 		  && !sym_lookup (&syms[EXCL_TIME], child->addr)))
500*3d8817e4Smiod 	    {
501*3d8817e4Smiod 	      child->cg.prop.fract = 1.0;
502*3d8817e4Smiod 	    }
503*3d8817e4Smiod 	}
504*3d8817e4Smiod       else
505*3d8817e4Smiod 	{
506*3d8817e4Smiod 	  /*
507*3d8817e4Smiod 	   * It has parents to pass time to, but maybe someone wants
508*3d8817e4Smiod 	   * to shut it up by puttting it in the EXCL_TIME table.
509*3d8817e4Smiod 	   * (But favor being in INCL_TIME tabe over being in
510*3d8817e4Smiod 	   * EXCL_TIME table.)
511*3d8817e4Smiod 	   */
512*3d8817e4Smiod 	  if (!sym_lookup (&syms[INCL_TIME], child->addr)
513*3d8817e4Smiod 	      && sym_lookup (&syms[EXCL_TIME], child->addr))
514*3d8817e4Smiod 	    {
515*3d8817e4Smiod 	      child->cg.prop.fract = 0.0;
516*3d8817e4Smiod 	    }
517*3d8817e4Smiod 	}
518*3d8817e4Smiod       child->cg.prop.self = child->hist.time * child->cg.prop.fract;
519*3d8817e4Smiod       print_time += child->cg.prop.self;
520*3d8817e4Smiod       DBG (PROPDEBUG,
521*3d8817e4Smiod 	   printf ("[prop_flags] ");
522*3d8817e4Smiod 	   print_name (child);
523*3d8817e4Smiod 	   printf (" ends up with printflag %d and prop-fract %f\n",
524*3d8817e4Smiod 		   child->cg.print_flag, child->cg.prop.fract);
525*3d8817e4Smiod 	   printf ("[prop_flags] time %f propself %f print_time %f\n",
526*3d8817e4Smiod 		   child->hist.time, child->cg.prop.self, print_time));
527*3d8817e4Smiod     }
528*3d8817e4Smiod }
529*3d8817e4Smiod 
530*3d8817e4Smiod 
531*3d8817e4Smiod /*
532*3d8817e4Smiod  * Compare by decreasing propagated time.  If times are equal, but one
533*3d8817e4Smiod  * is a cycle header, say that's first (e.g. less, i.e. -1).  If one's
534*3d8817e4Smiod  * name doesn't have an underscore and the other does, say that one is
535*3d8817e4Smiod  * first.  All else being equal, compare by names.
536*3d8817e4Smiod  */
537*3d8817e4Smiod static int
cmp_total(const PTR lp,const PTR rp)538*3d8817e4Smiod cmp_total (const PTR lp, const PTR rp)
539*3d8817e4Smiod {
540*3d8817e4Smiod   const Sym *left = *(const Sym **) lp;
541*3d8817e4Smiod   const Sym *right = *(const Sym **) rp;
542*3d8817e4Smiod   double diff;
543*3d8817e4Smiod 
544*3d8817e4Smiod   diff = (left->cg.prop.self + left->cg.prop.child)
545*3d8817e4Smiod     - (right->cg.prop.self + right->cg.prop.child);
546*3d8817e4Smiod   if (diff < 0.0)
547*3d8817e4Smiod     {
548*3d8817e4Smiod       return 1;
549*3d8817e4Smiod     }
550*3d8817e4Smiod   if (diff > 0.0)
551*3d8817e4Smiod     {
552*3d8817e4Smiod       return -1;
553*3d8817e4Smiod     }
554*3d8817e4Smiod   if (!left->name && left->cg.cyc.num != 0)
555*3d8817e4Smiod     {
556*3d8817e4Smiod       return -1;
557*3d8817e4Smiod     }
558*3d8817e4Smiod   if (!right->name && right->cg.cyc.num != 0)
559*3d8817e4Smiod     {
560*3d8817e4Smiod       return 1;
561*3d8817e4Smiod     }
562*3d8817e4Smiod   if (!left->name)
563*3d8817e4Smiod     {
564*3d8817e4Smiod       return -1;
565*3d8817e4Smiod     }
566*3d8817e4Smiod   if (!right->name)
567*3d8817e4Smiod     {
568*3d8817e4Smiod       return 1;
569*3d8817e4Smiod     }
570*3d8817e4Smiod   if (left->name[0] != '_' && right->name[0] == '_')
571*3d8817e4Smiod     {
572*3d8817e4Smiod       return -1;
573*3d8817e4Smiod     }
574*3d8817e4Smiod   if (left->name[0] == '_' && right->name[0] != '_')
575*3d8817e4Smiod     {
576*3d8817e4Smiod       return 1;
577*3d8817e4Smiod     }
578*3d8817e4Smiod   if (left->ncalls > right->ncalls)
579*3d8817e4Smiod     {
580*3d8817e4Smiod       return -1;
581*3d8817e4Smiod     }
582*3d8817e4Smiod   if (left->ncalls < right->ncalls)
583*3d8817e4Smiod     {
584*3d8817e4Smiod       return 1;
585*3d8817e4Smiod     }
586*3d8817e4Smiod   return strcmp (left->name, right->name);
587*3d8817e4Smiod }
588*3d8817e4Smiod 
589*3d8817e4Smiod 
590*3d8817e4Smiod /*
591*3d8817e4Smiod  * Topologically sort the graph (collapsing cycles), and propagates
592*3d8817e4Smiod  * time bottom up and flags top down.
593*3d8817e4Smiod  */
594*3d8817e4Smiod Sym **
cg_assemble()595*3d8817e4Smiod cg_assemble ()
596*3d8817e4Smiod {
597*3d8817e4Smiod   Sym *parent, **time_sorted_syms, **top_sorted_syms;
598*3d8817e4Smiod   unsigned int index;
599*3d8817e4Smiod   Arc *arc;
600*3d8817e4Smiod 
601*3d8817e4Smiod   /*
602*3d8817e4Smiod    * initialize various things:
603*3d8817e4Smiod    *      zero out child times.
604*3d8817e4Smiod    *      count self-recursive calls.
605*3d8817e4Smiod    *      indicate that nothing is on cycles.
606*3d8817e4Smiod    */
607*3d8817e4Smiod   for (parent = symtab.base; parent < symtab.limit; parent++)
608*3d8817e4Smiod     {
609*3d8817e4Smiod       parent->cg.child_time = 0.0;
610*3d8817e4Smiod       arc = arc_lookup (parent, parent);
611*3d8817e4Smiod       if (arc && parent == arc->child)
612*3d8817e4Smiod 	{
613*3d8817e4Smiod 	  parent->ncalls -= arc->count;
614*3d8817e4Smiod 	  parent->cg.self_calls = arc->count;
615*3d8817e4Smiod 	}
616*3d8817e4Smiod       else
617*3d8817e4Smiod 	{
618*3d8817e4Smiod 	  parent->cg.self_calls = 0;
619*3d8817e4Smiod 	}
620*3d8817e4Smiod       parent->cg.prop.fract = 0.0;
621*3d8817e4Smiod       parent->cg.prop.self = 0.0;
622*3d8817e4Smiod       parent->cg.prop.child = 0.0;
623*3d8817e4Smiod       parent->cg.print_flag = FALSE;
624*3d8817e4Smiod       parent->cg.top_order = DFN_NAN;
625*3d8817e4Smiod       parent->cg.cyc.num = 0;
626*3d8817e4Smiod       parent->cg.cyc.head = parent;
627*3d8817e4Smiod       parent->cg.cyc.next = 0;
628*3d8817e4Smiod       if (ignore_direct_calls)
629*3d8817e4Smiod 	{
630*3d8817e4Smiod 	  find_call (parent, parent->addr, (parent + 1)->addr);
631*3d8817e4Smiod 	}
632*3d8817e4Smiod     }
633*3d8817e4Smiod   /*
634*3d8817e4Smiod    * Topologically order things.  If any node is unnumbered, number
635*3d8817e4Smiod    * it and any of its descendents.
636*3d8817e4Smiod    */
637*3d8817e4Smiod   for (parent = symtab.base; parent < symtab.limit; parent++)
638*3d8817e4Smiod     {
639*3d8817e4Smiod       if (parent->cg.top_order == DFN_NAN)
640*3d8817e4Smiod 	{
641*3d8817e4Smiod 	  cg_dfn (parent);
642*3d8817e4Smiod 	}
643*3d8817e4Smiod     }
644*3d8817e4Smiod 
645*3d8817e4Smiod   /* link together nodes on the same cycle: */
646*3d8817e4Smiod   cycle_link ();
647*3d8817e4Smiod 
648*3d8817e4Smiod   /* sort the symbol table in reverse topological order: */
649*3d8817e4Smiod   top_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
650*3d8817e4Smiod   for (index = 0; index < symtab.len; ++index)
651*3d8817e4Smiod     {
652*3d8817e4Smiod       top_sorted_syms[index] = &symtab.base[index];
653*3d8817e4Smiod     }
654*3d8817e4Smiod   qsort (top_sorted_syms, symtab.len, sizeof (Sym *), cmp_topo);
655*3d8817e4Smiod   DBG (DFNDEBUG,
656*3d8817e4Smiod        printf ("[cg_assemble] topological sort listing\n");
657*3d8817e4Smiod        for (index = 0; index < symtab.len; ++index)
658*3d8817e4Smiod        {
659*3d8817e4Smiod        printf ("[cg_assemble] ");
660*3d8817e4Smiod        printf ("%d:", top_sorted_syms[index]->cg.top_order);
661*3d8817e4Smiod        print_name (top_sorted_syms[index]);
662*3d8817e4Smiod        printf ("\n");
663*3d8817e4Smiod        }
664*3d8817e4Smiod   );
665*3d8817e4Smiod   /*
666*3d8817e4Smiod    * Starting from the topological top, propagate print flags to
667*3d8817e4Smiod    * children.  also, calculate propagation fractions.  this happens
668*3d8817e4Smiod    * before time propagation since time propagation uses the
669*3d8817e4Smiod    * fractions.
670*3d8817e4Smiod    */
671*3d8817e4Smiod   propagate_flags (top_sorted_syms);
672*3d8817e4Smiod 
673*3d8817e4Smiod   /*
674*3d8817e4Smiod    * Starting from the topological bottom, propogate children times
675*3d8817e4Smiod    * up to parents.
676*3d8817e4Smiod    */
677*3d8817e4Smiod   cycle_time ();
678*3d8817e4Smiod   for (index = 0; index < symtab.len; ++index)
679*3d8817e4Smiod     {
680*3d8817e4Smiod       propagate_time (top_sorted_syms[index]);
681*3d8817e4Smiod     }
682*3d8817e4Smiod 
683*3d8817e4Smiod   free (top_sorted_syms);
684*3d8817e4Smiod 
685*3d8817e4Smiod   /*
686*3d8817e4Smiod    * Now, sort by CG.PROP.SELF + CG.PROP.CHILD.  Sorting both the regular
687*3d8817e4Smiod    * function names and cycle headers.
688*3d8817e4Smiod    */
689*3d8817e4Smiod   time_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
690*3d8817e4Smiod   for (index = 0; index < symtab.len; index++)
691*3d8817e4Smiod     {
692*3d8817e4Smiod       time_sorted_syms[index] = &symtab.base[index];
693*3d8817e4Smiod     }
694*3d8817e4Smiod   for (index = 1; index <= num_cycles; index++)
695*3d8817e4Smiod     {
696*3d8817e4Smiod       time_sorted_syms[symtab.len + index - 1] = &cycle_header[index];
697*3d8817e4Smiod     }
698*3d8817e4Smiod   qsort (time_sorted_syms, symtab.len + num_cycles, sizeof (Sym *),
699*3d8817e4Smiod 	 cmp_total);
700*3d8817e4Smiod   for (index = 0; index < symtab.len + num_cycles; index++)
701*3d8817e4Smiod     {
702*3d8817e4Smiod       time_sorted_syms[index]->cg.index = index + 1;
703*3d8817e4Smiod     }
704*3d8817e4Smiod   return time_sorted_syms;
705*3d8817e4Smiod }
706