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