/* cg_print.c - Print routines for displaying call graphs.
- Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2004, 2007, 2009, 2011
+ Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
\f
-#include "libiberty.h"
#include "gprof.h"
+#include "libiberty.h"
+#include "filenames.h"
#include "search_list.h"
#include "source.h"
#include "symtab.h"
#include "cg_print.h"
#include "hist.h"
#include "utils.h"
+#include "corefile.h"
/* Return value of comparison functions used to sort tables. */
#define LESSTHAN -1
#define EQUALTO 0
#define GREATERTHAN 1
-static void order_and_dump_functions_by_arcs PARAMS ((Arc **, unsigned long,
- int, Arc **,
- unsigned long *));
+static void print_header (void);
+static void print_cycle (Sym *);
+static int cmp_member (Sym *, Sym *);
+static void sort_members (Sym *);
+static void print_members (Sym *);
+static int cmp_arc (Arc *, Arc *);
+static void sort_parents (Sym *);
+static void print_parents (Sym *);
+static void sort_children (Sym *);
+static void print_children (Sym *);
+static void print_line (Sym *);
+static int cmp_name (const PTR, const PTR);
+static int cmp_arc_count (const PTR, const PTR);
+static int cmp_fun_nuses (const PTR, const PTR);
+static void order_and_dump_functions_by_arcs
+ (Arc **, unsigned long, int, Arc **, unsigned long *);
+
/* Declarations of automatically generated functions to output blurbs. */
-extern void bsd_callg_blurb PARAMS ((FILE * fp));
-extern void fsf_callg_blurb PARAMS ((FILE * fp));
+extern void bsd_callg_blurb (FILE * fp);
+extern void fsf_callg_blurb (FILE * fp);
double print_time = 0.0;
static void
-DEFUN_VOID (print_header)
+print_header ()
{
if (first_output)
first_output = FALSE;
}
printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
- (long) hist_scale * sizeof (UNIT));
+ (long) hist_scale * (long) sizeof (UNIT));
if (print_time > 0.0)
printf (_(" for %.2f%% of %.2f seconds\n\n"),
printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
"", "", "", "", _("called"), _("total"), _("parents"));
printf ("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
- _("index"), _("%time"), _("self"), _("descendants"),
- _("called"), _("self"), _("name"), _("index"));
+ _("index"),
+ /* xgettext:no-c-format */
+ _("%time"),
+ _("self"), _("descendants"), _("called"), _("self"),
+ _("name"), _("index"));
printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
"", "", "", "", _("called"), _("total"), _("children"));
printf ("\n");
/* Print a cycle header. */
static void
-DEFUN (print_cycle, (cyc), Sym * cyc)
+print_cycle (Sym *cyc)
{
char buf[BUFSIZ];
CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS. */
static int
-DEFUN (cmp_member, (left, right), Sym * left AND Sym * right)
+cmp_member (Sym *left, Sym *right)
{
double left_time = left->cg.prop.self + left->cg.prop.child;
double right_time = right->cg.prop.self + right->cg.prop.child;
/* Sort members of a cycle. */
static void
-DEFUN (sort_members, (cyc), Sym * cyc)
+sort_members (Sym *cyc)
{
Sym *todo, *doing, *prev;
todo = cyc->cg.cyc.next;
cyc->cg.cyc.next = 0;
- for (doing = todo; doing && doing->cg.cyc.next; doing = todo)
+ for (doing = todo; doing != NULL; doing = todo)
{
todo = doing->cg.cyc.next;
/* Print the members of a cycle. */
static void
-DEFUN (print_members, (cyc), Sym * cyc)
+print_members (Sym *cyc)
{
Sym *member;
arc count as minor key. */
static int
-DEFUN (cmp_arc, (left, right), Arc * left AND Arc * right)
+cmp_arc (Arc *left, Arc *right)
{
Sym *left_parent = left->parent;
Sym *left_child = left->child;
static void
-DEFUN (sort_parents, (child), Sym * child)
+sort_parents (Sym * child)
{
Arc *arc, *detached, sorted, *prev;
static void
-DEFUN (print_parents, (child), Sym * child)
+print_parents (Sym *child)
{
Sym *parent;
Arc *arc;
static void
-DEFUN (sort_children, (parent), Sym * parent)
+sort_children (Sym *parent)
{
Arc *arc, *detached, sorted, *prev;
static void
-DEFUN (print_children, (parent), Sym * parent)
+print_children (Sym *parent)
{
Sym *child;
Arc *arc;
static void
-DEFUN (print_line, (np), Sym * np)
+print_line (Sym *np)
{
char buf[BUFSIZ];
/* Print dynamic call graph. */
void
-DEFUN (cg_print, (timesortsym), Sym ** timesortsym)
+cg_print (Sym ** timesortsym)
{
- unsigned int index;
+ unsigned int sym_index;
Sym *parent;
if (print_descriptions && bsd_style_output)
print_header ();
- for (index = 0; index < symtab.len + num_cycles; ++index)
+ for (sym_index = 0; sym_index < symtab.len + num_cycles; ++sym_index)
{
- parent = timesortsym[index];
+ parent = timesortsym[sym_index];
if ((ignore_zeros && parent->ncalls == 0
&& parent->cg.self_calls == 0 && parent->cg.prop.self == 0
static int
-DEFUN (cmp_name, (left, right), const PTR left AND const PTR right)
+cmp_name (const PTR left, const PTR right)
{
const Sym **npp1 = (const Sym **) left;
const Sym **npp2 = (const Sym **) right;
void
-DEFUN_VOID (cg_print_index)
+cg_print_index ()
{
- unsigned int index;
+ unsigned int sym_index;
unsigned int nnames, todo, i, j;
int col, starting_col;
Sym **name_sorted_syms, *sym;
alphabetically to create an index. */
name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
- for (index = 0, nnames = 0; index < symtab.len; index++)
+ for (sym_index = 0, nnames = 0; sym_index < symtab.len; sym_index++)
{
- if (ignore_zeros && symtab.base[index].ncalls == 0
- && symtab.base[index].hist.time == 0)
+ if (ignore_zeros && symtab.base[sym_index].ncalls == 0
+ && symtab.base[sym_index].hist.time == 0)
continue;
- name_sorted_syms[nnames++] = &symtab.base[index];
+ name_sorted_syms[nnames++] = &symtab.base[sym_index];
}
qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
- for (index = 1, todo = nnames; index <= num_cycles; index++)
- name_sorted_syms[todo++] = &cycle_header[index];
+ for (sym_index = 1, todo = nnames; sym_index <= num_cycles; sym_index++)
+ name_sorted_syms[todo++] = &cycle_header[sym_index];
printf ("\f\n");
printf (_("Index by function name\n\n"));
- index = (todo + 2) / 3;
+ sym_index = (todo + 2) / 3;
- for (i = 0; i < index; i++)
+ for (i = 0; i < sym_index; i++)
{
col = 0;
starting_col = 0;
- for (j = i; j < todo; j += index)
+ for (j = i; j < todo; j += sym_index)
{
sym = name_sorted_syms[j];
We want to sort in descending order. */
static int
-DEFUN (cmp_arc_count, (left, right), const PTR left AND const PTR right)
+cmp_arc_count (const PTR left, const PTR right)
{
const Arc **npp1 = (const Arc **) left;
const Arc **npp2 = (const Arc **) right;
We want to sort in descending order. */
static int
-DEFUN (cmp_fun_nuses, (left, right), const PTR left AND const PTR right)
+cmp_fun_nuses (const PTR left, const PTR right)
{
const Sym **npp1 = (const Sym **) left;
const Sym **npp2 = (const Sym **) right;
of function ordering). */
void
-DEFUN_VOID (cg_print_function_ordering)
+cg_print_function_ordering (void)
{
- unsigned long index, used, unused, scratch_index;
+ unsigned long sym_index;
+ unsigned long arc_index;
+ unsigned long used, unused, scratch_index;
unsigned long unplaced_arc_count, high_arc_count, scratch_arc_count;
#ifdef __GNUC__
unsigned long long total_arcs, tmp_arcs_count;
Sym **unused_syms, **used_syms, **scratch_syms;
Arc **unplaced_arcs, **high_arcs, **scratch_arcs;
- index = 0;
+ sym_index = 0;
used = 0;
unused = 0;
scratch_index = 0;
/* Walk through all the functions; mark those which are never
called as placed (we'll emit them as a group later). */
- for (index = 0, used = 0, unused = 0; index < symtab.len; index++)
+ for (sym_index = 0, used = 0, unused = 0; sym_index < symtab.len; sym_index++)
{
- if (symtab.base[index].ncalls == 0)
+ if (symtab.base[sym_index].ncalls == 0)
{
- /* Filter out gprof generated names. */
- if (strcmp (symtab.base[index].name, "<locore>")
- && strcmp (symtab.base[index].name, "<hicore>"))
- {
- unused_syms[unused++] = &symtab.base[index];
- symtab.base[index].has_been_placed = 1;
- }
+ unused_syms[unused++] = &symtab.base[sym_index];
+ symtab.base[sym_index].has_been_placed = 1;
}
else
{
- used_syms[used++] = &symtab.base[index];
- symtab.base[index].has_been_placed = 0;
- symtab.base[index].next = 0;
- symtab.base[index].prev = 0;
- symtab.base[index].nuses = 0;
+ used_syms[used++] = &symtab.base[sym_index];
+ symtab.base[sym_index].has_been_placed = 0;
+ symtab.base[sym_index].next = 0;
+ symtab.base[sym_index].prev = 0;
+ symtab.base[sym_index].nuses = 0;
}
}
Overflow is much less likely when this file is compiled
with GCC as it can double-wide integers via long long. */
total_arcs = 0;
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < numarcs; arc_index++)
{
- total_arcs += arcs[index]->count;
- arcs[index]->has_been_placed = 0;
+ total_arcs += arcs[arc_index]->count;
+ arcs[arc_index]->has_been_placed = 0;
}
/* We want to pull out those functions which are referenced
by many highly used arcs and emit them as a group. This
could probably use some tuning. */
tmp_arcs_count = 0;
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < numarcs; arc_index++)
{
- tmp_arcs_count += arcs[index]->count;
+ tmp_arcs_count += arcs[arc_index]->count;
/* Count how many times each parent and child are used up
to our threshhold of arcs (90%). */
if ((double)tmp_arcs_count / (double)total_arcs > 0.90)
break;
- arcs[index]->child->nuses++;
+ arcs[arc_index]->child->nuses++;
}
/* Now sort a temporary symbol table based on the number of
/* Now pick out those symbols we're going to emit as
a group. We take up to 1.25% of the used symbols. */
- for (index = 0; index < used / 80; index++)
+ for (sym_index = 0; sym_index < used / 80; sym_index++)
{
- Sym *sym = scratch_syms[index];
+ Sym *sym = scratch_syms[sym_index];
Arc *arc;
/* If we hit symbols that aren't used from many call sites,
}
/* Keep track of how many symbols we're going to place. */
- scratch_index = index;
+ scratch_index = sym_index;
/* A lie, but it makes identifying
these functions easier later. */
/* Now walk through the temporary arcs and copy
those we care about into the high arcs array. */
- for (index = 0; index < scratch_arc_count; index++)
+ for (arc_index = 0; arc_index < scratch_arc_count; arc_index++)
{
- Arc *arc = scratch_arcs[index];
+ Arc *arc = scratch_arcs[arc_index];
/* If this arc refers to highly used functions, then
then we want to keep it. */
if (arc->child->has_been_placed
&& arc->parent->has_been_placed)
{
- high_arcs[high_arc_count++] = scratch_arcs[index];
+ high_arcs[high_arc_count++] = scratch_arcs[arc_index];
/* We need to turn of has_been_placed since we're going to
use the main arc placement algorithm on these arcs. */
/* Dump the multi-site high usage functions which are not
going to be ordered by the main ordering algorithm. */
- for (index = 0; index < scratch_index; index++)
+ for (sym_index = 0; sym_index < scratch_index; sym_index++)
{
- if (scratch_syms[index]->has_been_placed)
- printf ("%s\n", scratch_syms[index]->name);
+ if (scratch_syms[sym_index]->has_been_placed)
+ printf ("%s\n", scratch_syms[sym_index]->name);
}
/* Now we can order the multi-site high use
scratch_arcs, &scratch_arc_count);
/* Output any functions not emitted by the order_and_dump calls. */
- for (index = 0; index < used; index++)
- if (used_syms[index]->has_been_placed == 0)
- printf("%s\n", used_syms[index]->name);
+ for (sym_index = 0; sym_index < used; sym_index++)
+ if (used_syms[sym_index]->has_been_placed == 0)
+ printf("%s\n", used_syms[sym_index]->name);
/* Output the unused functions. */
- for (index = 0; index < unused; index++)
- printf("%s\n", unused_syms[index]->name);
+ for (sym_index = 0; sym_index < unused; sym_index++)
+ printf("%s\n", unused_syms[sym_index]->name);
unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
free (unplaced_arcs);
}
-/* Place functions based on the arcs in ARCS with NUMARCS entries;
+/* Place functions based on the arcs in THE_ARCS with ARC_COUNT entries;
place unused arcs into UNPLACED_ARCS/UNPLACED_ARC_COUNT.
- If ALL is nonzero, then place all functions referenced by ARCS,
- else only place those referenced in the top 99% of the arcs in ARCS. */
+ If ALL is nonzero, then place all functions referenced by THE_ARCS,
+ else only place those referenced in the top 99% of the arcs in THE_ARCS. */
#define MOST 0.99
static void
-order_and_dump_functions_by_arcs (arcs, numarcs, all,
+order_and_dump_functions_by_arcs (the_arcs, arc_count, all,
unplaced_arcs, unplaced_arc_count)
- Arc **arcs;
- unsigned long numarcs;
+ Arc **the_arcs;
+ unsigned long arc_count;
int all;
Arc **unplaced_arcs;
unsigned long *unplaced_arc_count;
#else
unsigned long tmp_arcs, total_arcs;
#endif
- unsigned int index;
+ unsigned int arc_index;
/* If needed, compute the total arc count.
if (! all)
{
total_arcs = 0;
- for (index = 0; index < numarcs; index++)
- total_arcs += arcs[index]->count;
+ for (arc_index = 0; arc_index < arc_count; arc_index++)
+ total_arcs += the_arcs[arc_index]->count;
}
else
total_arcs = 0;
tmp_arcs = 0;
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < arc_count; arc_index++)
{
Sym *sym1, *sym2;
Sym *child, *parent;
- tmp_arcs += arcs[index]->count;
+ tmp_arcs += the_arcs[arc_index]->count;
/* Ignore this arc if it's already been placed. */
- if (arcs[index]->has_been_placed)
+ if (the_arcs[arc_index]->has_been_placed)
continue;
- child = arcs[index]->child;
- parent = arcs[index]->parent;
+ child = the_arcs[arc_index]->child;
+ parent = the_arcs[arc_index]->parent;
/* If we're not using all arcs, and this is a rarely used
arc, then put it on the unplaced_arc list. Similarly
if ((! all && (double)tmp_arcs / (double)total_arcs > MOST)
|| child->has_been_placed || parent->has_been_placed)
{
- unplaced_arcs[(*unplaced_arc_count)++] = arcs[index];
+ unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[arc_index];
continue;
}
algorithm can use it to place function chains. */
if (parent->next && parent->prev && child->next && child->prev)
{
- unplaced_arcs[(*unplaced_arc_count)++] = arcs[index];
+ unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[arc_index];
continue;
}
{
/* Couldn't find anywhere to attach the functions,
put the arc on the unplaced arc list. */
- unplaced_arcs[(*unplaced_arc_count)++] = arcs[index];
+ unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[arc_index];
continue;
}
&& sym2 == parent)
{
/* This would tie two ends together. */
- unplaced_arcs[(*unplaced_arc_count)++] = arcs[index];
+ unplaced_arcs[(*unplaced_arc_count)++] = the_arcs[arc_index];
continue;
}
/* parent-prev and child-next */
parent->prev = child;
child->next = parent;
- arcs[index]->has_been_placed = 1;
+ the_arcs[arc_index]->has_been_placed = 1;
}
}
else if (parent->prev)
/* parent-next and child-prev */
parent->next = child;
child->prev = parent;
- arcs[index]->has_been_placed = 1;
+ the_arcs[arc_index]->has_been_placed = 1;
}
}
else
/* parent-prev and child-next. */
parent->prev = child;
child->next = parent;
- arcs[index]->has_been_placed = 1;
+ the_arcs[arc_index]->has_been_placed = 1;
}
else
{
/* parent-next and child-prev. */
parent->next = child;
child->prev = parent;
- arcs[index]->has_been_placed = 1;
+ the_arcs[arc_index]->has_been_placed = 1;
}
}
}
/* Dump the chains of functions we've made. */
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < arc_count; arc_index++)
{
Sym *sym;
- if (arcs[index]->parent->has_been_placed
- || arcs[index]->child->has_been_placed)
+ if (the_arcs[arc_index]->parent->has_been_placed
+ || the_arcs[arc_index]->child->has_been_placed)
continue;
- sym = arcs[index]->parent;
+ sym = the_arcs[arc_index]->parent;
/* If this symbol isn't attached to any other
symbols, then we've got a rarely used arc.
/* If we want to place all the arcs, then output
those which weren't placed by the main algorithm. */
if (all)
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < arc_count; arc_index++)
{
Sym *sym;
- if (arcs[index]->parent->has_been_placed
- || arcs[index]->child->has_been_placed)
+ if (the_arcs[arc_index]->parent->has_been_placed
+ || the_arcs[arc_index]->child->has_been_placed)
continue;
- sym = arcs[index]->parent;
+ sym = the_arcs[arc_index]->parent;
sym->has_been_placed = 1;
printf ("%s\n", sym->name);
}
}
+/* Compare two function_map structs based on file name.
+ We want to sort in ascending order. */
+
+static int
+cmp_symbol_map (const void * l, const void * r)
+{
+ return filename_cmp (((struct function_map *) l)->file_name,
+ ((struct function_map *) r)->file_name);
+}
+
/* Print a suggested .o ordering for files on a link line based
on profiling information. This uses the function placement
code for the bulk of its work. */
-struct function_map
-{
- char *function_name;
- char *file_name;
-};
-
void
-DEFUN_VOID (cg_print_file_ordering)
+cg_print_file_ordering (void)
{
- unsigned long scratch_arc_count, index;
+ unsigned long scratch_arc_count;
+ unsigned long arc_index;
+ unsigned long sym_index;
Arc **scratch_arcs;
- extern struct function_map *symbol_map;
- extern unsigned int symbol_map_count;
char *last;
scratch_arc_count = 0;
scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
- for (index = 0; index < numarcs; index++)
+ for (arc_index = 0; arc_index < numarcs; arc_index++)
{
- if (! arcs[index]->parent->mapped
- || ! arcs[index]->child->mapped)
- arcs[index]->has_been_placed = 1;
+ if (! arcs[arc_index]->parent->mapped
+ || ! arcs[arc_index]->child->mapped)
+ arcs[arc_index]->has_been_placed = 1;
}
order_and_dump_functions_by_arcs (arcs, numarcs, 0,
scratch_arcs, &scratch_arc_count);
/* Output .o's not handled by the main placement algorithm. */
- for (index = 0; index < symtab.len; index++)
+ for (sym_index = 0; sym_index < symtab.len; sym_index++)
{
- if (symtab.base[index].mapped
- && ! symtab.base[index].has_been_placed)
- printf ("%s\n", symtab.base[index].name);
+ if (symtab.base[sym_index].mapped
+ && ! symtab.base[sym_index].has_been_placed)
+ printf ("%s\n", symtab.base[sym_index].name);
}
+ qsort (symbol_map, symbol_map_count, sizeof (struct function_map), cmp_symbol_map);
+
/* Now output any .o's that didn't have any text symbols. */
last = NULL;
- for (index = 0; index < symbol_map_count; index++)
+ for (sym_index = 0; sym_index < symbol_map_count; sym_index++)
{
unsigned int index2;
/* Don't bother searching if this symbol
is the same as the previous one. */
- if (last && !strcmp (last, symbol_map[index].file_name))
+ if (last && !filename_cmp (last, symbol_map[sym_index].file_name))
continue;
for (index2 = 0; index2 < symtab.len; index2++)
if (! symtab.base[index2].mapped)
continue;
- if (!strcmp (symtab.base[index2].name, symbol_map[index].file_name))
+ if (!filename_cmp (symtab.base[index2].name,
+ symbol_map[sym_index].file_name))
break;
}
/* If we didn't find it in the symbol table, then it must
be a .o with no text symbols. Output it last. */
if (index2 == symtab.len)
- printf ("%s\n", symbol_map[index].file_name);
- last = symbol_map[index].file_name;
+ printf ("%s\n", symbol_map[sym_index].file_name);
+ last = symbol_map[sym_index].file_name;
}
}