xref: /openbsd-src/gnu/usr.bin/binutils-2.17/gprof/cg_print.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
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