1b55d4692Sfgsch /* cg_print.c - Print routines for displaying call graphs.
2b55d4692Sfgsch
3*c074d1c9Sdrahn Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
4b55d4692Sfgsch
5b55d4692Sfgsch This file is part of GNU Binutils.
6b55d4692Sfgsch
7b55d4692Sfgsch This program is free software; you can redistribute it and/or modify
8b55d4692Sfgsch it under the terms of the GNU General Public License as published by
9b55d4692Sfgsch the Free Software Foundation; either version 2 of the License, or
10b55d4692Sfgsch (at your option) any later version.
11b55d4692Sfgsch
12b55d4692Sfgsch This program is distributed in the hope that it will be useful,
13b55d4692Sfgsch but WITHOUT ANY WARRANTY; without even the implied warranty of
14b55d4692Sfgsch MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15b55d4692Sfgsch GNU General Public License for more details.
16b55d4692Sfgsch
17b55d4692Sfgsch You should have received a copy of the GNU General Public License
18b55d4692Sfgsch along with this program; if not, write to the Free Software
19b55d4692Sfgsch Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20b55d4692Sfgsch 02111-1307, USA. */
21b55d4692Sfgsch
222159047fSniklas #include "libiberty.h"
23*c074d1c9Sdrahn #include "gprof.h"
24*c074d1c9Sdrahn #include "search_list.h"
25*c074d1c9Sdrahn #include "source.h"
26*c074d1c9Sdrahn #include "symtab.h"
272159047fSniklas #include "cg_arcs.h"
282159047fSniklas #include "cg_print.h"
292159047fSniklas #include "hist.h"
302159047fSniklas #include "utils.h"
31*c074d1c9Sdrahn #include "corefile.h"
322159047fSniklas
33b55d4692Sfgsch /* Return value of comparison functions used to sort tables. */
342159047fSniklas #define LESSTHAN -1
352159047fSniklas #define EQUALTO 0
362159047fSniklas #define GREATERTHAN 1
372159047fSniklas
38*c074d1c9Sdrahn static void print_header PARAMS ((void));
39*c074d1c9Sdrahn static void print_cycle PARAMS ((Sym *));
40*c074d1c9Sdrahn static int cmp_member PARAMS ((Sym *, Sym *));
41*c074d1c9Sdrahn static void sort_members PARAMS ((Sym *));
42*c074d1c9Sdrahn static void print_members PARAMS ((Sym *));
43*c074d1c9Sdrahn static int cmp_arc PARAMS ((Arc *, Arc *));
44*c074d1c9Sdrahn static void sort_parents PARAMS ((Sym *));
45*c074d1c9Sdrahn static void print_parents PARAMS ((Sym *));
46*c074d1c9Sdrahn static void sort_children PARAMS ((Sym *));
47*c074d1c9Sdrahn static void print_children PARAMS ((Sym *));
48*c074d1c9Sdrahn static void print_line PARAMS ((Sym *));
49*c074d1c9Sdrahn static int cmp_name PARAMS ((const PTR, const PTR));
50*c074d1c9Sdrahn static int cmp_arc_count PARAMS ((const PTR, const PTR));
51*c074d1c9Sdrahn static int cmp_fun_nuses PARAMS ((const PTR, const PTR));
52*c074d1c9Sdrahn static void order_and_dump_functions_by_arcs
53*c074d1c9Sdrahn PARAMS ((Arc **, unsigned long, int, Arc **, unsigned long *));
54*c074d1c9Sdrahn
55b55d4692Sfgsch /* Declarations of automatically generated functions to output blurbs. */
562159047fSniklas extern void bsd_callg_blurb PARAMS ((FILE * fp));
572159047fSniklas extern void fsf_callg_blurb PARAMS ((FILE * fp));
582159047fSniklas
592159047fSniklas double print_time = 0.0;
602159047fSniklas
612159047fSniklas
622159047fSniklas static void
print_header()63*c074d1c9Sdrahn print_header ()
642159047fSniklas {
652159047fSniklas if (first_output)
662159047fSniklas first_output = FALSE;
672159047fSniklas else
682159047fSniklas printf ("\f\n");
69b55d4692Sfgsch
702159047fSniklas if (!bsd_style_output)
712159047fSniklas {
722159047fSniklas if (print_descriptions)
73b305b0f1Sespie printf (_("\t\t Call graph (explanation follows)\n\n"));
742159047fSniklas else
75b305b0f1Sespie printf (_("\t\t\tCall graph\n\n"));
762159047fSniklas }
77b55d4692Sfgsch
78b305b0f1Sespie printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
792159047fSniklas (long) hist_scale * sizeof (UNIT));
80b55d4692Sfgsch
812159047fSniklas if (print_time > 0.0)
82b305b0f1Sespie printf (_(" for %.2f%% of %.2f seconds\n\n"),
832159047fSniklas 100.0 / print_time, print_time / hz);
842159047fSniklas else
852159047fSniklas {
86b305b0f1Sespie printf (_(" no time propagated\n\n"));
87b55d4692Sfgsch
88b55d4692Sfgsch /* This doesn't hurt, since all the numerators will be 0.0. */
892159047fSniklas print_time = 1.0;
902159047fSniklas }
91b55d4692Sfgsch
922159047fSniklas if (bsd_style_output)
932159047fSniklas {
942159047fSniklas printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
95b305b0f1Sespie "", "", "", "", _("called"), _("total"), _("parents"));
962159047fSniklas printf ("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
97*c074d1c9Sdrahn _("index"), _("%time"), _("self"), _("descendants"),
98b305b0f1Sespie _("called"), _("self"), _("name"), _("index"));
992159047fSniklas printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
100b305b0f1Sespie "", "", "", "", _("called"), _("total"), _("children"));
1012159047fSniklas printf ("\n");
1022159047fSniklas }
1032159047fSniklas else
1042159047fSniklas {
105b305b0f1Sespie printf (_("index %% time self children called name\n"));
1062159047fSniklas }
1072159047fSniklas }
1082159047fSniklas
109b55d4692Sfgsch /* Print a cycle header. */
1102159047fSniklas
1112159047fSniklas static void
print_cycle(cyc)112*c074d1c9Sdrahn print_cycle (cyc)
113*c074d1c9Sdrahn Sym *cyc;
1142159047fSniklas {
1152159047fSniklas char buf[BUFSIZ];
1162159047fSniklas
1172159047fSniklas sprintf (buf, "[%d]", cyc->cg.index);
1182159047fSniklas printf (bsd_style_output
119b305b0f1Sespie ? "%-6.6s %5.1f %7.2f %11.2f %7lu"
120b305b0f1Sespie : "%-6.6s %5.1f %7.2f %7.2f %7lu", buf,
1212159047fSniklas 100 * (cyc->cg.prop.self + cyc->cg.prop.child) / print_time,
1222159047fSniklas cyc->cg.prop.self / hz, cyc->cg.prop.child / hz, cyc->ncalls);
123b55d4692Sfgsch
1242159047fSniklas if (cyc->cg.self_calls != 0)
125b305b0f1Sespie printf ("+%-7lu", cyc->cg.self_calls);
1262159047fSniklas else
1272159047fSniklas printf (" %7.7s", "");
128b55d4692Sfgsch
129b305b0f1Sespie printf (_(" <cycle %d as a whole> [%d]\n"), cyc->cg.cyc.num, cyc->cg.index);
1302159047fSniklas }
1312159047fSniklas
132b55d4692Sfgsch /* Compare LEFT and RIGHT membmer. Major comparison key is
133b55d4692Sfgsch CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS. */
1342159047fSniklas
1352159047fSniklas static int
cmp_member(left,right)136*c074d1c9Sdrahn cmp_member (left, right)
137*c074d1c9Sdrahn Sym *left;
138*c074d1c9Sdrahn Sym *right;
1392159047fSniklas {
1402159047fSniklas double left_time = left->cg.prop.self + left->cg.prop.child;
1412159047fSniklas double right_time = right->cg.prop.self + right->cg.prop.child;
142b305b0f1Sespie unsigned long left_calls = left->ncalls + left->cg.self_calls;
143b305b0f1Sespie unsigned long right_calls = right->ncalls + right->cg.self_calls;
1442159047fSniklas
1452159047fSniklas if (left_time > right_time)
1462159047fSniklas return GREATERTHAN;
147b55d4692Sfgsch
1482159047fSniklas if (left_time < right_time)
1492159047fSniklas return LESSTHAN;
1502159047fSniklas
1512159047fSniklas if (left_calls > right_calls)
1522159047fSniklas return GREATERTHAN;
153b55d4692Sfgsch
1542159047fSniklas if (left_calls < right_calls)
1552159047fSniklas return LESSTHAN;
156b55d4692Sfgsch
1572159047fSniklas return EQUALTO;
1582159047fSniklas }
1592159047fSniklas
160b55d4692Sfgsch /* Sort members of a cycle. */
1612159047fSniklas
1622159047fSniklas static void
sort_members(cyc)163*c074d1c9Sdrahn sort_members (cyc)
164*c074d1c9Sdrahn Sym *cyc;
1652159047fSniklas {
1662159047fSniklas Sym *todo, *doing, *prev;
167b55d4692Sfgsch
168b55d4692Sfgsch /* Detach cycle members from cyclehead,
169b55d4692Sfgsch and insertion sort them back on. */
1702159047fSniklas todo = cyc->cg.cyc.next;
1712159047fSniklas cyc->cg.cyc.next = 0;
172b55d4692Sfgsch
1732159047fSniklas for (doing = todo; doing && doing->cg.cyc.next; doing = todo)
1742159047fSniklas {
1752159047fSniklas todo = doing->cg.cyc.next;
176b55d4692Sfgsch
1772159047fSniklas for (prev = cyc; prev->cg.cyc.next; prev = prev->cg.cyc.next)
1782159047fSniklas {
1792159047fSniklas if (cmp_member (doing, prev->cg.cyc.next) == GREATERTHAN)
1802159047fSniklas break;
1812159047fSniklas }
182b55d4692Sfgsch
1832159047fSniklas doing->cg.cyc.next = prev->cg.cyc.next;
1842159047fSniklas prev->cg.cyc.next = doing;
1852159047fSniklas }
1862159047fSniklas }
1872159047fSniklas
188b55d4692Sfgsch /* Print the members of a cycle. */
1892159047fSniklas
1902159047fSniklas static void
print_members(cyc)191*c074d1c9Sdrahn print_members (cyc)
192*c074d1c9Sdrahn Sym *cyc;
1932159047fSniklas {
1942159047fSniklas Sym *member;
1952159047fSniklas
1962159047fSniklas sort_members (cyc);
197b55d4692Sfgsch
1982159047fSniklas for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next)
1992159047fSniklas {
2002159047fSniklas printf (bsd_style_output
201b305b0f1Sespie ? "%6.6s %5.5s %7.2f %11.2f %7lu"
202b305b0f1Sespie : "%6.6s %5.5s %7.2f %7.2f %7lu",
2032159047fSniklas "", "", member->cg.prop.self / hz, member->cg.prop.child / hz,
2042159047fSniklas member->ncalls);
205b55d4692Sfgsch
2062159047fSniklas if (member->cg.self_calls != 0)
207b305b0f1Sespie printf ("+%-7lu", member->cg.self_calls);
2082159047fSniklas else
2092159047fSniklas printf (" %7.7s", "");
210b55d4692Sfgsch
2112159047fSniklas printf (" ");
2122159047fSniklas print_name (member);
2132159047fSniklas printf ("\n");
2142159047fSniklas }
2152159047fSniklas }
2162159047fSniklas
217b55d4692Sfgsch /* Compare two arcs to/from the same child/parent.
218b55d4692Sfgsch - if one arc is a self arc, it's least.
219b55d4692Sfgsch - if one arc is within a cycle, it's less than.
220b55d4692Sfgsch - if both arcs are within a cycle, compare arc counts.
221b55d4692Sfgsch - if neither arc is within a cycle, compare with
222b55d4692Sfgsch time + child_time as major key
223b55d4692Sfgsch arc count as minor key. */
2242159047fSniklas
2252159047fSniklas static int
cmp_arc(left,right)226*c074d1c9Sdrahn cmp_arc (left, right)
227*c074d1c9Sdrahn Arc *left;
228*c074d1c9Sdrahn Arc *right;
2292159047fSniklas {
2302159047fSniklas Sym *left_parent = left->parent;
2312159047fSniklas Sym *left_child = left->child;
2322159047fSniklas Sym *right_parent = right->parent;
2332159047fSniklas Sym *right_child = right->child;
2342159047fSniklas double left_time, right_time;
2352159047fSniklas
2362159047fSniklas DBG (TIMEDEBUG,
2372159047fSniklas printf ("[cmp_arc] ");
2382159047fSniklas print_name (left_parent);
2392159047fSniklas printf (" calls ");
2402159047fSniklas print_name (left_child);
241b305b0f1Sespie printf (" %f + %f %lu/%lu\n", left->time, left->child_time,
2422159047fSniklas left->count, left_child->ncalls);
2432159047fSniklas printf ("[cmp_arc] ");
2442159047fSniklas print_name (right_parent);
2452159047fSniklas printf (" calls ");
2462159047fSniklas print_name (right_child);
247b305b0f1Sespie printf (" %f + %f %lu/%lu\n", right->time, right->child_time,
2482159047fSniklas right->count, right_child->ncalls);
2492159047fSniklas printf ("\n");
2502159047fSniklas );
251b55d4692Sfgsch
2522159047fSniklas if (left_parent == left_child)
253b55d4692Sfgsch return LESSTHAN; /* Left is a self call. */
254b55d4692Sfgsch
2552159047fSniklas if (right_parent == right_child)
256b55d4692Sfgsch return GREATERTHAN; /* Right is a self call. */
2572159047fSniklas
2582159047fSniklas if (left_parent->cg.cyc.num != 0 && left_child->cg.cyc.num != 0
2592159047fSniklas && left_parent->cg.cyc.num == left_child->cg.cyc.num)
2602159047fSniklas {
261b55d4692Sfgsch /* Left is a call within a cycle. */
2622159047fSniklas if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
2632159047fSniklas && right_parent->cg.cyc.num == right_child->cg.cyc.num)
2642159047fSniklas {
265b55d4692Sfgsch /* Right is a call within the cycle, too. */
2662159047fSniklas if (left->count < right->count)
2672159047fSniklas return LESSTHAN;
268b55d4692Sfgsch
2692159047fSniklas if (left->count > right->count)
2702159047fSniklas return GREATERTHAN;
271b55d4692Sfgsch
2722159047fSniklas return EQUALTO;
2732159047fSniklas }
2742159047fSniklas else
2752159047fSniklas {
276b55d4692Sfgsch /* Right isn't a call within the cycle. */
2772159047fSniklas return LESSTHAN;
2782159047fSniklas }
2792159047fSniklas }
2802159047fSniklas else
2812159047fSniklas {
282b55d4692Sfgsch /* Left isn't a call within a cycle. */
2832159047fSniklas if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
2842159047fSniklas && right_parent->cg.cyc.num == right_child->cg.cyc.num)
2852159047fSniklas {
286b55d4692Sfgsch /* Right is a call within a cycle. */
2872159047fSniklas return GREATERTHAN;
2882159047fSniklas }
2892159047fSniklas else
2902159047fSniklas {
291b55d4692Sfgsch /* Neither is a call within a cycle. */
2922159047fSniklas left_time = left->time + left->child_time;
2932159047fSniklas right_time = right->time + right->child_time;
294b55d4692Sfgsch
2952159047fSniklas if (left_time < right_time)
2962159047fSniklas return LESSTHAN;
297b55d4692Sfgsch
2982159047fSniklas if (left_time > right_time)
2992159047fSniklas return GREATERTHAN;
300b55d4692Sfgsch
3012159047fSniklas if (left->count < right->count)
3022159047fSniklas return LESSTHAN;
303b55d4692Sfgsch
3042159047fSniklas if (left->count > right->count)
3052159047fSniklas return GREATERTHAN;
306b55d4692Sfgsch
3072159047fSniklas return EQUALTO;
3082159047fSniklas }
3092159047fSniklas }
3102159047fSniklas }
3112159047fSniklas
3122159047fSniklas
3132159047fSniklas static void
sort_parents(child)314*c074d1c9Sdrahn sort_parents (child)
315*c074d1c9Sdrahn Sym * child;
3162159047fSniklas {
3172159047fSniklas Arc *arc, *detached, sorted, *prev;
3182159047fSniklas
319b55d4692Sfgsch /* Unlink parents from child, then insertion sort back on to
320b55d4692Sfgsch sorted's parents.
321b55d4692Sfgsch *arc the arc you have detached and are inserting.
322b55d4692Sfgsch *detached the rest of the arcs to be sorted.
323b55d4692Sfgsch sorted arc list onto which you insertion sort.
324b55d4692Sfgsch *prev arc before the arc you are comparing. */
3252159047fSniklas sorted.next_parent = 0;
326b55d4692Sfgsch
3272159047fSniklas for (arc = child->cg.parents; arc; arc = detached)
3282159047fSniklas {
3292159047fSniklas detached = arc->next_parent;
3302159047fSniklas
331b55d4692Sfgsch /* Consider *arc as disconnected; insert it into sorted. */
3322159047fSniklas for (prev = &sorted; prev->next_parent; prev = prev->next_parent)
3332159047fSniklas {
3342159047fSniklas if (cmp_arc (arc, prev->next_parent) != GREATERTHAN)
3352159047fSniklas break;
3362159047fSniklas }
337b55d4692Sfgsch
3382159047fSniklas arc->next_parent = prev->next_parent;
3392159047fSniklas prev->next_parent = arc;
3402159047fSniklas }
3412159047fSniklas
342b55d4692Sfgsch /* Reattach sorted arcs to child. */
3432159047fSniklas child->cg.parents = sorted.next_parent;
3442159047fSniklas }
3452159047fSniklas
3462159047fSniklas
3472159047fSniklas static void
print_parents(child)348*c074d1c9Sdrahn print_parents (child)
349*c074d1c9Sdrahn Sym *child;
3502159047fSniklas {
3512159047fSniklas Sym *parent;
3522159047fSniklas Arc *arc;
3532159047fSniklas Sym *cycle_head;
3542159047fSniklas
3552159047fSniklas if (child->cg.cyc.head != 0)
3562159047fSniklas cycle_head = child->cg.cyc.head;
3572159047fSniklas else
3582159047fSniklas cycle_head = child;
359b55d4692Sfgsch
3602159047fSniklas if (!child->cg.parents)
3612159047fSniklas {
3622159047fSniklas printf (bsd_style_output
363b305b0f1Sespie ? _("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n")
364b305b0f1Sespie : _("%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n"),
3652159047fSniklas "", "", "", "", "", "");
3662159047fSniklas return;
3672159047fSniklas }
368b55d4692Sfgsch
3692159047fSniklas sort_parents (child);
370b55d4692Sfgsch
3712159047fSniklas for (arc = child->cg.parents; arc; arc = arc->next_parent)
3722159047fSniklas {
3732159047fSniklas parent = arc->parent;
3742159047fSniklas if (child == parent || (child->cg.cyc.num != 0
3752159047fSniklas && parent->cg.cyc.num == child->cg.cyc.num))
3762159047fSniklas {
377b55d4692Sfgsch /* Selfcall or call among siblings. */
3782159047fSniklas printf (bsd_style_output
379b305b0f1Sespie ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
380b305b0f1Sespie : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
3812159047fSniklas "", "", "", "",
3822159047fSniklas arc->count, "");
3832159047fSniklas print_name (parent);
3842159047fSniklas printf ("\n");
3852159047fSniklas }
3862159047fSniklas else
3872159047fSniklas {
388b55d4692Sfgsch /* Regular parent of child. */
3892159047fSniklas printf (bsd_style_output
390b305b0f1Sespie ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
391b305b0f1Sespie : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
3922159047fSniklas "", "",
3932159047fSniklas arc->time / hz, arc->child_time / hz,
3942159047fSniklas arc->count, cycle_head->ncalls);
3952159047fSniklas print_name (parent);
3962159047fSniklas printf ("\n");
3972159047fSniklas }
3982159047fSniklas }
3992159047fSniklas }
4002159047fSniklas
4012159047fSniklas
4022159047fSniklas static void
sort_children(parent)403*c074d1c9Sdrahn sort_children (parent)
404*c074d1c9Sdrahn Sym *parent;
4052159047fSniklas {
4062159047fSniklas Arc *arc, *detached, sorted, *prev;
407b55d4692Sfgsch
408b55d4692Sfgsch /* Unlink children from parent, then insertion sort back on to
409b55d4692Sfgsch sorted's children.
410b55d4692Sfgsch *arc the arc you have detached and are inserting.
411b55d4692Sfgsch *detached the rest of the arcs to be sorted.
412b55d4692Sfgsch sorted arc list onto which you insertion sort.
413b55d4692Sfgsch *prev arc before the arc you are comparing. */
4142159047fSniklas sorted.next_child = 0;
415b55d4692Sfgsch
4162159047fSniklas for (arc = parent->cg.children; arc; arc = detached)
4172159047fSniklas {
4182159047fSniklas detached = arc->next_child;
4192159047fSniklas
420b55d4692Sfgsch /* Consider *arc as disconnected; insert it into sorted. */
4212159047fSniklas for (prev = &sorted; prev->next_child; prev = prev->next_child)
4222159047fSniklas {
4232159047fSniklas if (cmp_arc (arc, prev->next_child) != LESSTHAN)
4242159047fSniklas break;
4252159047fSniklas }
426b55d4692Sfgsch
4272159047fSniklas arc->next_child = prev->next_child;
4282159047fSniklas prev->next_child = arc;
4292159047fSniklas }
4302159047fSniklas
431b55d4692Sfgsch /* Reattach sorted children to parent. */
4322159047fSniklas parent->cg.children = sorted.next_child;
4332159047fSniklas }
4342159047fSniklas
4352159047fSniklas
4362159047fSniklas static void
print_children(parent)437*c074d1c9Sdrahn print_children (parent)
438*c074d1c9Sdrahn Sym *parent;
4392159047fSniklas {
4402159047fSniklas Sym *child;
4412159047fSniklas Arc *arc;
4422159047fSniklas
4432159047fSniklas sort_children (parent);
4442159047fSniklas arc = parent->cg.children;
445b55d4692Sfgsch
4462159047fSniklas for (arc = parent->cg.children; arc; arc = arc->next_child)
4472159047fSniklas {
4482159047fSniklas child = arc->child;
4492159047fSniklas if (child == parent || (child->cg.cyc.num != 0
4502159047fSniklas && child->cg.cyc.num == parent->cg.cyc.num))
4512159047fSniklas {
452b55d4692Sfgsch /* Self call or call to sibling. */
4532159047fSniklas printf (bsd_style_output
454b305b0f1Sespie ? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
455b305b0f1Sespie : "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
4562159047fSniklas "", "", "", "", arc->count, "");
4572159047fSniklas print_name (child);
4582159047fSniklas printf ("\n");
4592159047fSniklas }
4602159047fSniklas else
4612159047fSniklas {
462b55d4692Sfgsch /* Regular child of parent. */
4632159047fSniklas printf (bsd_style_output
464b305b0f1Sespie ? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
465b305b0f1Sespie : "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
4662159047fSniklas "", "",
4672159047fSniklas arc->time / hz, arc->child_time / hz,
4682159047fSniklas arc->count, child->cg.cyc.head->ncalls);
4692159047fSniklas print_name (child);
4702159047fSniklas printf ("\n");
4712159047fSniklas }
4722159047fSniklas }
4732159047fSniklas }
4742159047fSniklas
4752159047fSniklas
4762159047fSniklas static void
print_line(np)477*c074d1c9Sdrahn print_line (np)
478*c074d1c9Sdrahn Sym *np;
4792159047fSniklas {
4802159047fSniklas char buf[BUFSIZ];
4812159047fSniklas
4822159047fSniklas sprintf (buf, "[%d]", np->cg.index);
4832159047fSniklas printf (bsd_style_output
4842159047fSniklas ? "%-6.6s %5.1f %7.2f %11.2f"
4852159047fSniklas : "%-6.6s %5.1f %7.2f %7.2f", buf,
4862159047fSniklas 100 * (np->cg.prop.self + np->cg.prop.child) / print_time,
4872159047fSniklas np->cg.prop.self / hz, np->cg.prop.child / hz);
488b55d4692Sfgsch
4892159047fSniklas if ((np->ncalls + np->cg.self_calls) != 0)
4902159047fSniklas {
491b305b0f1Sespie printf (" %7lu", np->ncalls);
492b55d4692Sfgsch
4932159047fSniklas if (np->cg.self_calls != 0)
494b305b0f1Sespie printf ("+%-7lu ", np->cg.self_calls);
4952159047fSniklas else
4962159047fSniklas printf (" %7.7s ", "");
4972159047fSniklas }
4982159047fSniklas else
4992159047fSniklas {
5002159047fSniklas printf (" %7.7s %7.7s ", "", "");
5012159047fSniklas }
502b55d4692Sfgsch
5032159047fSniklas print_name (np);
5042159047fSniklas printf ("\n");
5052159047fSniklas }
5062159047fSniklas
5072159047fSniklas
508b55d4692Sfgsch /* Print dynamic call graph. */
509b55d4692Sfgsch
5102159047fSniklas void
cg_print(timesortsym)511*c074d1c9Sdrahn cg_print (timesortsym)
512*c074d1c9Sdrahn Sym ** timesortsym;
5132159047fSniklas {
514b305b0f1Sespie unsigned int index;
5152159047fSniklas Sym *parent;
5162159047fSniklas
5172159047fSniklas if (print_descriptions && bsd_style_output)
5182159047fSniklas bsd_callg_blurb (stdout);
5192159047fSniklas
5202159047fSniklas print_header ();
5212159047fSniklas
5222159047fSniklas for (index = 0; index < symtab.len + num_cycles; ++index)
5232159047fSniklas {
5242159047fSniklas parent = timesortsym[index];
525b55d4692Sfgsch
5262159047fSniklas if ((ignore_zeros && parent->ncalls == 0
5272159047fSniklas && parent->cg.self_calls == 0 && parent->cg.prop.self == 0
5282159047fSniklas && parent->cg.prop.child == 0)
529b305b0f1Sespie || !parent->cg.print_flag
530b305b0f1Sespie || (line_granularity && ! parent->is_func))
5312159047fSniklas continue;
532b55d4692Sfgsch
5332159047fSniklas if (!parent->name && parent->cg.cyc.num != 0)
5342159047fSniklas {
535b55d4692Sfgsch /* Cycle header. */
5362159047fSniklas print_cycle (parent);
5372159047fSniklas print_members (parent);
5382159047fSniklas }
5392159047fSniklas else
5402159047fSniklas {
5412159047fSniklas print_parents (parent);
5422159047fSniklas print_line (parent);
5432159047fSniklas print_children (parent);
5442159047fSniklas }
545b55d4692Sfgsch
5462159047fSniklas if (bsd_style_output)
5472159047fSniklas printf ("\n");
548b55d4692Sfgsch
5492159047fSniklas printf ("-----------------------------------------------\n");
550b55d4692Sfgsch
5512159047fSniklas if (bsd_style_output)
5522159047fSniklas printf ("\n");
5532159047fSniklas }
554b55d4692Sfgsch
5552159047fSniklas free (timesortsym);
556b55d4692Sfgsch
5572159047fSniklas if (print_descriptions && !bsd_style_output)
5582159047fSniklas fsf_callg_blurb (stdout);
5592159047fSniklas }
5602159047fSniklas
5612159047fSniklas
5622159047fSniklas static int
cmp_name(left,right)563*c074d1c9Sdrahn cmp_name (left, right)
564*c074d1c9Sdrahn const PTR left;
565*c074d1c9Sdrahn const PTR right;
5662159047fSniklas {
5672159047fSniklas const Sym **npp1 = (const Sym **) left;
5682159047fSniklas const Sym **npp2 = (const Sym **) right;
5692159047fSniklas
5702159047fSniklas return strcmp ((*npp1)->name, (*npp2)->name);
5712159047fSniklas }
5722159047fSniklas
5732159047fSniklas
5742159047fSniklas void
cg_print_index()575*c074d1c9Sdrahn cg_print_index ()
5762159047fSniklas {
577b305b0f1Sespie unsigned int index;
578b305b0f1Sespie unsigned int nnames, todo, i, j;
579b305b0f1Sespie int col, starting_col;
5802159047fSniklas Sym **name_sorted_syms, *sym;
5812159047fSniklas const char *filename;
5822159047fSniklas char buf[20];
583b55d4692Sfgsch int column_width = (output_width - 1) / 3; /* Don't write in last col! */
584b55d4692Sfgsch
585b55d4692Sfgsch /* Now, sort regular function name
586b55d4692Sfgsch alphabetically to create an index. */
5872159047fSniklas name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
588b55d4692Sfgsch
5892159047fSniklas for (index = 0, nnames = 0; index < symtab.len; index++)
5902159047fSniklas {
5912159047fSniklas if (ignore_zeros && symtab.base[index].ncalls == 0
5922159047fSniklas && symtab.base[index].hist.time == 0)
5932159047fSniklas continue;
594b55d4692Sfgsch
5952159047fSniklas name_sorted_syms[nnames++] = &symtab.base[index];
5962159047fSniklas }
597b55d4692Sfgsch
5982159047fSniklas qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
599b55d4692Sfgsch
6002159047fSniklas for (index = 1, todo = nnames; index <= num_cycles; index++)
6012159047fSniklas name_sorted_syms[todo++] = &cycle_header[index];
602b55d4692Sfgsch
603b305b0f1Sespie printf ("\f\n");
604b305b0f1Sespie printf (_("Index by function name\n\n"));
6052159047fSniklas index = (todo + 2) / 3;
606b55d4692Sfgsch
6072159047fSniklas for (i = 0; i < index; i++)
6082159047fSniklas {
6092159047fSniklas col = 0;
6102159047fSniklas starting_col = 0;
611b55d4692Sfgsch
6122159047fSniklas for (j = i; j < todo; j += index)
6132159047fSniklas {
6142159047fSniklas sym = name_sorted_syms[j];
615b55d4692Sfgsch
6162159047fSniklas if (sym->cg.print_flag)
6172159047fSniklas sprintf (buf, "[%d]", sym->cg.index);
6182159047fSniklas else
6192159047fSniklas sprintf (buf, "(%d)", sym->cg.index);
620b55d4692Sfgsch
6212159047fSniklas if (j < nnames)
6222159047fSniklas {
6232159047fSniklas if (bsd_style_output)
6242159047fSniklas {
6252159047fSniklas printf ("%6.6s %-19.19s", buf, sym->name);
6262159047fSniklas }
6272159047fSniklas else
6282159047fSniklas {
6292159047fSniklas col += strlen (buf);
630b55d4692Sfgsch
6312159047fSniklas for (; col < starting_col + 5; ++col)
6322159047fSniklas putchar (' ');
633b55d4692Sfgsch
6342159047fSniklas printf (" %s ", buf);
6352159047fSniklas col += print_name_only (sym);
636b55d4692Sfgsch
6372159047fSniklas if (!line_granularity && sym->is_static && sym->file)
6382159047fSniklas {
6392159047fSniklas filename = sym->file->name;
640b55d4692Sfgsch
6412159047fSniklas if (!print_path)
6422159047fSniklas {
6432159047fSniklas filename = strrchr (filename, '/');
644b55d4692Sfgsch
6452159047fSniklas if (filename)
6462159047fSniklas ++filename;
6472159047fSniklas else
6482159047fSniklas filename = sym->file->name;
6492159047fSniklas }
650b55d4692Sfgsch
6512159047fSniklas printf (" (%s)", filename);
6522159047fSniklas col += strlen (filename) + 3;
6532159047fSniklas }
6542159047fSniklas }
6552159047fSniklas }
6562159047fSniklas else
6572159047fSniklas {
6582159047fSniklas if (bsd_style_output)
6592159047fSniklas {
6602159047fSniklas printf ("%6.6s ", buf);
661b305b0f1Sespie sprintf (buf, _("<cycle %d>"), sym->cg.cyc.num);
6622159047fSniklas printf ("%-19.19s", buf);
6632159047fSniklas }
6642159047fSniklas else
6652159047fSniklas {
6662159047fSniklas col += strlen (buf);
6672159047fSniklas for (; col < starting_col + 5; ++col)
6682159047fSniklas putchar (' ');
6692159047fSniklas printf (" %s ", buf);
670b305b0f1Sespie sprintf (buf, _("<cycle %d>"), sym->cg.cyc.num);
6712159047fSniklas printf ("%s", buf);
6722159047fSniklas col += strlen (buf);
6732159047fSniklas }
6742159047fSniklas }
675b55d4692Sfgsch
6762159047fSniklas starting_col += column_width;
6772159047fSniklas }
678b55d4692Sfgsch
6792159047fSniklas printf ("\n");
6802159047fSniklas }
681b55d4692Sfgsch
6822159047fSniklas free (name_sorted_syms);
6832159047fSniklas }
684191aa565Sniklas
685b55d4692Sfgsch /* Compare two arcs based on their usage counts.
686b55d4692Sfgsch We want to sort in descending order. */
687b55d4692Sfgsch
688191aa565Sniklas static int
cmp_arc_count(left,right)689*c074d1c9Sdrahn cmp_arc_count (left, right)
690*c074d1c9Sdrahn const PTR left;
691*c074d1c9Sdrahn const PTR right;
692191aa565Sniklas {
693191aa565Sniklas const Arc **npp1 = (const Arc **) left;
694191aa565Sniklas const Arc **npp2 = (const Arc **) right;
695191aa565Sniklas
696191aa565Sniklas if ((*npp1)->count > (*npp2)->count)
697191aa565Sniklas return -1;
698191aa565Sniklas else if ((*npp1)->count < (*npp2)->count)
699191aa565Sniklas return 1;
700191aa565Sniklas else
701191aa565Sniklas return 0;
702191aa565Sniklas }
703191aa565Sniklas
704b55d4692Sfgsch /* Compare two funtions based on their usage counts.
705b55d4692Sfgsch We want to sort in descending order. */
706b55d4692Sfgsch
707191aa565Sniklas static int
cmp_fun_nuses(left,right)708*c074d1c9Sdrahn cmp_fun_nuses (left, right)
709*c074d1c9Sdrahn const PTR left;
710*c074d1c9Sdrahn const PTR right;
711191aa565Sniklas {
712191aa565Sniklas const Sym **npp1 = (const Sym **) left;
713191aa565Sniklas const Sym **npp2 = (const Sym **) right;
714191aa565Sniklas
715191aa565Sniklas if ((*npp1)->nuses > (*npp2)->nuses)
716191aa565Sniklas return -1;
717191aa565Sniklas else if ((*npp1)->nuses < (*npp2)->nuses)
718191aa565Sniklas return 1;
719191aa565Sniklas else
720191aa565Sniklas return 0;
721191aa565Sniklas }
722191aa565Sniklas
723191aa565Sniklas /* Print a suggested function ordering based on the profiling data.
724191aa565Sniklas
725191aa565Sniklas We perform 4 major steps when ordering functions:
726191aa565Sniklas
727191aa565Sniklas * Group unused functions together and place them at the
728191aa565Sniklas end of the function order.
729191aa565Sniklas
730191aa565Sniklas * Search the highest use arcs (those which account for 90% of
731191aa565Sniklas the total arc count) for functions which have several parents.
732191aa565Sniklas
733191aa565Sniklas Group those with the most call sites together (currently the
734191aa565Sniklas top 1.25% which have at least five different call sites).
735191aa565Sniklas
736191aa565Sniklas These are emitted at the start of the function order.
737191aa565Sniklas
738191aa565Sniklas * Use a greedy placement algorithm to place functions which
739191aa565Sniklas occur in the top 99% of the arcs in the profile. Some provisions
740191aa565Sniklas are made to handle high usage arcs where the parent and/or
741191aa565Sniklas child has already been placed.
742191aa565Sniklas
743191aa565Sniklas * Run the same greedy placement algorithm on the remaining
744191aa565Sniklas arcs to place the leftover functions.
745191aa565Sniklas
746191aa565Sniklas
747191aa565Sniklas The various "magic numbers" should (one day) be tuneable by command
748191aa565Sniklas line options. They were arrived at by benchmarking a few applications
749191aa565Sniklas with various values to see which values produced better overall function
750191aa565Sniklas orderings.
751191aa565Sniklas
752191aa565Sniklas Of course, profiling errors, machine limitations (PA long calls), and
753191aa565Sniklas poor cutoff values for the placement algorithm may limit the usefullness
754191aa565Sniklas of the resulting function order. Improvements would be greatly appreciated.
755191aa565Sniklas
756191aa565Sniklas Suggestions:
757191aa565Sniklas
758191aa565Sniklas * Place the functions with many callers near the middle of the
759191aa565Sniklas list to reduce long calls.
760191aa565Sniklas
761191aa565Sniklas * Propagate arc usage changes as functions are placed. Ie if
762191aa565Sniklas func1 and func2 are placed together, arcs to/from those arcs
763191aa565Sniklas to the same parent/child should be combined, then resort the
764191aa565Sniklas arcs to choose the next one.
765191aa565Sniklas
766191aa565Sniklas * Implement some global positioning algorithm to place the
767191aa565Sniklas chains made by the greedy local positioning algorithm. Probably
768191aa565Sniklas by examining arcs which haven't been placed yet to tie two
769191aa565Sniklas chains together.
770191aa565Sniklas
771191aa565Sniklas * Take a function's size and time into account in the algorithm;
772191aa565Sniklas size in particular is important on the PA (long calls). Placing
773191aa565Sniklas many small functions onto their own page may be wise.
774191aa565Sniklas
775191aa565Sniklas * Use better profiling information; many published algorithms
776191aa565Sniklas are based on call sequences through time, rather than just
777191aa565Sniklas arc counts.
778191aa565Sniklas
779191aa565Sniklas * Prodecure cloning could improve performance when a small number
780191aa565Sniklas of arcs account for most of the calls to a particular function.
781191aa565Sniklas
782191aa565Sniklas * Use relocation information to avoid moving unused functions
783191aa565Sniklas completely out of the code stream; this would avoid severe lossage
784191aa565Sniklas when the profile data bears little resemblance to actual runs.
785191aa565Sniklas
786191aa565Sniklas * Propagation of arc usages should also improve .o link line
787191aa565Sniklas ordering which shares the same arc placement algorithm with
788191aa565Sniklas the function ordering code (in fact it is a degenerate case
789191aa565Sniklas of function ordering). */
790191aa565Sniklas
791191aa565Sniklas void
cg_print_function_ordering()792*c074d1c9Sdrahn cg_print_function_ordering ()
793191aa565Sniklas {
794191aa565Sniklas unsigned long index, used, unused, scratch_index;
795191aa565Sniklas unsigned long unplaced_arc_count, high_arc_count, scratch_arc_count;
796191aa565Sniklas #ifdef __GNUC__
797191aa565Sniklas unsigned long long total_arcs, tmp_arcs_count;
798191aa565Sniklas #else
799191aa565Sniklas unsigned long total_arcs, tmp_arcs_count;
800191aa565Sniklas #endif
801191aa565Sniklas Sym **unused_syms, **used_syms, **scratch_syms;
802191aa565Sniklas Arc **unplaced_arcs, **high_arcs, **scratch_arcs;
803191aa565Sniklas
804191aa565Sniklas index = 0;
805191aa565Sniklas used = 0;
806191aa565Sniklas unused = 0;
807191aa565Sniklas scratch_index = 0;
808191aa565Sniklas unplaced_arc_count = 0;
809191aa565Sniklas high_arc_count = 0;
810191aa565Sniklas scratch_arc_count = 0;
811191aa565Sniklas
812191aa565Sniklas /* First group all the unused functions together. */
813191aa565Sniklas unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
814191aa565Sniklas used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
815191aa565Sniklas scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
816191aa565Sniklas high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
817191aa565Sniklas scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
818191aa565Sniklas unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
819191aa565Sniklas
820191aa565Sniklas /* Walk through all the functions; mark those which are never
821191aa565Sniklas called as placed (we'll emit them as a group later). */
822191aa565Sniklas for (index = 0, used = 0, unused = 0; index < symtab.len; index++)
823191aa565Sniklas {
824191aa565Sniklas if (symtab.base[index].ncalls == 0)
825191aa565Sniklas {
826191aa565Sniklas /* Filter out gprof generated names. */
827191aa565Sniklas if (strcmp (symtab.base[index].name, "<locore>")
828191aa565Sniklas && strcmp (symtab.base[index].name, "<hicore>"))
829191aa565Sniklas {
830191aa565Sniklas unused_syms[unused++] = &symtab.base[index];
831191aa565Sniklas symtab.base[index].has_been_placed = 1;
832191aa565Sniklas }
833191aa565Sniklas }
834191aa565Sniklas else
835191aa565Sniklas {
836191aa565Sniklas used_syms[used++] = &symtab.base[index];
837191aa565Sniklas symtab.base[index].has_been_placed = 0;
838191aa565Sniklas symtab.base[index].next = 0;
839191aa565Sniklas symtab.base[index].prev = 0;
840191aa565Sniklas symtab.base[index].nuses = 0;
841191aa565Sniklas }
842191aa565Sniklas }
843191aa565Sniklas
844191aa565Sniklas /* Sort the arcs from most used to least used. */
845191aa565Sniklas qsort (arcs, numarcs, sizeof (Arc *), cmp_arc_count);
846191aa565Sniklas
847191aa565Sniklas /* Compute the total arc count. Also mark arcs as unplaced.
848191aa565Sniklas
849191aa565Sniklas Note we don't compensate for overflow if that happens!
850191aa565Sniklas Overflow is much less likely when this file is compiled
851191aa565Sniklas with GCC as it can double-wide integers via long long. */
852191aa565Sniklas total_arcs = 0;
853191aa565Sniklas for (index = 0; index < numarcs; index++)
854191aa565Sniklas {
855191aa565Sniklas total_arcs += arcs[index]->count;
856191aa565Sniklas arcs[index]->has_been_placed = 0;
857191aa565Sniklas }
858191aa565Sniklas
859191aa565Sniklas /* We want to pull out those functions which are referenced
860191aa565Sniklas by many highly used arcs and emit them as a group. This
861191aa565Sniklas could probably use some tuning. */
862191aa565Sniklas tmp_arcs_count = 0;
863191aa565Sniklas for (index = 0; index < numarcs; index++)
864191aa565Sniklas {
865191aa565Sniklas tmp_arcs_count += arcs[index]->count;
866191aa565Sniklas
867191aa565Sniklas /* Count how many times each parent and child are used up
868191aa565Sniklas to our threshhold of arcs (90%). */
869191aa565Sniklas if ((double)tmp_arcs_count / (double)total_arcs > 0.90)
870191aa565Sniklas break;
871191aa565Sniklas
872191aa565Sniklas arcs[index]->child->nuses++;
873191aa565Sniklas }
874191aa565Sniklas
875191aa565Sniklas /* Now sort a temporary symbol table based on the number of
876191aa565Sniklas times each function was used in the highest used arcs. */
877191aa565Sniklas memcpy (scratch_syms, used_syms, used * sizeof (Sym *));
878191aa565Sniklas qsort (scratch_syms, used, sizeof (Sym *), cmp_fun_nuses);
879191aa565Sniklas
880191aa565Sniklas /* Now pick out those symbols we're going to emit as
881191aa565Sniklas a group. We take up to 1.25% of the used symbols. */
882191aa565Sniklas for (index = 0; index < used / 80; index++)
883191aa565Sniklas {
884191aa565Sniklas Sym *sym = scratch_syms[index];
885191aa565Sniklas Arc *arc;
886191aa565Sniklas
887191aa565Sniklas /* If we hit symbols that aren't used from many call sites,
888191aa565Sniklas then we can quit. We choose five as the low limit for
889191aa565Sniklas no particular reason. */
890191aa565Sniklas if (sym->nuses == 5)
891191aa565Sniklas break;
892191aa565Sniklas
893191aa565Sniklas /* We're going to need the arcs between these functions.
894191aa565Sniklas Unfortunately, we don't know all these functions
895191aa565Sniklas until we're done. So we keep track of all the arcs
896191aa565Sniklas to the functions we care about, then prune out those
897191aa565Sniklas which are uninteresting.
898191aa565Sniklas
899191aa565Sniklas An interesting variation would be to quit when we found
900191aa565Sniklas multi-call site functions which account for some percentage
901191aa565Sniklas of the arcs. */
902191aa565Sniklas arc = sym->cg.children;
903b55d4692Sfgsch
904191aa565Sniklas while (arc)
905191aa565Sniklas {
906191aa565Sniklas if (arc->parent != arc->child)
907191aa565Sniklas scratch_arcs[scratch_arc_count++] = arc;
908191aa565Sniklas arc->has_been_placed = 1;
909191aa565Sniklas arc = arc->next_child;
910191aa565Sniklas }
911191aa565Sniklas
912191aa565Sniklas arc = sym->cg.parents;
913b55d4692Sfgsch
914191aa565Sniklas while (arc)
915191aa565Sniklas {
916191aa565Sniklas if (arc->parent != arc->child)
917191aa565Sniklas scratch_arcs[scratch_arc_count++] = arc;
918191aa565Sniklas arc->has_been_placed = 1;
919191aa565Sniklas arc = arc->next_parent;
920191aa565Sniklas }
921191aa565Sniklas
922191aa565Sniklas /* Keep track of how many symbols we're going to place. */
923191aa565Sniklas scratch_index = index;
924191aa565Sniklas
925b55d4692Sfgsch /* A lie, but it makes identifying
926b55d4692Sfgsch these functions easier later. */
927191aa565Sniklas sym->has_been_placed = 1;
928191aa565Sniklas }
929191aa565Sniklas
930b55d4692Sfgsch /* Now walk through the temporary arcs and copy
931b55d4692Sfgsch those we care about into the high arcs array. */
932191aa565Sniklas for (index = 0; index < scratch_arc_count; index++)
933191aa565Sniklas {
934191aa565Sniklas Arc *arc = scratch_arcs[index];
935191aa565Sniklas
936191aa565Sniklas /* If this arc refers to highly used functions, then
937191aa565Sniklas then we want to keep it. */
938191aa565Sniklas if (arc->child->has_been_placed
939191aa565Sniklas && arc->parent->has_been_placed)
940191aa565Sniklas {
941191aa565Sniklas high_arcs[high_arc_count++] = scratch_arcs[index];
942191aa565Sniklas
943191aa565Sniklas /* We need to turn of has_been_placed since we're going to
944191aa565Sniklas use the main arc placement algorithm on these arcs. */
945191aa565Sniklas arc->child->has_been_placed = 0;
946191aa565Sniklas arc->parent->has_been_placed = 0;
947191aa565Sniklas }
948191aa565Sniklas }
949191aa565Sniklas
950b55d4692Sfgsch /* Dump the multi-site high usage functions which are not
951b55d4692Sfgsch going to be ordered by the main ordering algorithm. */
952191aa565Sniklas for (index = 0; index < scratch_index; index++)
953191aa565Sniklas {
954191aa565Sniklas if (scratch_syms[index]->has_been_placed)
955191aa565Sniklas printf ("%s\n", scratch_syms[index]->name);
956191aa565Sniklas }
957191aa565Sniklas
958b55d4692Sfgsch /* Now we can order the multi-site high use
959b55d4692Sfgsch functions based on the arcs between them. */
960191aa565Sniklas qsort (high_arcs, high_arc_count, sizeof (Arc *), cmp_arc_count);
961191aa565Sniklas order_and_dump_functions_by_arcs (high_arcs, high_arc_count, 1,
962191aa565Sniklas unplaced_arcs, &unplaced_arc_count);
963191aa565Sniklas
964b55d4692Sfgsch /* Order and dump the high use functions left,
965b55d4692Sfgsch these typically have only a few call sites. */
966191aa565Sniklas order_and_dump_functions_by_arcs (arcs, numarcs, 0,
967191aa565Sniklas unplaced_arcs, &unplaced_arc_count);
968191aa565Sniklas
969191aa565Sniklas /* Now place the rarely used functions. */
970191aa565Sniklas order_and_dump_functions_by_arcs (unplaced_arcs, unplaced_arc_count, 1,
971191aa565Sniklas scratch_arcs, &scratch_arc_count);
972191aa565Sniklas
973191aa565Sniklas /* Output any functions not emitted by the order_and_dump calls. */
974191aa565Sniklas for (index = 0; index < used; index++)
975191aa565Sniklas if (used_syms[index]->has_been_placed == 0)
976191aa565Sniklas printf("%s\n", used_syms[index]->name);
977191aa565Sniklas
978191aa565Sniklas /* Output the unused functions. */
979191aa565Sniklas for (index = 0; index < unused; index++)
980191aa565Sniklas printf("%s\n", unused_syms[index]->name);
981191aa565Sniklas
982191aa565Sniklas unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
983191aa565Sniklas used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
984191aa565Sniklas scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
985191aa565Sniklas high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
986191aa565Sniklas scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
987191aa565Sniklas unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
988191aa565Sniklas
989191aa565Sniklas free (unused_syms);
990191aa565Sniklas free (used_syms);
991191aa565Sniklas free (scratch_syms);
992191aa565Sniklas free (high_arcs);
993191aa565Sniklas free (scratch_arcs);
994191aa565Sniklas free (unplaced_arcs);
995191aa565Sniklas }
996191aa565Sniklas
997*c074d1c9Sdrahn /* Place functions based on the arcs in THE_ARCS with ARC_COUNT entries;
998191aa565Sniklas place unused arcs into UNPLACED_ARCS/UNPLACED_ARC_COUNT.
999191aa565Sniklas
1000*c074d1c9Sdrahn If ALL is nonzero, then place all functions referenced by THE_ARCS,
1001*c074d1c9Sdrahn else only place those referenced in the top 99% of the arcs in THE_ARCS. */
1002191aa565Sniklas
1003191aa565Sniklas #define MOST 0.99
1004191aa565Sniklas static void
order_and_dump_functions_by_arcs(the_arcs,arc_count,all,unplaced_arcs,unplaced_arc_count)1005*c074d1c9Sdrahn order_and_dump_functions_by_arcs (the_arcs, arc_count, all,
1006191aa565Sniklas unplaced_arcs, unplaced_arc_count)
1007*c074d1c9Sdrahn Arc **the_arcs;
1008*c074d1c9Sdrahn unsigned long arc_count;
1009191aa565Sniklas int all;
1010191aa565Sniklas Arc **unplaced_arcs;
1011191aa565Sniklas unsigned long *unplaced_arc_count;
1012191aa565Sniklas {
1013191aa565Sniklas #ifdef __GNUC__
1014191aa565Sniklas unsigned long long tmp_arcs, total_arcs;
1015191aa565Sniklas #else
1016191aa565Sniklas unsigned long tmp_arcs, total_arcs;
1017191aa565Sniklas #endif
1018191aa565Sniklas unsigned int index;
1019191aa565Sniklas
1020191aa565Sniklas /* If needed, compute the total arc count.
1021191aa565Sniklas
1022191aa565Sniklas Note we don't compensate for overflow if that happens! */
1023191aa565Sniklas if (! all)
1024191aa565Sniklas {
1025191aa565Sniklas total_arcs = 0;
1026*c074d1c9Sdrahn for (index = 0; index < arc_count; index++)
1027*c074d1c9Sdrahn total_arcs += the_arcs[index]->count;
1028191aa565Sniklas }
1029191aa565Sniklas else
1030191aa565Sniklas total_arcs = 0;
1031191aa565Sniklas
1032191aa565Sniklas tmp_arcs = 0;
1033b55d4692Sfgsch
1034*c074d1c9Sdrahn for (index = 0; index < arc_count; index++)
1035191aa565Sniklas {
1036191aa565Sniklas Sym *sym1, *sym2;
1037191aa565Sniklas Sym *child, *parent;
1038191aa565Sniklas
1039*c074d1c9Sdrahn tmp_arcs += the_arcs[index]->count;
1040191aa565Sniklas
1041191aa565Sniklas /* Ignore this arc if it's already been placed. */
1042*c074d1c9Sdrahn if (the_arcs[index]->has_been_placed)
1043191aa565Sniklas continue;
1044191aa565Sniklas
1045*c074d1c9Sdrahn child = the_arcs[index]->child;
1046*c074d1c9Sdrahn parent = the_arcs[index]->parent;
1047191aa565Sniklas
1048191aa565Sniklas /* If we're not using all arcs, and this is a rarely used
1049191aa565Sniklas arc, then put it on the unplaced_arc list. Similarly
1050191aa565Sniklas if both the parent and child of this arc have been placed. */
1051191aa565Sniklas if ((! all && (double)tmp_arcs / (double)total_arcs > MOST)
1052191aa565Sniklas || child->has_been_placed || parent->has_been_placed)
1053191aa565Sniklas {
1054*c074d1c9Sdrahn unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1055191aa565Sniklas continue;
1056191aa565Sniklas }
1057191aa565Sniklas
1058191aa565Sniklas /* If all slots in the parent and child are full, then there isn't
1059191aa565Sniklas anything we can do right now. We'll place this arc on the
1060191aa565Sniklas unplaced arc list in the hope that a global positioning
1061191aa565Sniklas algorithm can use it to place function chains. */
1062191aa565Sniklas if (parent->next && parent->prev && child->next && child->prev)
1063191aa565Sniklas {
1064*c074d1c9Sdrahn unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1065191aa565Sniklas continue;
1066191aa565Sniklas }
1067191aa565Sniklas
1068191aa565Sniklas /* If the parent is unattached, then find the closest
1069191aa565Sniklas place to attach it onto child's chain. Similarly
1070191aa565Sniklas for the opposite case. */
1071191aa565Sniklas if (!parent->next && !parent->prev)
1072191aa565Sniklas {
1073191aa565Sniklas int next_count = 0;
1074191aa565Sniklas int prev_count = 0;
1075191aa565Sniklas Sym *prev = child;
1076191aa565Sniklas Sym *next = child;
1077191aa565Sniklas
1078191aa565Sniklas /* Walk to the beginning and end of the child's chain. */
1079191aa565Sniklas while (next->next)
1080191aa565Sniklas {
1081191aa565Sniklas next = next->next;
1082191aa565Sniklas next_count++;
1083191aa565Sniklas }
1084191aa565Sniklas
1085191aa565Sniklas while (prev->prev)
1086191aa565Sniklas {
1087191aa565Sniklas prev = prev->prev;
1088191aa565Sniklas prev_count++;
1089191aa565Sniklas }
1090191aa565Sniklas
1091191aa565Sniklas /* Choose the closest. */
1092191aa565Sniklas child = next_count < prev_count ? next : prev;
1093191aa565Sniklas }
1094191aa565Sniklas else if (! child->next && !child->prev)
1095191aa565Sniklas {
1096191aa565Sniklas int next_count = 0;
1097191aa565Sniklas int prev_count = 0;
1098191aa565Sniklas Sym *prev = parent;
1099191aa565Sniklas Sym *next = parent;
1100191aa565Sniklas
1101191aa565Sniklas while (next->next)
1102191aa565Sniklas {
1103191aa565Sniklas next = next->next;
1104191aa565Sniklas next_count++;
1105191aa565Sniklas }
1106191aa565Sniklas
1107191aa565Sniklas while (prev->prev)
1108191aa565Sniklas {
1109191aa565Sniklas prev = prev->prev;
1110191aa565Sniklas prev_count++;
1111191aa565Sniklas }
1112191aa565Sniklas
1113191aa565Sniklas parent = prev_count < next_count ? prev : next;
1114191aa565Sniklas }
1115191aa565Sniklas else
1116191aa565Sniklas {
1117191aa565Sniklas /* Couldn't find anywhere to attach the functions,
1118191aa565Sniklas put the arc on the unplaced arc list. */
1119*c074d1c9Sdrahn unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1120191aa565Sniklas continue;
1121191aa565Sniklas }
1122191aa565Sniklas
1123191aa565Sniklas /* Make sure we don't tie two ends together. */
1124191aa565Sniklas sym1 = parent;
1125191aa565Sniklas if (sym1->next)
1126191aa565Sniklas while (sym1->next)
1127191aa565Sniklas sym1 = sym1->next;
1128191aa565Sniklas else
1129191aa565Sniklas while (sym1->prev)
1130191aa565Sniklas sym1 = sym1->prev;
1131191aa565Sniklas
1132191aa565Sniklas sym2 = child;
1133191aa565Sniklas if (sym2->next)
1134191aa565Sniklas while (sym2->next)
1135191aa565Sniklas sym2 = sym2->next;
1136191aa565Sniklas else
1137191aa565Sniklas while (sym2->prev)
1138191aa565Sniklas sym2 = sym2->prev;
1139191aa565Sniklas
1140191aa565Sniklas if (sym1 == child
1141191aa565Sniklas && sym2 == parent)
1142191aa565Sniklas {
1143191aa565Sniklas /* This would tie two ends together. */
1144*c074d1c9Sdrahn unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[index];
1145191aa565Sniklas continue;
1146191aa565Sniklas }
1147191aa565Sniklas
1148191aa565Sniklas if (parent->next)
1149191aa565Sniklas {
1150191aa565Sniklas /* Must attach to the parent's prev field. */
1151191aa565Sniklas if (! child->next)
1152191aa565Sniklas {
1153191aa565Sniklas /* parent-prev and child-next */
1154191aa565Sniklas parent->prev = child;
1155191aa565Sniklas child->next = parent;
1156*c074d1c9Sdrahn the_arcs[index]->has_been_placed = 1;
1157191aa565Sniklas }
1158191aa565Sniklas }
1159191aa565Sniklas else if (parent->prev)
1160191aa565Sniklas {
1161191aa565Sniklas /* Must attach to the parent's next field. */
1162191aa565Sniklas if (! child->prev)
1163191aa565Sniklas {
1164191aa565Sniklas /* parent-next and child-prev */
1165191aa565Sniklas parent->next = child;
1166191aa565Sniklas child->prev = parent;
1167*c074d1c9Sdrahn the_arcs[index]->has_been_placed = 1;
1168191aa565Sniklas }
1169191aa565Sniklas }
1170191aa565Sniklas else
1171191aa565Sniklas {
1172191aa565Sniklas /* Can attach to either field in the parent, depends
1173191aa565Sniklas on where we've got space in the child. */
1174191aa565Sniklas if (child->prev)
1175191aa565Sniklas {
1176b55d4692Sfgsch /* parent-prev and child-next. */
1177191aa565Sniklas parent->prev = child;
1178191aa565Sniklas child->next = parent;
1179*c074d1c9Sdrahn the_arcs[index]->has_been_placed = 1;
1180191aa565Sniklas }
1181191aa565Sniklas else
1182191aa565Sniklas {
1183b55d4692Sfgsch /* parent-next and child-prev. */
1184191aa565Sniklas parent->next = child;
1185191aa565Sniklas child->prev = parent;
1186*c074d1c9Sdrahn the_arcs[index]->has_been_placed = 1;
1187191aa565Sniklas }
1188191aa565Sniklas }
1189191aa565Sniklas }
1190191aa565Sniklas
1191191aa565Sniklas /* Dump the chains of functions we've made. */
1192*c074d1c9Sdrahn for (index = 0; index < arc_count; index++)
1193191aa565Sniklas {
1194191aa565Sniklas Sym *sym;
1195*c074d1c9Sdrahn if (the_arcs[index]->parent->has_been_placed
1196*c074d1c9Sdrahn || the_arcs[index]->child->has_been_placed)
1197191aa565Sniklas continue;
1198191aa565Sniklas
1199*c074d1c9Sdrahn sym = the_arcs[index]->parent;
1200191aa565Sniklas
1201191aa565Sniklas /* If this symbol isn't attached to any other
1202191aa565Sniklas symbols, then we've got a rarely used arc.
1203191aa565Sniklas
1204191aa565Sniklas Skip it for now, we'll deal with them later. */
1205191aa565Sniklas if (sym->next == NULL
1206191aa565Sniklas && sym->prev == NULL)
1207191aa565Sniklas continue;
1208191aa565Sniklas
1209191aa565Sniklas /* Get to the start of this chain. */
1210191aa565Sniklas while (sym->prev)
1211191aa565Sniklas sym = sym->prev;
1212191aa565Sniklas
1213191aa565Sniklas while (sym)
1214191aa565Sniklas {
1215191aa565Sniklas /* Mark it as placed. */
1216191aa565Sniklas sym->has_been_placed = 1;
1217191aa565Sniklas printf ("%s\n", sym->name);
1218191aa565Sniklas sym = sym->next;
1219191aa565Sniklas }
1220191aa565Sniklas }
1221191aa565Sniklas
1222b55d4692Sfgsch /* If we want to place all the arcs, then output
1223b55d4692Sfgsch those which weren't placed by the main algorithm. */
1224191aa565Sniklas if (all)
1225*c074d1c9Sdrahn for (index = 0; index < arc_count; index++)
1226191aa565Sniklas {
1227191aa565Sniklas Sym *sym;
1228*c074d1c9Sdrahn if (the_arcs[index]->parent->has_been_placed
1229*c074d1c9Sdrahn || the_arcs[index]->child->has_been_placed)
1230191aa565Sniklas continue;
1231191aa565Sniklas
1232*c074d1c9Sdrahn sym = the_arcs[index]->parent;
1233191aa565Sniklas
1234191aa565Sniklas sym->has_been_placed = 1;
1235191aa565Sniklas printf ("%s\n", sym->name);
1236191aa565Sniklas }
1237191aa565Sniklas }
1238191aa565Sniklas
1239191aa565Sniklas /* Print a suggested .o ordering for files on a link line based
1240191aa565Sniklas on profiling information. This uses the function placement
1241191aa565Sniklas code for the bulk of its work. */
1242191aa565Sniklas
1243191aa565Sniklas void
cg_print_file_ordering()1244*c074d1c9Sdrahn cg_print_file_ordering ()
1245191aa565Sniklas {
1246191aa565Sniklas unsigned long scratch_arc_count, index;
1247191aa565Sniklas Arc **scratch_arcs;
1248191aa565Sniklas char *last;
1249191aa565Sniklas
1250191aa565Sniklas scratch_arc_count = 0;
1251191aa565Sniklas
1252191aa565Sniklas scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
1253191aa565Sniklas for (index = 0; index < numarcs; index++)
1254191aa565Sniklas {
1255191aa565Sniklas if (! arcs[index]->parent->mapped
1256191aa565Sniklas || ! arcs[index]->child->mapped)
1257191aa565Sniklas arcs[index]->has_been_placed = 1;
1258191aa565Sniklas }
1259191aa565Sniklas
1260191aa565Sniklas order_and_dump_functions_by_arcs (arcs, numarcs, 0,
1261191aa565Sniklas scratch_arcs, &scratch_arc_count);
1262191aa565Sniklas
1263191aa565Sniklas /* Output .o's not handled by the main placement algorithm. */
1264191aa565Sniklas for (index = 0; index < symtab.len; index++)
1265191aa565Sniklas {
1266191aa565Sniklas if (symtab.base[index].mapped
1267191aa565Sniklas && ! symtab.base[index].has_been_placed)
1268191aa565Sniklas printf ("%s\n", symtab.base[index].name);
1269191aa565Sniklas }
1270191aa565Sniklas
1271191aa565Sniklas /* Now output any .o's that didn't have any text symbols. */
1272191aa565Sniklas last = NULL;
1273191aa565Sniklas for (index = 0; index < symbol_map_count; index++)
1274191aa565Sniklas {
1275b305b0f1Sespie unsigned int index2;
1276191aa565Sniklas
1277b55d4692Sfgsch /* Don't bother searching if this symbol
1278b55d4692Sfgsch is the same as the previous one. */
1279191aa565Sniklas if (last && !strcmp (last, symbol_map[index].file_name))
1280191aa565Sniklas continue;
1281191aa565Sniklas
1282191aa565Sniklas for (index2 = 0; index2 < symtab.len; index2++)
1283191aa565Sniklas {
1284191aa565Sniklas if (! symtab.base[index2].mapped)
1285191aa565Sniklas continue;
1286191aa565Sniklas
1287191aa565Sniklas if (!strcmp (symtab.base[index2].name, symbol_map[index].file_name))
1288191aa565Sniklas break;
1289191aa565Sniklas }
1290191aa565Sniklas
1291b55d4692Sfgsch /* If we didn't find it in the symbol table, then it must
1292b55d4692Sfgsch be a .o with no text symbols. Output it last. */
1293191aa565Sniklas if (index2 == symtab.len)
1294191aa565Sniklas printf ("%s\n", symbol_map[index].file_name);
1295191aa565Sniklas last = symbol_map[index].file_name;
1296191aa565Sniklas }
1297191aa565Sniklas }
1298