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