1*3d8817e4Smiod /* cg_print.c - Print routines for displaying call graphs.
2*3d8817e4Smiod
3*3d8817e4Smiod Copyright 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
4*3d8817e4Smiod
5*3d8817e4Smiod This file is part of GNU Binutils.
6*3d8817e4Smiod
7*3d8817e4Smiod This program is free software; you can redistribute it and/or modify
8*3d8817e4Smiod it under the terms of the GNU General Public License as published by
9*3d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
10*3d8817e4Smiod (at your option) any later version.
11*3d8817e4Smiod
12*3d8817e4Smiod This program is distributed in the hope that it will be useful,
13*3d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
14*3d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*3d8817e4Smiod GNU General Public License for more details.
16*3d8817e4Smiod
17*3d8817e4Smiod You should have received a copy of the GNU General Public License
18*3d8817e4Smiod along with this program; if not, write to the Free Software
19*3d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20*3d8817e4Smiod 02110-1301, USA. */
21*3d8817e4Smiod
22*3d8817e4Smiod #include "libiberty.h"
23*3d8817e4Smiod #include "gprof.h"
24*3d8817e4Smiod #include "search_list.h"
25*3d8817e4Smiod #include "source.h"
26*3d8817e4Smiod #include "symtab.h"
27*3d8817e4Smiod #include "cg_arcs.h"
28*3d8817e4Smiod #include "cg_print.h"
29*3d8817e4Smiod #include "hist.h"
30*3d8817e4Smiod #include "utils.h"
31*3d8817e4Smiod #include "corefile.h"
32*3d8817e4Smiod
33*3d8817e4Smiod /* Return value of comparison functions used to sort tables. */
34*3d8817e4Smiod #define LESSTHAN -1
35*3d8817e4Smiod #define EQUALTO 0
36*3d8817e4Smiod #define GREATERTHAN 1
37*3d8817e4Smiod
38*3d8817e4Smiod static void print_header (void);
39*3d8817e4Smiod static void print_cycle (Sym *);
40*3d8817e4Smiod static int cmp_member (Sym *, Sym *);
41*3d8817e4Smiod static void sort_members (Sym *);
42*3d8817e4Smiod static void print_members (Sym *);
43*3d8817e4Smiod static int cmp_arc (Arc *, Arc *);
44*3d8817e4Smiod static void sort_parents (Sym *);
45*3d8817e4Smiod static void print_parents (Sym *);
46*3d8817e4Smiod static void sort_children (Sym *);
47*3d8817e4Smiod static void print_children (Sym *);
48*3d8817e4Smiod static void print_line (Sym *);
49*3d8817e4Smiod static int cmp_name (const PTR, const PTR);
50*3d8817e4Smiod static int cmp_arc_count (const PTR, const PTR);
51*3d8817e4Smiod static int cmp_fun_nuses (const PTR, const PTR);
52*3d8817e4Smiod static void order_and_dump_functions_by_arcs
53*3d8817e4Smiod (Arc **, unsigned long, int, Arc **, unsigned long *);
54*3d8817e4Smiod
55*3d8817e4Smiod /* Declarations of automatically generated functions to output blurbs. */
56*3d8817e4Smiod extern void bsd_callg_blurb (FILE * fp);
57*3d8817e4Smiod extern void fsf_callg_blurb (FILE * fp);
58*3d8817e4Smiod
59*3d8817e4Smiod double print_time = 0.0;
60*3d8817e4Smiod
61*3d8817e4Smiod
62*3d8817e4Smiod static void
print_header()63*3d8817e4Smiod print_header ()
64*3d8817e4Smiod {
65*3d8817e4Smiod if (first_output)
66*3d8817e4Smiod first_output = FALSE;
67*3d8817e4Smiod else
68*3d8817e4Smiod printf ("\f\n");
69*3d8817e4Smiod
70*3d8817e4Smiod if (!bsd_style_output)
71*3d8817e4Smiod {
72*3d8817e4Smiod if (print_descriptions)
73*3d8817e4Smiod printf (_("\t\t Call graph (explanation follows)\n\n"));
74*3d8817e4Smiod else
75*3d8817e4Smiod printf (_("\t\t\tCall graph\n\n"));
76*3d8817e4Smiod }
77*3d8817e4Smiod
78*3d8817e4Smiod printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
79*3d8817e4Smiod (long) hist_scale * sizeof (UNIT));
80*3d8817e4Smiod
81*3d8817e4Smiod if (print_time > 0.0)
82*3d8817e4Smiod printf (_(" for %.2f%% of %.2f seconds\n\n"),
83*3d8817e4Smiod 100.0 / print_time, print_time / hz);
84*3d8817e4Smiod else
85*3d8817e4Smiod {
86*3d8817e4Smiod printf (_(" no time propagated\n\n"));
87*3d8817e4Smiod
88*3d8817e4Smiod /* This doesn't hurt, since all the numerators will be 0.0. */
89*3d8817e4Smiod print_time = 1.0;
90*3d8817e4Smiod }
91*3d8817e4Smiod
92*3d8817e4Smiod if (bsd_style_output)
93*3d8817e4Smiod {
94*3d8817e4Smiod printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
95*3d8817e4Smiod "", "", "", "", _("called"), _("total"), _("parents"));
96*3d8817e4Smiod printf ("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
97*3d8817e4Smiod _("index"), _("%time"), _("self"), _("descendants"),
98*3d8817e4Smiod _("called"), _("self"), _("name"), _("index"));
99*3d8817e4Smiod printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
100*3d8817e4Smiod "", "", "", "", _("called"), _("total"), _("children"));
101*3d8817e4Smiod printf ("\n");
102*3d8817e4Smiod }
103*3d8817e4Smiod else
104*3d8817e4Smiod {
105*3d8817e4Smiod printf (_("index %% time self children called name\n"));
106*3d8817e4Smiod }
107*3d8817e4Smiod }
108*3d8817e4Smiod
109*3d8817e4Smiod /* Print a cycle header. */
110*3d8817e4Smiod
111*3d8817e4Smiod static void
print_cycle(Sym * cyc)112*3d8817e4Smiod print_cycle (Sym *cyc)
113*3d8817e4Smiod {
114*3d8817e4Smiod char buf[BUFSIZ];
115*3d8817e4Smiod
116*3d8817e4Smiod sprintf (buf, "[%d]", cyc->cg.index);
117*3d8817e4Smiod printf (bsd_style_output
118*3d8817e4Smiod ? "%-6.6s %5.1f %7.2f %11.2f %7lu"
119*3d8817e4Smiod : "%-6.6s %5.1f %7.2f %7.2f %7lu", buf,
120*3d8817e4Smiod 100 * (cyc->cg.prop.self + cyc->cg.prop.child) / print_time,
121*3d8817e4Smiod cyc->cg.prop.self / hz, cyc->cg.prop.child / hz, cyc->ncalls);
122*3d8817e4Smiod
123*3d8817e4Smiod if (cyc->cg.self_calls != 0)
124*3d8817e4Smiod printf ("+%-7lu", cyc->cg.self_calls);
125*3d8817e4Smiod else
126*3d8817e4Smiod printf (" %7.7s", "");
127*3d8817e4Smiod
128*3d8817e4Smiod printf (_(" <cycle %d as a whole> [%d]\n"), cyc->cg.cyc.num, cyc->cg.index);
129*3d8817e4Smiod }
130*3d8817e4Smiod
131*3d8817e4Smiod /* Compare LEFT and RIGHT membmer. Major comparison key is
132*3d8817e4Smiod CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS. */
133*3d8817e4Smiod
134*3d8817e4Smiod static int
cmp_member(Sym * left,Sym * right)135*3d8817e4Smiod cmp_member (Sym *left, Sym *right)
136*3d8817e4Smiod {
137*3d8817e4Smiod double left_time = left->cg.prop.self + left->cg.prop.child;
138*3d8817e4Smiod double right_time = right->cg.prop.self + right->cg.prop.child;
139*3d8817e4Smiod unsigned long left_calls = left->ncalls + left->cg.self_calls;
140*3d8817e4Smiod unsigned long right_calls = right->ncalls + right->cg.self_calls;
141*3d8817e4Smiod
142*3d8817e4Smiod if (left_time > right_time)
143*3d8817e4Smiod return GREATERTHAN;
144*3d8817e4Smiod
145*3d8817e4Smiod if (left_time < right_time)
146*3d8817e4Smiod return LESSTHAN;
147*3d8817e4Smiod
148*3d8817e4Smiod if (left_calls > right_calls)
149*3d8817e4Smiod return GREATERTHAN;
150*3d8817e4Smiod
151*3d8817e4Smiod if (left_calls < right_calls)
152*3d8817e4Smiod return LESSTHAN;
153*3d8817e4Smiod
154*3d8817e4Smiod return EQUALTO;
155*3d8817e4Smiod }
156*3d8817e4Smiod
157*3d8817e4Smiod /* Sort members of a cycle. */
158*3d8817e4Smiod
159*3d8817e4Smiod static void
sort_members(Sym * cyc)160*3d8817e4Smiod sort_members (Sym *cyc)
161*3d8817e4Smiod {
162*3d8817e4Smiod Sym *todo, *doing, *prev;
163*3d8817e4Smiod
164*3d8817e4Smiod /* Detach cycle members from cyclehead,
165*3d8817e4Smiod and insertion sort them back on. */
166*3d8817e4Smiod todo = cyc->cg.cyc.next;
167*3d8817e4Smiod cyc->cg.cyc.next = 0;
168*3d8817e4Smiod
169*3d8817e4Smiod for (doing = todo; doing && doing->cg.cyc.next; doing = todo)
170*3d8817e4Smiod {
171*3d8817e4Smiod todo = doing->cg.cyc.next;
172*3d8817e4Smiod
173*3d8817e4Smiod for (prev = cyc; prev->cg.cyc.next; prev = prev->cg.cyc.next)
174*3d8817e4Smiod {
175*3d8817e4Smiod if (cmp_member (doing, prev->cg.cyc.next) == GREATERTHAN)
176*3d8817e4Smiod break;
177*3d8817e4Smiod }
178*3d8817e4Smiod
179*3d8817e4Smiod doing->cg.cyc.next = prev->cg.cyc.next;
180*3d8817e4Smiod prev->cg.cyc.next = doing;
181*3d8817e4Smiod }
182*3d8817e4Smiod }
183*3d8817e4Smiod
184*3d8817e4Smiod /* Print the members of a cycle. */
185*3d8817e4Smiod
186*3d8817e4Smiod static void
print_members(Sym * cyc)187*3d8817e4Smiod print_members (Sym *cyc)
188*3d8817e4Smiod {
189*3d8817e4Smiod Sym *member;
190*3d8817e4Smiod
191*3d8817e4Smiod sort_members (cyc);
192*3d8817e4Smiod
193*3d8817e4Smiod for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next)
194*3d8817e4Smiod {
195*3d8817e4Smiod printf (bsd_style_output
196*3d8817e4Smiod ? "%6.6s %5.5s %7.2f %11.2f %7lu"
197*3d8817e4Smiod : "%6.6s %5.5s %7.2f %7.2f %7lu",
198*3d8817e4Smiod "", "", member->cg.prop.self / hz, member->cg.prop.child / hz,
199*3d8817e4Smiod member->ncalls);
200*3d8817e4Smiod
201*3d8817e4Smiod if (member->cg.self_calls != 0)
202*3d8817e4Smiod printf ("+%-7lu", member->cg.self_calls);
203*3d8817e4Smiod else
204*3d8817e4Smiod printf (" %7.7s", "");
205*3d8817e4Smiod
206*3d8817e4Smiod printf (" ");
207*3d8817e4Smiod print_name (member);
208*3d8817e4Smiod printf ("\n");
209*3d8817e4Smiod }
210*3d8817e4Smiod }
211*3d8817e4Smiod
212*3d8817e4Smiod /* Compare two arcs to/from the same child/parent.
213*3d8817e4Smiod - if one arc is a self arc, it's least.
214*3d8817e4Smiod - if one arc is within a cycle, it's less than.
215*3d8817e4Smiod - if both arcs are within a cycle, compare arc counts.
216*3d8817e4Smiod - if neither arc is within a cycle, compare with
217*3d8817e4Smiod time + child_time as major key
218*3d8817e4Smiod arc count as minor key. */
219*3d8817e4Smiod
220*3d8817e4Smiod static int
cmp_arc(Arc * left,Arc * right)221*3d8817e4Smiod cmp_arc (Arc *left, Arc *right)
222*3d8817e4Smiod {
223*3d8817e4Smiod Sym *left_parent = left->parent;
224*3d8817e4Smiod Sym *left_child = left->child;
225*3d8817e4Smiod Sym *right_parent = right->parent;
226*3d8817e4Smiod Sym *right_child = right->child;
227*3d8817e4Smiod double left_time, right_time;
228*3d8817e4Smiod
229*3d8817e4Smiod DBG (TIMEDEBUG,
230*3d8817e4Smiod printf ("[cmp_arc] ");
231*3d8817e4Smiod print_name (left_parent);
232*3d8817e4Smiod printf (" calls ");
233*3d8817e4Smiod print_name (left_child);
234*3d8817e4Smiod printf (" %f + %f %lu/%lu\n", left->time, left->child_time,
235*3d8817e4Smiod left->count, left_child->ncalls);
236*3d8817e4Smiod printf ("[cmp_arc] ");
237*3d8817e4Smiod print_name (right_parent);
238*3d8817e4Smiod printf (" calls ");
239*3d8817e4Smiod print_name (right_child);
240*3d8817e4Smiod printf (" %f + %f %lu/%lu\n", right->time, right->child_time,
241*3d8817e4Smiod right->count, right_child->ncalls);
242*3d8817e4Smiod printf ("\n");
243*3d8817e4Smiod );
244*3d8817e4Smiod
245*3d8817e4Smiod if (left_parent == left_child)
246*3d8817e4Smiod return LESSTHAN; /* Left is a self call. */
247*3d8817e4Smiod
248*3d8817e4Smiod if (right_parent == right_child)
249*3d8817e4Smiod return GREATERTHAN; /* Right is a self call. */
250*3d8817e4Smiod
251*3d8817e4Smiod if (left_parent->cg.cyc.num != 0 && left_child->cg.cyc.num != 0
252*3d8817e4Smiod && left_parent->cg.cyc.num == left_child->cg.cyc.num)
253*3d8817e4Smiod {
254*3d8817e4Smiod /* Left is a call within a cycle. */
255*3d8817e4Smiod if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
256*3d8817e4Smiod && right_parent->cg.cyc.num == right_child->cg.cyc.num)
257*3d8817e4Smiod {
258*3d8817e4Smiod /* Right is a call within the cycle, too. */
259*3d8817e4Smiod if (left->count < right->count)
260*3d8817e4Smiod return LESSTHAN;
261*3d8817e4Smiod
262*3d8817e4Smiod if (left->count > right->count)
263*3d8817e4Smiod return GREATERTHAN;
264*3d8817e4Smiod
265*3d8817e4Smiod return EQUALTO;
266*3d8817e4Smiod }
267*3d8817e4Smiod else
268*3d8817e4Smiod {
269*3d8817e4Smiod /* Right isn't a call within the cycle. */
270*3d8817e4Smiod return LESSTHAN;
271*3d8817e4Smiod }
272*3d8817e4Smiod }
273*3d8817e4Smiod else
274*3d8817e4Smiod {
275*3d8817e4Smiod /* Left isn't a call within a cycle. */
276*3d8817e4Smiod if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
277*3d8817e4Smiod && right_parent->cg.cyc.num == right_child->cg.cyc.num)
278*3d8817e4Smiod {
279*3d8817e4Smiod /* Right is a call within a cycle. */
280*3d8817e4Smiod return GREATERTHAN;
281*3d8817e4Smiod }
282*3d8817e4Smiod else
283*3d8817e4Smiod {
284*3d8817e4Smiod /* Neither is a call within a cycle. */
285*3d8817e4Smiod left_time = left->time + left->child_time;
286*3d8817e4Smiod right_time = right->time + right->child_time;
287*3d8817e4Smiod
288*3d8817e4Smiod if (left_time < right_time)
289*3d8817e4Smiod return LESSTHAN;
290*3d8817e4Smiod
291*3d8817e4Smiod if (left_time > right_time)
292*3d8817e4Smiod return GREATERTHAN;
293*3d8817e4Smiod
294*3d8817e4Smiod if (left->count < right->count)
295*3d8817e4Smiod return LESSTHAN;
296*3d8817e4Smiod
297*3d8817e4Smiod if (left->count > right->count)
298*3d8817e4Smiod return GREATERTHAN;
299*3d8817e4Smiod
300*3d8817e4Smiod return EQUALTO;
301*3d8817e4Smiod }
302*3d8817e4Smiod }
303*3d8817e4Smiod }
304*3d8817e4Smiod
305*3d8817e4Smiod
306*3d8817e4Smiod static void
sort_parents(Sym * child)307*3d8817e4Smiod sort_parents (Sym * child)
308*3d8817e4Smiod {
309*3d8817e4Smiod Arc *arc, *detached, sorted, *prev;
310*3d8817e4Smiod
311*3d8817e4Smiod /* Unlink parents from child, then insertion sort back on to
312*3d8817e4Smiod sorted's parents.
313*3d8817e4Smiod *arc the arc you have detached and are inserting.
314*3d8817e4Smiod *detached the rest of the arcs to be sorted.
315*3d8817e4Smiod sorted arc list onto which you insertion sort.
316*3d8817e4Smiod *prev arc before the arc you are comparing. */
317*3d8817e4Smiod sorted.next_parent = 0;
318*3d8817e4Smiod
319*3d8817e4Smiod for (arc = child->cg.parents; arc; arc = detached)
320*3d8817e4Smiod {
321*3d8817e4Smiod detached = arc->next_parent;
322*3d8817e4Smiod
323*3d8817e4Smiod /* Consider *arc as disconnected; insert it into sorted. */
324*3d8817e4Smiod for (prev = &sorted; prev->next_parent; prev = prev->next_parent)
325*3d8817e4Smiod {
326*3d8817e4Smiod if (cmp_arc (arc, prev->next_parent) != GREATERTHAN)
327*3d8817e4Smiod break;
328*3d8817e4Smiod }
329*3d8817e4Smiod
330*3d8817e4Smiod arc->next_parent = prev->next_parent;
331*3d8817e4Smiod prev->next_parent = arc;
332*3d8817e4Smiod }
333*3d8817e4Smiod
334*3d8817e4Smiod /* Reattach sorted arcs to child. */
335*3d8817e4Smiod child->cg.parents = sorted.next_parent;
336*3d8817e4Smiod }
337*3d8817e4Smiod
338*3d8817e4Smiod
339*3d8817e4Smiod static void
print_parents(Sym * child)340*3d8817e4Smiod print_parents (Sym *child)
341*3d8817e4Smiod {
342*3d8817e4Smiod Sym *parent;
343*3d8817e4Smiod Arc *arc;
344*3d8817e4Smiod Sym *cycle_head;
345*3d8817e4Smiod
346*3d8817e4Smiod if (child->cg.cyc.head != 0)
347*3d8817e4Smiod cycle_head = child->cg.cyc.head;
348*3d8817e4Smiod else
349*3d8817e4Smiod cycle_head = child;
350*3d8817e4Smiod
351*3d8817e4Smiod if (!child->cg.parents)
352*3d8817e4Smiod {
353*3d8817e4Smiod printf (bsd_style_output
354*3d8817e4Smiod ? _("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n")
355*3d8817e4Smiod : _("%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n"),
356*3d8817e4Smiod "", "", "", "", "", "");
357*3d8817e4Smiod return;
358*3d8817e4Smiod }
359*3d8817e4Smiod
360*3d8817e4Smiod sort_parents (child);
361*3d8817e4Smiod
362*3d8817e4Smiod for (arc = child->cg.parents; arc; arc = arc->next_parent)
363*3d8817e4Smiod {
364*3d8817e4Smiod parent = arc->parent;
365*3d8817e4Smiod if (child == parent || (child->cg.cyc.num != 0
366*3d8817e4Smiod && parent->cg.cyc.num == child->cg.cyc.num))
367*3d8817e4Smiod {
368*3d8817e4Smiod /* Selfcall or call among siblings. */
369*3d8817e4Smiod printf (bsd_style_output
370*3d8817e4Smiod ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
371*3d8817e4Smiod : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
372*3d8817e4Smiod "", "", "", "",
373*3d8817e4Smiod arc->count, "");
374*3d8817e4Smiod print_name (parent);
375*3d8817e4Smiod printf ("\n");
376*3d8817e4Smiod }
377*3d8817e4Smiod else
378*3d8817e4Smiod {
379*3d8817e4Smiod /* Regular parent of child. */
380*3d8817e4Smiod printf (bsd_style_output
381*3d8817e4Smiod ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
382*3d8817e4Smiod : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
383*3d8817e4Smiod "", "",
384*3d8817e4Smiod arc->time / hz, arc->child_time / hz,
385*3d8817e4Smiod arc->count, cycle_head->ncalls);
386*3d8817e4Smiod print_name (parent);
387*3d8817e4Smiod printf ("\n");
388*3d8817e4Smiod }
389*3d8817e4Smiod }
390*3d8817e4Smiod }
391*3d8817e4Smiod
392*3d8817e4Smiod
393*3d8817e4Smiod static void
sort_children(Sym * parent)394*3d8817e4Smiod sort_children (Sym *parent)
395*3d8817e4Smiod {
396*3d8817e4Smiod Arc *arc, *detached, sorted, *prev;
397*3d8817e4Smiod
398*3d8817e4Smiod /* Unlink children from parent, then insertion sort back on to
399*3d8817e4Smiod sorted's children.
400*3d8817e4Smiod *arc the arc you have detached and are inserting.
401*3d8817e4Smiod *detached the rest of the arcs to be sorted.
402*3d8817e4Smiod sorted arc list onto which you insertion sort.
403*3d8817e4Smiod *prev arc before the arc you are comparing. */
404*3d8817e4Smiod sorted.next_child = 0;
405*3d8817e4Smiod
406*3d8817e4Smiod for (arc = parent->cg.children; arc; arc = detached)
407*3d8817e4Smiod {
408*3d8817e4Smiod detached = arc->next_child;
409*3d8817e4Smiod
410*3d8817e4Smiod /* Consider *arc as disconnected; insert it into sorted. */
411*3d8817e4Smiod for (prev = &sorted; prev->next_child; prev = prev->next_child)
412*3d8817e4Smiod {
413*3d8817e4Smiod if (cmp_arc (arc, prev->next_child) != LESSTHAN)
414*3d8817e4Smiod break;
415*3d8817e4Smiod }
416*3d8817e4Smiod
417*3d8817e4Smiod arc->next_child = prev->next_child;
418*3d8817e4Smiod prev->next_child = arc;
419*3d8817e4Smiod }
420*3d8817e4Smiod
421*3d8817e4Smiod /* Reattach sorted children to parent. */
422*3d8817e4Smiod parent->cg.children = sorted.next_child;
423*3d8817e4Smiod }
424*3d8817e4Smiod
425*3d8817e4Smiod
426*3d8817e4Smiod static void
print_children(Sym * parent)427*3d8817e4Smiod print_children (Sym *parent)
428*3d8817e4Smiod {
429*3d8817e4Smiod Sym *child;
430*3d8817e4Smiod Arc *arc;
431*3d8817e4Smiod
432*3d8817e4Smiod sort_children (parent);
433*3d8817e4Smiod arc = parent->cg.children;
434*3d8817e4Smiod
435*3d8817e4Smiod for (arc = parent->cg.children; arc; arc = arc->next_child)
436*3d8817e4Smiod {
437*3d8817e4Smiod child = arc->child;
438*3d8817e4Smiod if (child == parent || (child->cg.cyc.num != 0
439*3d8817e4Smiod && child->cg.cyc.num == parent->cg.cyc.num))
440*3d8817e4Smiod {
441*3d8817e4Smiod /* Self call or call to sibling. */
442*3d8817e4Smiod printf (bsd_style_output
443*3d8817e4Smiod ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
444*3d8817e4Smiod : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
445*3d8817e4Smiod "", "", "", "", arc->count, "");
446*3d8817e4Smiod print_name (child);
447*3d8817e4Smiod printf ("\n");
448*3d8817e4Smiod }
449*3d8817e4Smiod else
450*3d8817e4Smiod {
451*3d8817e4Smiod /* Regular child of parent. */
452*3d8817e4Smiod printf (bsd_style_output
453*3d8817e4Smiod ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
454*3d8817e4Smiod : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
455*3d8817e4Smiod "", "",
456*3d8817e4Smiod arc->time / hz, arc->child_time / hz,
457*3d8817e4Smiod arc->count, child->cg.cyc.head->ncalls);
458*3d8817e4Smiod print_name (child);
459*3d8817e4Smiod printf ("\n");
460*3d8817e4Smiod }
461*3d8817e4Smiod }
462*3d8817e4Smiod }
463*3d8817e4Smiod
464*3d8817e4Smiod
465*3d8817e4Smiod static void
print_line(Sym * np)466*3d8817e4Smiod print_line (Sym *np)
467*3d8817e4Smiod {
468*3d8817e4Smiod char buf[BUFSIZ];
469*3d8817e4Smiod
470*3d8817e4Smiod sprintf (buf, "[%d]", np->cg.index);
471*3d8817e4Smiod printf (bsd_style_output
472*3d8817e4Smiod ? "%-6.6s %5.1f %7.2f %11.2f"
473*3d8817e4Smiod : "%-6.6s %5.1f %7.2f %7.2f", buf,
474*3d8817e4Smiod 100 * (np->cg.prop.self + np->cg.prop.child) / print_time,
475*3d8817e4Smiod np->cg.prop.self / hz, np->cg.prop.child / hz);
476*3d8817e4Smiod
477*3d8817e4Smiod if ((np->ncalls + np->cg.self_calls) != 0)
478*3d8817e4Smiod {
479*3d8817e4Smiod printf (" %7lu", np->ncalls);
480*3d8817e4Smiod
481*3d8817e4Smiod if (np->cg.self_calls != 0)
482*3d8817e4Smiod printf ("+%-7lu ", np->cg.self_calls);
483*3d8817e4Smiod else
484*3d8817e4Smiod printf (" %7.7s ", "");
485*3d8817e4Smiod }
486*3d8817e4Smiod else
487*3d8817e4Smiod {
488*3d8817e4Smiod printf (" %7.7s %7.7s ", "", "");
489*3d8817e4Smiod }
490*3d8817e4Smiod
491*3d8817e4Smiod print_name (np);
492*3d8817e4Smiod printf ("\n");
493*3d8817e4Smiod }
494*3d8817e4Smiod
495*3d8817e4Smiod
496*3d8817e4Smiod /* Print dynamic call graph. */
497*3d8817e4Smiod
498*3d8817e4Smiod void
cg_print(Sym ** timesortsym)499*3d8817e4Smiod cg_print (Sym ** timesortsym)
500*3d8817e4Smiod {
501*3d8817e4Smiod unsigned int index;
502*3d8817e4Smiod Sym *parent;
503*3d8817e4Smiod
504*3d8817e4Smiod if (print_descriptions && bsd_style_output)
505*3d8817e4Smiod bsd_callg_blurb (stdout);
506*3d8817e4Smiod
507*3d8817e4Smiod print_header ();
508*3d8817e4Smiod
509*3d8817e4Smiod for (index = 0; index < symtab.len + num_cycles; ++index)
510*3d8817e4Smiod {
511*3d8817e4Smiod parent = timesortsym[index];
512*3d8817e4Smiod
513*3d8817e4Smiod if ((ignore_zeros && parent->ncalls == 0
514*3d8817e4Smiod && parent->cg.self_calls == 0 && parent->cg.prop.self == 0
515*3d8817e4Smiod && parent->cg.prop.child == 0)
516*3d8817e4Smiod || !parent->cg.print_flag
517*3d8817e4Smiod || (line_granularity && ! parent->is_func))
518*3d8817e4Smiod continue;
519*3d8817e4Smiod
520*3d8817e4Smiod if (!parent->name && parent->cg.cyc.num != 0)
521*3d8817e4Smiod {
522*3d8817e4Smiod /* Cycle header. */
523*3d8817e4Smiod print_cycle (parent);
524*3d8817e4Smiod print_members (parent);
525*3d8817e4Smiod }
526*3d8817e4Smiod else
527*3d8817e4Smiod {
528*3d8817e4Smiod print_parents (parent);
529*3d8817e4Smiod print_line (parent);
530*3d8817e4Smiod print_children (parent);
531*3d8817e4Smiod }
532*3d8817e4Smiod
533*3d8817e4Smiod if (bsd_style_output)
534*3d8817e4Smiod printf ("\n");
535*3d8817e4Smiod
536*3d8817e4Smiod printf ("-----------------------------------------------\n");
537*3d8817e4Smiod
538*3d8817e4Smiod if (bsd_style_output)
539*3d8817e4Smiod printf ("\n");
540*3d8817e4Smiod }
541*3d8817e4Smiod
542*3d8817e4Smiod free (timesortsym);
543*3d8817e4Smiod
544*3d8817e4Smiod if (print_descriptions && !bsd_style_output)
545*3d8817e4Smiod fsf_callg_blurb (stdout);
546*3d8817e4Smiod }
547*3d8817e4Smiod
548*3d8817e4Smiod
549*3d8817e4Smiod static int
cmp_name(const PTR left,const PTR right)550*3d8817e4Smiod cmp_name (const PTR left, const PTR right)
551*3d8817e4Smiod {
552*3d8817e4Smiod const Sym **npp1 = (const Sym **) left;
553*3d8817e4Smiod const Sym **npp2 = (const Sym **) right;
554*3d8817e4Smiod
555*3d8817e4Smiod return strcmp ((*npp1)->name, (*npp2)->name);
556*3d8817e4Smiod }
557*3d8817e4Smiod
558*3d8817e4Smiod
559*3d8817e4Smiod void
cg_print_index()560*3d8817e4Smiod cg_print_index ()
561*3d8817e4Smiod {
562*3d8817e4Smiod unsigned int index;
563*3d8817e4Smiod unsigned int nnames, todo, i, j;
564*3d8817e4Smiod int col, starting_col;
565*3d8817e4Smiod Sym **name_sorted_syms, *sym;
566*3d8817e4Smiod const char *filename;
567*3d8817e4Smiod char buf[20];
568*3d8817e4Smiod int column_width = (output_width - 1) / 3; /* Don't write in last col! */
569*3d8817e4Smiod
570*3d8817e4Smiod /* Now, sort regular function name
571*3d8817e4Smiod alphabetically to create an index. */
572*3d8817e4Smiod name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
573*3d8817e4Smiod
574*3d8817e4Smiod for (index = 0, nnames = 0; index < symtab.len; index++)
575*3d8817e4Smiod {
576*3d8817e4Smiod if (ignore_zeros && symtab.base[index].ncalls == 0
577*3d8817e4Smiod && symtab.base[index].hist.time == 0)
578*3d8817e4Smiod continue;
579*3d8817e4Smiod
580*3d8817e4Smiod name_sorted_syms[nnames++] = &symtab.base[index];
581*3d8817e4Smiod }
582*3d8817e4Smiod
583*3d8817e4Smiod qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
584*3d8817e4Smiod
585*3d8817e4Smiod for (index = 1, todo = nnames; index <= num_cycles; index++)
586*3d8817e4Smiod name_sorted_syms[todo++] = &cycle_header[index];
587*3d8817e4Smiod
588*3d8817e4Smiod printf ("\f\n");
589*3d8817e4Smiod printf (_("Index by function name\n\n"));
590*3d8817e4Smiod index = (todo + 2) / 3;
591*3d8817e4Smiod
592*3d8817e4Smiod for (i = 0; i < index; i++)
593*3d8817e4Smiod {
594*3d8817e4Smiod col = 0;
595*3d8817e4Smiod starting_col = 0;
596*3d8817e4Smiod
597*3d8817e4Smiod for (j = i; j < todo; j += index)
598*3d8817e4Smiod {
599*3d8817e4Smiod sym = name_sorted_syms[j];
600*3d8817e4Smiod
601*3d8817e4Smiod if (sym->cg.print_flag)
602*3d8817e4Smiod sprintf (buf, "[%d]", sym->cg.index);
603*3d8817e4Smiod else
604*3d8817e4Smiod sprintf (buf, "(%d)", sym->cg.index);
605*3d8817e4Smiod
606*3d8817e4Smiod if (j < nnames)
607*3d8817e4Smiod {
608*3d8817e4Smiod if (bsd_style_output)
609*3d8817e4Smiod {
610*3d8817e4Smiod printf ("%6.6s %-19.19s", buf, sym->name);
611*3d8817e4Smiod }
612*3d8817e4Smiod else
613*3d8817e4Smiod {
614*3d8817e4Smiod col += strlen (buf);
615*3d8817e4Smiod
616*3d8817e4Smiod for (; col < starting_col + 5; ++col)
617*3d8817e4Smiod putchar (' ');
618*3d8817e4Smiod
619*3d8817e4Smiod printf (" %s ", buf);
620*3d8817e4Smiod col += print_name_only (sym);
621*3d8817e4Smiod
622*3d8817e4Smiod if (!line_granularity && sym->is_static && sym->file)
623*3d8817e4Smiod {
624*3d8817e4Smiod filename = sym->file->name;
625*3d8817e4Smiod
626*3d8817e4Smiod if (!print_path)
627*3d8817e4Smiod {
628*3d8817e4Smiod filename = strrchr (filename, '/');
629*3d8817e4Smiod
630*3d8817e4Smiod if (filename)
631*3d8817e4Smiod ++filename;
632*3d8817e4Smiod else
633*3d8817e4Smiod filename = sym->file->name;
634*3d8817e4Smiod }
635*3d8817e4Smiod
636*3d8817e4Smiod printf (" (%s)", filename);
637*3d8817e4Smiod col += strlen (filename) + 3;
638*3d8817e4Smiod }
639*3d8817e4Smiod }
640*3d8817e4Smiod }
641*3d8817e4Smiod else
642*3d8817e4Smiod {
643*3d8817e4Smiod if (bsd_style_output)
644*3d8817e4Smiod {
645*3d8817e4Smiod printf ("%6.6s ", buf);
646*3d8817e4Smiod sprintf (buf, _("<cycle %d>"), sym->cg.cyc.num);
647*3d8817e4Smiod printf ("%-19.19s", buf);
648*3d8817e4Smiod }
649*3d8817e4Smiod else
650*3d8817e4Smiod {
651*3d8817e4Smiod col += strlen (buf);
652*3d8817e4Smiod for (; col < starting_col + 5; ++col)
653*3d8817e4Smiod putchar (' ');
654*3d8817e4Smiod printf (" %s ", buf);
655*3d8817e4Smiod sprintf (buf, _("<cycle %d>"), sym->cg.cyc.num);
656*3d8817e4Smiod printf ("%s", buf);
657*3d8817e4Smiod col += strlen (buf);
658*3d8817e4Smiod }
659*3d8817e4Smiod }
660*3d8817e4Smiod
661*3d8817e4Smiod starting_col += column_width;
662*3d8817e4Smiod }
663*3d8817e4Smiod
664*3d8817e4Smiod printf ("\n");
665*3d8817e4Smiod }
666*3d8817e4Smiod
667*3d8817e4Smiod free (name_sorted_syms);
668*3d8817e4Smiod }
669*3d8817e4Smiod
670*3d8817e4Smiod /* Compare two arcs based on their usage counts.
671*3d8817e4Smiod We want to sort in descending order. */
672*3d8817e4Smiod
673*3d8817e4Smiod static int
cmp_arc_count(const PTR left,const PTR right)674*3d8817e4Smiod cmp_arc_count (const PTR left, const PTR right)
675*3d8817e4Smiod {
676*3d8817e4Smiod const Arc **npp1 = (const Arc **) left;
677*3d8817e4Smiod const Arc **npp2 = (const Arc **) right;
678*3d8817e4Smiod
679*3d8817e4Smiod if ((*npp1)->count > (*npp2)->count)
680*3d8817e4Smiod return -1;
681*3d8817e4Smiod else if ((*npp1)->count < (*npp2)->count)
682*3d8817e4Smiod return 1;
683*3d8817e4Smiod else
684*3d8817e4Smiod return 0;
685*3d8817e4Smiod }
686*3d8817e4Smiod
687*3d8817e4Smiod /* Compare two funtions based on their usage counts.
688*3d8817e4Smiod We want to sort in descending order. */
689*3d8817e4Smiod
690*3d8817e4Smiod static int
cmp_fun_nuses(const PTR left,const PTR right)691*3d8817e4Smiod cmp_fun_nuses (const PTR left, const PTR right)
692*3d8817e4Smiod {
693*3d8817e4Smiod const Sym **npp1 = (const Sym **) left;
694*3d8817e4Smiod const Sym **npp2 = (const Sym **) right;
695*3d8817e4Smiod
696*3d8817e4Smiod if ((*npp1)->nuses > (*npp2)->nuses)
697*3d8817e4Smiod return -1;
698*3d8817e4Smiod else if ((*npp1)->nuses < (*npp2)->nuses)
699*3d8817e4Smiod return 1;
700*3d8817e4Smiod else
701*3d8817e4Smiod return 0;
702*3d8817e4Smiod }
703*3d8817e4Smiod
704*3d8817e4Smiod /* Print a suggested function ordering based on the profiling data.
705*3d8817e4Smiod
706*3d8817e4Smiod We perform 4 major steps when ordering functions:
707*3d8817e4Smiod
708*3d8817e4Smiod * Group unused functions together and place them at the
709*3d8817e4Smiod end of the function order.
710*3d8817e4Smiod
711*3d8817e4Smiod * Search the highest use arcs (those which account for 90% of
712*3d8817e4Smiod the total arc count) for functions which have several parents.
713*3d8817e4Smiod
714*3d8817e4Smiod Group those with the most call sites together (currently the
715*3d8817e4Smiod top 1.25% which have at least five different call sites).
716*3d8817e4Smiod
717*3d8817e4Smiod These are emitted at the start of the function order.
718*3d8817e4Smiod
719*3d8817e4Smiod * Use a greedy placement algorithm to place functions which
720*3d8817e4Smiod occur in the top 99% of the arcs in the profile. Some provisions
721*3d8817e4Smiod are made to handle high usage arcs where the parent and/or
722*3d8817e4Smiod child has already been placed.
723*3d8817e4Smiod
724*3d8817e4Smiod * Run the same greedy placement algorithm on the remaining
725*3d8817e4Smiod arcs to place the leftover functions.
726*3d8817e4Smiod
727*3d8817e4Smiod
728*3d8817e4Smiod The various "magic numbers" should (one day) be tuneable by command
729*3d8817e4Smiod line options. They were arrived at by benchmarking a few applications
730*3d8817e4Smiod with various values to see which values produced better overall function
731*3d8817e4Smiod orderings.
732*3d8817e4Smiod
733*3d8817e4Smiod Of course, profiling errors, machine limitations (PA long calls), and
734*3d8817e4Smiod poor cutoff values for the placement algorithm may limit the usefullness
735*3d8817e4Smiod of the resulting function order. Improvements would be greatly appreciated.
736*3d8817e4Smiod
737*3d8817e4Smiod Suggestions:
738*3d8817e4Smiod
739*3d8817e4Smiod * Place the functions with many callers near the middle of the
740*3d8817e4Smiod list to reduce long calls.
741*3d8817e4Smiod
742*3d8817e4Smiod * Propagate arc usage changes as functions are placed. Ie if
743*3d8817e4Smiod func1 and func2 are placed together, arcs to/from those arcs
744*3d8817e4Smiod to the same parent/child should be combined, then resort the
745*3d8817e4Smiod arcs to choose the next one.
746*3d8817e4Smiod
747*3d8817e4Smiod * Implement some global positioning algorithm to place the
748*3d8817e4Smiod chains made by the greedy local positioning algorithm. Probably
749*3d8817e4Smiod by examining arcs which haven't been placed yet to tie two
750*3d8817e4Smiod chains together.
751*3d8817e4Smiod
752*3d8817e4Smiod * Take a function's size and time into account in the algorithm;
753*3d8817e4Smiod size in particular is important on the PA (long calls). Placing
754*3d8817e4Smiod many small functions onto their own page may be wise.
755*3d8817e4Smiod
756*3d8817e4Smiod * Use better profiling information; many published algorithms
757*3d8817e4Smiod are based on call sequences through time, rather than just
758*3d8817e4Smiod arc counts.
759*3d8817e4Smiod
760*3d8817e4Smiod * Prodecure cloning could improve performance when a small number
761*3d8817e4Smiod of arcs account for most of the calls to a particular function.
762*3d8817e4Smiod
763*3d8817e4Smiod * Use relocation information to avoid moving unused functions
764*3d8817e4Smiod completely out of the code stream; this would avoid severe lossage
765*3d8817e4Smiod when the profile data bears little resemblance to actual runs.
766*3d8817e4Smiod
767*3d8817e4Smiod * Propagation of arc usages should also improve .o link line
768*3d8817e4Smiod ordering which shares the same arc placement algorithm with
769*3d8817e4Smiod the function ordering code (in fact it is a degenerate case
770*3d8817e4Smiod of function ordering). */
771*3d8817e4Smiod
772*3d8817e4Smiod void
cg_print_function_ordering()773*3d8817e4Smiod cg_print_function_ordering ()
774*3d8817e4Smiod {
775*3d8817e4Smiod unsigned long index, used, unused, scratch_index;
776*3d8817e4Smiod unsigned long unplaced_arc_count, high_arc_count, scratch_arc_count;
777*3d8817e4Smiod #ifdef __GNUC__
778*3d8817e4Smiod unsigned long long total_arcs, tmp_arcs_count;
779*3d8817e4Smiod #else
780*3d8817e4Smiod unsigned long total_arcs, tmp_arcs_count;
781*3d8817e4Smiod #endif
782*3d8817e4Smiod Sym **unused_syms, **used_syms, **scratch_syms;
783*3d8817e4Smiod Arc **unplaced_arcs, **high_arcs, **scratch_arcs;
784*3d8817e4Smiod
785*3d8817e4Smiod index = 0;
786*3d8817e4Smiod used = 0;
787*3d8817e4Smiod unused = 0;
788*3d8817e4Smiod scratch_index = 0;
789*3d8817e4Smiod unplaced_arc_count = 0;
790*3d8817e4Smiod high_arc_count = 0;
791*3d8817e4Smiod scratch_arc_count = 0;
792*3d8817e4Smiod
793*3d8817e4Smiod /* First group all the unused functions together. */
794*3d8817e4Smiod unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
795*3d8817e4Smiod used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
796*3d8817e4Smiod scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
797*3d8817e4Smiod high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
798*3d8817e4Smiod scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
799*3d8817e4Smiod unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
800*3d8817e4Smiod
801*3d8817e4Smiod /* Walk through all the functions; mark those which are never
802*3d8817e4Smiod called as placed (we'll emit them as a group later). */
803*3d8817e4Smiod for (index = 0, used = 0, unused = 0; index < symtab.len; index++)
804*3d8817e4Smiod {
805*3d8817e4Smiod if (symtab.base[index].ncalls == 0)
806*3d8817e4Smiod {
807*3d8817e4Smiod /* Filter out gprof generated names. */
808*3d8817e4Smiod if (strcmp (symtab.base[index].name, "<locore>")
809*3d8817e4Smiod && strcmp (symtab.base[index].name, "<hicore>"))
810*3d8817e4Smiod {
811*3d8817e4Smiod unused_syms[unused++] = &symtab.base[index];
812*3d8817e4Smiod symtab.base[index].has_been_placed = 1;
813*3d8817e4Smiod }
814*3d8817e4Smiod }
815*3d8817e4Smiod else
816*3d8817e4Smiod {
817*3d8817e4Smiod used_syms[used++] = &symtab.base[index];
818*3d8817e4Smiod symtab.base[index].has_been_placed = 0;
819*3d8817e4Smiod symtab.base[index].next = 0;
820*3d8817e4Smiod symtab.base[index].prev = 0;
821*3d8817e4Smiod symtab.base[index].nuses = 0;
822*3d8817e4Smiod }
823*3d8817e4Smiod }
824*3d8817e4Smiod
825*3d8817e4Smiod /* Sort the arcs from most used to least used. */
826*3d8817e4Smiod qsort (arcs, numarcs, sizeof (Arc *), cmp_arc_count);
827*3d8817e4Smiod
828*3d8817e4Smiod /* Compute the total arc count. Also mark arcs as unplaced.
829*3d8817e4Smiod
830*3d8817e4Smiod Note we don't compensate for overflow if that happens!
831*3d8817e4Smiod Overflow is much less likely when this file is compiled
832*3d8817e4Smiod with GCC as it can double-wide integers via long long. */
833*3d8817e4Smiod total_arcs = 0;
834*3d8817e4Smiod for (index = 0; index < numarcs; index++)
835*3d8817e4Smiod {
836*3d8817e4Smiod total_arcs += arcs[index]->count;
837*3d8817e4Smiod arcs[index]->has_been_placed = 0;
838*3d8817e4Smiod }
839*3d8817e4Smiod
840*3d8817e4Smiod /* We want to pull out those functions which are referenced
841*3d8817e4Smiod by many highly used arcs and emit them as a group. This
842*3d8817e4Smiod could probably use some tuning. */
843*3d8817e4Smiod tmp_arcs_count = 0;
844*3d8817e4Smiod for (index = 0; index < numarcs; index++)
845*3d8817e4Smiod {
846*3d8817e4Smiod tmp_arcs_count += arcs[index]->count;
847*3d8817e4Smiod
848*3d8817e4Smiod /* Count how many times each parent and child are used up
849*3d8817e4Smiod to our threshhold of arcs (90%). */
850*3d8817e4Smiod if ((double)tmp_arcs_count / (double)total_arcs > 0.90)
851*3d8817e4Smiod break;
852*3d8817e4Smiod
853*3d8817e4Smiod arcs[index]->child->nuses++;
854*3d8817e4Smiod }
855*3d8817e4Smiod
856*3d8817e4Smiod /* Now sort a temporary symbol table based on the number of
857*3d8817e4Smiod times each function was used in the highest used arcs. */
858*3d8817e4Smiod memcpy (scratch_syms, used_syms, used * sizeof (Sym *));
859*3d8817e4Smiod qsort (scratch_syms, used, sizeof (Sym *), cmp_fun_nuses);
860*3d8817e4Smiod
861*3d8817e4Smiod /* Now pick out those symbols we're going to emit as
862*3d8817e4Smiod a group. We take up to 1.25% of the used symbols. */
863*3d8817e4Smiod for (index = 0; index < used / 80; index++)
864*3d8817e4Smiod {
865*3d8817e4Smiod Sym *sym = scratch_syms[index];
866*3d8817e4Smiod Arc *arc;
867*3d8817e4Smiod
868*3d8817e4Smiod /* If we hit symbols that aren't used from many call sites,
869*3d8817e4Smiod then we can quit. We choose five as the low limit for
870*3d8817e4Smiod no particular reason. */
871*3d8817e4Smiod if (sym->nuses == 5)
872*3d8817e4Smiod break;
873*3d8817e4Smiod
874*3d8817e4Smiod /* We're going to need the arcs between these functions.
875*3d8817e4Smiod Unfortunately, we don't know all these functions
876*3d8817e4Smiod until we're done. So we keep track of all the arcs
877*3d8817e4Smiod to the functions we care about, then prune out those
878*3d8817e4Smiod which are uninteresting.
879*3d8817e4Smiod
880*3d8817e4Smiod An interesting variation would be to quit when we found
881*3d8817e4Smiod multi-call site functions which account for some percentage
882*3d8817e4Smiod of the arcs. */
883*3d8817e4Smiod arc = sym->cg.children;
884*3d8817e4Smiod
885*3d8817e4Smiod while (arc)
886*3d8817e4Smiod {
887*3d8817e4Smiod if (arc->parent != arc->child)
888*3d8817e4Smiod scratch_arcs[scratch_arc_count++] = arc;
889*3d8817e4Smiod arc->has_been_placed = 1;
890*3d8817e4Smiod arc = arc->next_child;
891*3d8817e4Smiod }
892*3d8817e4Smiod
893*3d8817e4Smiod arc = sym->cg.parents;
894*3d8817e4Smiod
895*3d8817e4Smiod while (arc)
896*3d8817e4Smiod {
897*3d8817e4Smiod if (arc->parent != arc->child)
898*3d8817e4Smiod scratch_arcs[scratch_arc_count++] = arc;
899*3d8817e4Smiod arc->has_been_placed = 1;
900*3d8817e4Smiod arc = arc->next_parent;
901*3d8817e4Smiod }
902*3d8817e4Smiod
903*3d8817e4Smiod /* Keep track of how many symbols we're going to place. */
904*3d8817e4Smiod scratch_index = index;
905*3d8817e4Smiod
906*3d8817e4Smiod /* A lie, but it makes identifying
907*3d8817e4Smiod these functions easier later. */
908*3d8817e4Smiod sym->has_been_placed = 1;
909*3d8817e4Smiod }
910*3d8817e4Smiod
911*3d8817e4Smiod /* Now walk through the temporary arcs and copy
912*3d8817e4Smiod those we care about into the high arcs array. */
913*3d8817e4Smiod for (index = 0; index < scratch_arc_count; index++)
914*3d8817e4Smiod {
915*3d8817e4Smiod Arc *arc = scratch_arcs[index];
916*3d8817e4Smiod
917*3d8817e4Smiod /* If this arc refers to highly used functions, then
918*3d8817e4Smiod then we want to keep it. */
919*3d8817e4Smiod if (arc->child->has_been_placed
920*3d8817e4Smiod && arc->parent->has_been_placed)
921*3d8817e4Smiod {
922*3d8817e4Smiod high_arcs[high_arc_count++] = scratch_arcs[index];
923*3d8817e4Smiod
924*3d8817e4Smiod /* We need to turn of has_been_placed since we're going to
925*3d8817e4Smiod use the main arc placement algorithm on these arcs. */
926*3d8817e4Smiod arc->child->has_been_placed = 0;
927*3d8817e4Smiod arc->parent->has_been_placed = 0;
928*3d8817e4Smiod }
929*3d8817e4Smiod }
930*3d8817e4Smiod
931*3d8817e4Smiod /* Dump the multi-site high usage functions which are not
932*3d8817e4Smiod going to be ordered by the main ordering algorithm. */
933*3d8817e4Smiod for (index = 0; index < scratch_index; index++)
934*3d8817e4Smiod {
935*3d8817e4Smiod if (scratch_syms[index]->has_been_placed)
936*3d8817e4Smiod printf ("%s\n", scratch_syms[index]->name);
937*3d8817e4Smiod }
938*3d8817e4Smiod
939*3d8817e4Smiod /* Now we can order the multi-site high use
940*3d8817e4Smiod functions based on the arcs between them. */
941*3d8817e4Smiod qsort (high_arcs, high_arc_count, sizeof (Arc *), cmp_arc_count);
942*3d8817e4Smiod order_and_dump_functions_by_arcs (high_arcs, high_arc_count, 1,
943*3d8817e4Smiod unplaced_arcs, &unplaced_arc_count);
944*3d8817e4Smiod
945*3d8817e4Smiod /* Order and dump the high use functions left,
946*3d8817e4Smiod these typically have only a few call sites. */
947*3d8817e4Smiod order_and_dump_functions_by_arcs (arcs, numarcs, 0,
948*3d8817e4Smiod unplaced_arcs, &unplaced_arc_count);
949*3d8817e4Smiod
950*3d8817e4Smiod /* Now place the rarely used functions. */
951*3d8817e4Smiod order_and_dump_functions_by_arcs (unplaced_arcs, unplaced_arc_count, 1,
952*3d8817e4Smiod scratch_arcs, &scratch_arc_count);
953*3d8817e4Smiod
954*3d8817e4Smiod /* Output any functions not emitted by the order_and_dump calls. */
955*3d8817e4Smiod for (index = 0; index < used; index++)
956*3d8817e4Smiod if (used_syms[index]->has_been_placed == 0)
957*3d8817e4Smiod printf("%s\n", used_syms[index]->name);
958*3d8817e4Smiod
959*3d8817e4Smiod /* Output the unused functions. */
960*3d8817e4Smiod for (index = 0; index < unused; index++)
961*3d8817e4Smiod printf("%s\n", unused_syms[index]->name);
962*3d8817e4Smiod
963*3d8817e4Smiod unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
964*3d8817e4Smiod used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
965*3d8817e4Smiod scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
966*3d8817e4Smiod high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
967*3d8817e4Smiod scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
968*3d8817e4Smiod unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
969*3d8817e4Smiod
970*3d8817e4Smiod free (unused_syms);
971*3d8817e4Smiod free (used_syms);
972*3d8817e4Smiod free (scratch_syms);
973*3d8817e4Smiod free (high_arcs);
974*3d8817e4Smiod free (scratch_arcs);
975*3d8817e4Smiod free (unplaced_arcs);
976*3d8817e4Smiod }
977*3d8817e4Smiod
978*3d8817e4Smiod /* Place functions based on the arcs in THE_ARCS with ARC_COUNT entries;
979*3d8817e4Smiod place unused arcs into UNPLACED_ARCS/UNPLACED_ARC_COUNT.
980*3d8817e4Smiod
981*3d8817e4Smiod If ALL is nonzero, then place all functions referenced by THE_ARCS,
982*3d8817e4Smiod else only place those referenced in the top 99% of the arcs in THE_ARCS. */
983*3d8817e4Smiod
984*3d8817e4Smiod #define MOST 0.99
985*3d8817e4Smiod static void
order_and_dump_functions_by_arcs(the_arcs,arc_count,all,unplaced_arcs,unplaced_arc_count)986*3d8817e4Smiod order_and_dump_functions_by_arcs (the_arcs, arc_count, all,
987*3d8817e4Smiod unplaced_arcs, unplaced_arc_count)
988*3d8817e4Smiod Arc **the_arcs;
989*3d8817e4Smiod unsigned long arc_count;
990*3d8817e4Smiod int all;
991*3d8817e4Smiod Arc **unplaced_arcs;
992*3d8817e4Smiod unsigned long *unplaced_arc_count;
993*3d8817e4Smiod {
994*3d8817e4Smiod #ifdef __GNUC__
995*3d8817e4Smiod unsigned long long tmp_arcs, total_arcs;
996*3d8817e4Smiod #else
997*3d8817e4Smiod unsigned long tmp_arcs, total_arcs;
998*3d8817e4Smiod #endif
999*3d8817e4Smiod unsigned int index;
1000*3d8817e4Smiod
1001*3d8817e4Smiod /* If needed, compute the total arc count.
1002*3d8817e4Smiod
1003*3d8817e4Smiod Note we don't compensate for overflow if that happens! */
1004*3d8817e4Smiod if (! all)
1005*3d8817e4Smiod {
1006*3d8817e4Smiod total_arcs = 0;
1007*3d8817e4Smiod for (index = 0; index < arc_count; index++)
1008*3d8817e4Smiod total_arcs += the_arcs[index]->count;
1009*3d8817e4Smiod }
1010*3d8817e4Smiod else
1011*3d8817e4Smiod total_arcs = 0;
1012*3d8817e4Smiod
1013*3d8817e4Smiod tmp_arcs = 0;
1014*3d8817e4Smiod
1015*3d8817e4Smiod for (index = 0; index < arc_count; index++)
1016*3d8817e4Smiod {
1017*3d8817e4Smiod Sym *sym1, *sym2;
1018*3d8817e4Smiod Sym *child, *parent;
1019*3d8817e4Smiod
1020*3d8817e4Smiod tmp_arcs += the_arcs[index]->count;
1021*3d8817e4Smiod
1022*3d8817e4Smiod /* Ignore this arc if it's already been placed. */
1023*3d8817e4Smiod if (the_arcs[index]->has_been_placed)
1024*3d8817e4Smiod continue;
1025*3d8817e4Smiod
1026*3d8817e4Smiod child = the_arcs[index]->child;
1027*3d8817e4Smiod parent = the_arcs[index]->parent;
1028*3d8817e4Smiod
1029*3d8817e4Smiod /* If we're not using all arcs, and this is a rarely used
1030*3d8817e4Smiod arc, then put it on the unplaced_arc list. Similarly
1031*3d8817e4Smiod if both the parent and child of this arc have been placed. */
1032*3d8817e4Smiod if ((! all && (double)tmp_arcs / (double)total_arcs > MOST)
1033*3d8817e4Smiod || child->has_been_placed || parent->has_been_placed)
1034*3d8817e4Smiod {
1035*3d8817e4Smiod unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1036*3d8817e4Smiod continue;
1037*3d8817e4Smiod }
1038*3d8817e4Smiod
1039*3d8817e4Smiod /* If all slots in the parent and child are full, then there isn't
1040*3d8817e4Smiod anything we can do right now. We'll place this arc on the
1041*3d8817e4Smiod unplaced arc list in the hope that a global positioning
1042*3d8817e4Smiod algorithm can use it to place function chains. */
1043*3d8817e4Smiod if (parent->next && parent->prev && child->next && child->prev)
1044*3d8817e4Smiod {
1045*3d8817e4Smiod unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1046*3d8817e4Smiod continue;
1047*3d8817e4Smiod }
1048*3d8817e4Smiod
1049*3d8817e4Smiod /* If the parent is unattached, then find the closest
1050*3d8817e4Smiod place to attach it onto child's chain. Similarly
1051*3d8817e4Smiod for the opposite case. */
1052*3d8817e4Smiod if (!parent->next && !parent->prev)
1053*3d8817e4Smiod {
1054*3d8817e4Smiod int next_count = 0;
1055*3d8817e4Smiod int prev_count = 0;
1056*3d8817e4Smiod Sym *prev = child;
1057*3d8817e4Smiod Sym *next = child;
1058*3d8817e4Smiod
1059*3d8817e4Smiod /* Walk to the beginning and end of the child's chain. */
1060*3d8817e4Smiod while (next->next)
1061*3d8817e4Smiod {
1062*3d8817e4Smiod next = next->next;
1063*3d8817e4Smiod next_count++;
1064*3d8817e4Smiod }
1065*3d8817e4Smiod
1066*3d8817e4Smiod while (prev->prev)
1067*3d8817e4Smiod {
1068*3d8817e4Smiod prev = prev->prev;
1069*3d8817e4Smiod prev_count++;
1070*3d8817e4Smiod }
1071*3d8817e4Smiod
1072*3d8817e4Smiod /* Choose the closest. */
1073*3d8817e4Smiod child = next_count < prev_count ? next : prev;
1074*3d8817e4Smiod }
1075*3d8817e4Smiod else if (! child->next && !child->prev)
1076*3d8817e4Smiod {
1077*3d8817e4Smiod int next_count = 0;
1078*3d8817e4Smiod int prev_count = 0;
1079*3d8817e4Smiod Sym *prev = parent;
1080*3d8817e4Smiod Sym *next = parent;
1081*3d8817e4Smiod
1082*3d8817e4Smiod while (next->next)
1083*3d8817e4Smiod {
1084*3d8817e4Smiod next = next->next;
1085*3d8817e4Smiod next_count++;
1086*3d8817e4Smiod }
1087*3d8817e4Smiod
1088*3d8817e4Smiod while (prev->prev)
1089*3d8817e4Smiod {
1090*3d8817e4Smiod prev = prev->prev;
1091*3d8817e4Smiod prev_count++;
1092*3d8817e4Smiod }
1093*3d8817e4Smiod
1094*3d8817e4Smiod parent = prev_count < next_count ? prev : next;
1095*3d8817e4Smiod }
1096*3d8817e4Smiod else
1097*3d8817e4Smiod {
1098*3d8817e4Smiod /* Couldn't find anywhere to attach the functions,
1099*3d8817e4Smiod put the arc on the unplaced arc list. */
1100*3d8817e4Smiod unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1101*3d8817e4Smiod continue;
1102*3d8817e4Smiod }
1103*3d8817e4Smiod
1104*3d8817e4Smiod /* Make sure we don't tie two ends together. */
1105*3d8817e4Smiod sym1 = parent;
1106*3d8817e4Smiod if (sym1->next)
1107*3d8817e4Smiod while (sym1->next)
1108*3d8817e4Smiod sym1 = sym1->next;
1109*3d8817e4Smiod else
1110*3d8817e4Smiod while (sym1->prev)
1111*3d8817e4Smiod sym1 = sym1->prev;
1112*3d8817e4Smiod
1113*3d8817e4Smiod sym2 = child;
1114*3d8817e4Smiod if (sym2->next)
1115*3d8817e4Smiod while (sym2->next)
1116*3d8817e4Smiod sym2 = sym2->next;
1117*3d8817e4Smiod else
1118*3d8817e4Smiod while (sym2->prev)
1119*3d8817e4Smiod sym2 = sym2->prev;
1120*3d8817e4Smiod
1121*3d8817e4Smiod if (sym1 == child
1122*3d8817e4Smiod && sym2 == parent)
1123*3d8817e4Smiod {
1124*3d8817e4Smiod /* This would tie two ends together. */
1125*3d8817e4Smiod unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1126*3d8817e4Smiod continue;
1127*3d8817e4Smiod }
1128*3d8817e4Smiod
1129*3d8817e4Smiod if (parent->next)
1130*3d8817e4Smiod {
1131*3d8817e4Smiod /* Must attach to the parent's prev field. */
1132*3d8817e4Smiod if (! child->next)
1133*3d8817e4Smiod {
1134*3d8817e4Smiod /* parent-prev and child-next */
1135*3d8817e4Smiod parent->prev = child;
1136*3d8817e4Smiod child->next = parent;
1137*3d8817e4Smiod the_arcs[index]->has_been_placed = 1;
1138*3d8817e4Smiod }
1139*3d8817e4Smiod }
1140*3d8817e4Smiod else if (parent->prev)
1141*3d8817e4Smiod {
1142*3d8817e4Smiod /* Must attach to the parent's next field. */
1143*3d8817e4Smiod if (! child->prev)
1144*3d8817e4Smiod {
1145*3d8817e4Smiod /* parent-next and child-prev */
1146*3d8817e4Smiod parent->next = child;
1147*3d8817e4Smiod child->prev = parent;
1148*3d8817e4Smiod the_arcs[index]->has_been_placed = 1;
1149*3d8817e4Smiod }
1150*3d8817e4Smiod }
1151*3d8817e4Smiod else
1152*3d8817e4Smiod {
1153*3d8817e4Smiod /* Can attach to either field in the parent, depends
1154*3d8817e4Smiod on where we've got space in the child. */
1155*3d8817e4Smiod if (child->prev)
1156*3d8817e4Smiod {
1157*3d8817e4Smiod /* parent-prev and child-next. */
1158*3d8817e4Smiod parent->prev = child;
1159*3d8817e4Smiod child->next = parent;
1160*3d8817e4Smiod the_arcs[index]->has_been_placed = 1;
1161*3d8817e4Smiod }
1162*3d8817e4Smiod else
1163*3d8817e4Smiod {
1164*3d8817e4Smiod /* parent-next and child-prev. */
1165*3d8817e4Smiod parent->next = child;
1166*3d8817e4Smiod child->prev = parent;
1167*3d8817e4Smiod the_arcs[index]->has_been_placed = 1;
1168*3d8817e4Smiod }
1169*3d8817e4Smiod }
1170*3d8817e4Smiod }
1171*3d8817e4Smiod
1172*3d8817e4Smiod /* Dump the chains of functions we've made. */
1173*3d8817e4Smiod for (index = 0; index < arc_count; index++)
1174*3d8817e4Smiod {
1175*3d8817e4Smiod Sym *sym;
1176*3d8817e4Smiod if (the_arcs[index]->parent->has_been_placed
1177*3d8817e4Smiod || the_arcs[index]->child->has_been_placed)
1178*3d8817e4Smiod continue;
1179*3d8817e4Smiod
1180*3d8817e4Smiod sym = the_arcs[index]->parent;
1181*3d8817e4Smiod
1182*3d8817e4Smiod /* If this symbol isn't attached to any other
1183*3d8817e4Smiod symbols, then we've got a rarely used arc.
1184*3d8817e4Smiod
1185*3d8817e4Smiod Skip it for now, we'll deal with them later. */
1186*3d8817e4Smiod if (sym->next == NULL
1187*3d8817e4Smiod && sym->prev == NULL)
1188*3d8817e4Smiod continue;
1189*3d8817e4Smiod
1190*3d8817e4Smiod /* Get to the start of this chain. */
1191*3d8817e4Smiod while (sym->prev)
1192*3d8817e4Smiod sym = sym->prev;
1193*3d8817e4Smiod
1194*3d8817e4Smiod while (sym)
1195*3d8817e4Smiod {
1196*3d8817e4Smiod /* Mark it as placed. */
1197*3d8817e4Smiod sym->has_been_placed = 1;
1198*3d8817e4Smiod printf ("%s\n", sym->name);
1199*3d8817e4Smiod sym = sym->next;
1200*3d8817e4Smiod }
1201*3d8817e4Smiod }
1202*3d8817e4Smiod
1203*3d8817e4Smiod /* If we want to place all the arcs, then output
1204*3d8817e4Smiod those which weren't placed by the main algorithm. */
1205*3d8817e4Smiod if (all)
1206*3d8817e4Smiod for (index = 0; index < arc_count; index++)
1207*3d8817e4Smiod {
1208*3d8817e4Smiod Sym *sym;
1209*3d8817e4Smiod if (the_arcs[index]->parent->has_been_placed
1210*3d8817e4Smiod || the_arcs[index]->child->has_been_placed)
1211*3d8817e4Smiod continue;
1212*3d8817e4Smiod
1213*3d8817e4Smiod sym = the_arcs[index]->parent;
1214*3d8817e4Smiod
1215*3d8817e4Smiod sym->has_been_placed = 1;
1216*3d8817e4Smiod printf ("%s\n", sym->name);
1217*3d8817e4Smiod }
1218*3d8817e4Smiod }
1219*3d8817e4Smiod
1220*3d8817e4Smiod /* Print a suggested .o ordering for files on a link line based
1221*3d8817e4Smiod on profiling information. This uses the function placement
1222*3d8817e4Smiod code for the bulk of its work. */
1223*3d8817e4Smiod
1224*3d8817e4Smiod void
cg_print_file_ordering()1225*3d8817e4Smiod cg_print_file_ordering ()
1226*3d8817e4Smiod {
1227*3d8817e4Smiod unsigned long scratch_arc_count, index;
1228*3d8817e4Smiod Arc **scratch_arcs;
1229*3d8817e4Smiod char *last;
1230*3d8817e4Smiod
1231*3d8817e4Smiod scratch_arc_count = 0;
1232*3d8817e4Smiod
1233*3d8817e4Smiod scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
1234*3d8817e4Smiod for (index = 0; index < numarcs; index++)
1235*3d8817e4Smiod {
1236*3d8817e4Smiod if (! arcs[index]->parent->mapped
1237*3d8817e4Smiod || ! arcs[index]->child->mapped)
1238*3d8817e4Smiod arcs[index]->has_been_placed = 1;
1239*3d8817e4Smiod }
1240*3d8817e4Smiod
1241*3d8817e4Smiod order_and_dump_functions_by_arcs (arcs, numarcs, 0,
1242*3d8817e4Smiod scratch_arcs, &scratch_arc_count);
1243*3d8817e4Smiod
1244*3d8817e4Smiod /* Output .o's not handled by the main placement algorithm. */
1245*3d8817e4Smiod for (index = 0; index < symtab.len; index++)
1246*3d8817e4Smiod {
1247*3d8817e4Smiod if (symtab.base[index].mapped
1248*3d8817e4Smiod && ! symtab.base[index].has_been_placed)
1249*3d8817e4Smiod printf ("%s\n", symtab.base[index].name);
1250*3d8817e4Smiod }
1251*3d8817e4Smiod
1252*3d8817e4Smiod /* Now output any .o's that didn't have any text symbols. */
1253*3d8817e4Smiod last = NULL;
1254*3d8817e4Smiod for (index = 0; index < symbol_map_count; index++)
1255*3d8817e4Smiod {
1256*3d8817e4Smiod unsigned int index2;
1257*3d8817e4Smiod
1258*3d8817e4Smiod /* Don't bother searching if this symbol
1259*3d8817e4Smiod is the same as the previous one. */
1260*3d8817e4Smiod if (last && !strcmp (last, symbol_map[index].file_name))
1261*3d8817e4Smiod continue;
1262*3d8817e4Smiod
1263*3d8817e4Smiod for (index2 = 0; index2 < symtab.len; index2++)
1264*3d8817e4Smiod {
1265*3d8817e4Smiod if (! symtab.base[index2].mapped)
1266*3d8817e4Smiod continue;
1267*3d8817e4Smiod
1268*3d8817e4Smiod if (!strcmp (symtab.base[index2].name, symbol_map[index].file_name))
1269*3d8817e4Smiod break;
1270*3d8817e4Smiod }
1271*3d8817e4Smiod
1272*3d8817e4Smiod /* If we didn't find it in the symbol table, then it must
1273*3d8817e4Smiod be a .o with no text symbols. Output it last. */
1274*3d8817e4Smiod if (index2 == symtab.len)
1275*3d8817e4Smiod printf ("%s\n", symbol_map[index].file_name);
1276*3d8817e4Smiod last = symbol_map[index].file_name;
1277*3d8817e4Smiod }
1278*3d8817e4Smiod }
1279