aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.3/gcc/dyn-ipa.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.4.3/gcc/dyn-ipa.c')
-rw-r--r--gcc-4.4.3/gcc/dyn-ipa.c379
1 files changed, 268 insertions, 111 deletions
diff --git a/gcc-4.4.3/gcc/dyn-ipa.c b/gcc-4.4.3/gcc/dyn-ipa.c
index ae2bf2793..537acff61 100644
--- a/gcc-4.4.3/gcc/dyn-ipa.c
+++ b/gcc-4.4.3/gcc/dyn-ipa.c
@@ -43,7 +43,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "gcov-io.h"
struct dyn_pointer_set;
-struct dyn_vect;
#define XNEWVEC(type,ne) (type *)malloc(sizeof(type) * (ne))
#define XNEW(type) (type *)malloc(sizeof(type))
@@ -57,6 +56,7 @@ struct dyn_cgraph_node
struct dyn_pointer_set *imported_modules;
gcov_type guid;
+ gcov_type sum_in_count;
gcov_unsigned_t visited;
};
@@ -77,7 +77,7 @@ struct dyn_module_info
struct dyn_cgraph
{
- struct dyn_cgraph_node **call_graph_nodes;
+ struct dyn_pointer_set **call_graph_nodes;
struct gcov_info **modules;
/* supplement module information */
struct dyn_module_info *sup_modules;
@@ -92,7 +92,8 @@ struct dyn_pointer_set
size_t n_slots; /* n_slots = 2^log_slots */
size_t n_elements;
- const void **slots;
+ void **slots;
+ unsigned (*get_key) (const void *);
};
@@ -105,13 +106,18 @@ void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
static void gcov_dump_callgraph (gcov_type);
static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node);
static void gcov_dump_cgraph_node (struct dyn_cgraph_node *node,
- unsigned m, unsigned f);
+ unsigned m, unsigned f, const char *n);
static void
gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
unsigned m, unsigned f,
+ const char *func_nm,
gcov_type cutoff_count);
static void
pointer_set_destroy (struct dyn_pointer_set *pset);
+static void **
+pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key);
+static struct dyn_pointer_set *
+pointer_set_create (unsigned (*get_key) (const void *));
static struct dyn_cgraph the_dyn_call_graph;
static int total_zero_count = 0;
@@ -172,7 +178,8 @@ get_cgraph_node (gcov_type func_guid)
if (func_id > the_dyn_call_graph.sup_modules[mod_id].max_func_ident)
return 0;
- return &the_dyn_call_graph.call_graph_nodes[mod_id][func_id];
+ return *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[mod_id], func_id));
}
/* Return the gcov_info pointer for module with id MODULE_ID. */
@@ -185,6 +192,12 @@ get_module_info (gcov_unsigned_t module_id)
struct gcov_info *__gcov_list ATTRIBUTE_HIDDEN;
+static inline unsigned
+cgraph_node_get_key (const void *p)
+{
+ return get_intra_module_func_id (((const struct dyn_cgraph_node *) p)->guid);
+}
+
/* Initialize dynamic call graph. */
static void
@@ -217,7 +230,7 @@ init_dyn_call_graph (void)
= XNEWVEC (const struct gcov_fn_info **, num_modules);
the_dyn_call_graph.call_graph_nodes
- = XNEWVEC (struct dyn_cgraph_node *, num_modules);
+ = XNEWVEC (struct dyn_pointer_set *, num_modules);
gi_ptr = __gcov_list;
@@ -255,21 +268,20 @@ init_dyn_call_graph (void)
the_dyn_call_graph.call_graph_nodes[mod_id]
- = XNEWVEC (struct dyn_cgraph_node, max_func_ident + 1);
+ = pointer_set_create (cgraph_node_get_key);
the_dyn_call_graph.sup_modules[mod_id].max_func_ident = max_func_ident;
- for (j = 0; j < max_func_ident + 1; j++)
- init_dyn_cgraph_node (&the_dyn_call_graph.call_graph_nodes[mod_id][j], 0);
-
for (j = 0; j < gi_ptr->n_functions; j++)
{
const struct gcov_fn_info *fi_ptr
= the_dyn_call_graph.functions[mod_id][j];
-
- node = &the_dyn_call_graph.call_graph_nodes[mod_id][fi_ptr->ident];
- init_dyn_cgraph_node (node, GEN_FUNC_GLOBAL_ID (gi_ptr->mod_info->ident,
- fi_ptr->ident));
+ *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[mod_id], fi_ptr->ident))
+ = node = XNEW (struct dyn_cgraph_node);
+ the_dyn_call_graph.call_graph_nodes[mod_id]->n_elements++;
+ init_dyn_cgraph_node (node, GEN_FUNC_GLOBAL_ID (gi_ptr->mod_info->ident,
+ fi_ptr->ident));
}
}
}
@@ -292,7 +304,9 @@ __gcov_finalize_dyn_callgraph (void)
struct dyn_cgraph_node *node;
struct dyn_cgraph_edge *callees, *next_callee;
fi_ptr = the_dyn_call_graph.functions[i][f_ix];
- node = &the_dyn_call_graph.call_graph_nodes[i][fi_ptr->ident];
+ node = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[i], fi_ptr->ident));
+ gcc_assert (node);
callees = node->callees;
if (!callees)
@@ -307,7 +321,7 @@ __gcov_finalize_dyn_callgraph (void)
pointer_set_destroy (node->imported_modules);
}
if (the_dyn_call_graph.call_graph_nodes[i])
- XDELETEVEC (the_dyn_call_graph.call_graph_nodes[i]);
+ pointer_set_destroy (the_dyn_call_graph.call_graph_nodes[i]);
if (the_dyn_call_graph.functions[i])
XDELETEVEC (the_dyn_call_graph.functions[i]);
/* Now delete sup modules */
@@ -486,7 +500,10 @@ gcov_build_callgraph (void)
{
struct dyn_cgraph_node *caller;
fi_ptr = the_dyn_call_graph.functions[m_ix][f_ix];
- caller = &the_dyn_call_graph.call_graph_nodes[m_ix][fi_ptr->ident];
+ caller = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix],
+ fi_ptr->ident));
+ gcc_assert (caller);
if (dcall_profile_values)
{
unsigned offset;
@@ -519,7 +536,7 @@ gcov_build_callgraph (void)
}
static inline size_t
-hash1 (const void *p, unsigned long max, unsigned long logmax)
+hash1 (unsigned p, unsigned long max, unsigned long logmax)
{
const unsigned long long A = 0x9e3779b97f4a7c16ull;
const unsigned long long shift = 64 - logmax;
@@ -527,10 +544,10 @@ hash1 (const void *p, unsigned long max, unsigned long logmax)
return ((A * (unsigned long) p) >> shift) & (max - 1);
}
-/* Allocate an empty pointer set. */
+/* Allocate an empty imported-modules set. */
static struct dyn_pointer_set *
-pointer_set_create (void)
+pointer_set_create (unsigned (*get_key) (const void *))
{
struct dyn_pointer_set *result = XNEW (struct dyn_pointer_set);
@@ -538,8 +555,10 @@ pointer_set_create (void)
result->log_slots = 8;
result->n_slots = (size_t) 1 << result->log_slots;
- result->slots = XNEWVEC (const void *, result->n_slots);
- memset (result->slots, 0, sizeof (const void *) * result->n_slots);
+ result->slots = XNEWVEC (void *, result->n_slots);
+ memset (result->slots, 0, sizeof (void *) * result->n_slots);
+ result->get_key = get_key;
+
return result;
}
@@ -548,19 +567,25 @@ pointer_set_create (void)
static void
pointer_set_destroy (struct dyn_pointer_set *pset)
{
+ size_t i;
+ for (i = 0; i < pset->n_slots; i++)
+ if (pset->slots[i])
+ XDELETE (pset->slots[i]);
XDELETEVEC (pset->slots);
XDELETE (pset);
}
-/* Subroutine of pointer_set_insert. Return the insertion slot for P into
- an empty element of SLOTS, an array of length N_SLOTS. */
+/* Subroutine of pointer_set_find_or_insert. Return the insertion slot for KEY
+ into an empty element of SLOTS, an array of length N_SLOTS. */
static inline size_t
-insert_aux (const void *p, const void **slots, size_t n_slots, size_t log_slots)
+insert_aux (unsigned key, void **slots,
+ size_t n_slots, size_t log_slots,
+ unsigned (*get_key) (const void *))
{
- size_t n = hash1 (p, n_slots, log_slots);
+ size_t n = hash1 (key, n_slots, log_slots);
while (1)
{
- if (slots[n] == p || slots[n] == 0)
+ if (slots[n] == 0 || get_key (slots[n]) == key)
return n;
else
{
@@ -571,28 +596,30 @@ insert_aux (const void *p, const void **slots, size_t n_slots, size_t log_slots)
}
}
-/* Insert P into PSET if it wasn't already there. Returns nonzero
- if it was already there. P must be nonnull. */
+/* Find slot for KEY. KEY must be nonnull. */
-static int
-pointer_set_insert (struct dyn_pointer_set *pset, const void *p)
+static void **
+pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key)
{
size_t n;
- /* For simplicity, expand the set even if P is already there. This can be
+ /* For simplicity, expand the set even if KEY is already there. This can be
superfluous but can happen at most once. */
if (pset->n_elements > pset->n_slots / 4)
{
size_t new_log_slots = pset->log_slots + 1;
size_t new_n_slots = pset->n_slots * 2;
- const void **new_slots = XNEWVEC (const void *, new_n_slots);
- memset (new_slots, 0, sizeof (const void*) * new_n_slots);
+ void **new_slots = XNEWVEC (void *, new_n_slots);
+ memset (new_slots, 0, sizeof (void *) * new_n_slots);
size_t i;
for (i = 0; i < pset->n_slots; ++i)
{
- const void *value = pset->slots[i];
- n = insert_aux (value, new_slots, new_n_slots, new_log_slots);
+ void *value = pset->slots[i];
+ if (!value)
+ continue;
+ n = insert_aux (pset->get_key (value), new_slots, new_n_slots,
+ new_log_slots, pset->get_key);
new_slots[n] = value;
}
@@ -602,37 +629,64 @@ pointer_set_insert (struct dyn_pointer_set *pset, const void *p)
pset->slots = new_slots;
}
- n = insert_aux (p, pset->slots, pset->n_slots, pset->log_slots);
- if (pset->slots[n])
- return 1;
-
- pset->slots[n] = p;
- ++pset->n_elements;
- return 0;
+ n = insert_aux (key, pset->slots, pset->n_slots, pset->log_slots,
+ pset->get_key);
+ return &pset->slots[n];
}
/* Pass each pointer in PSET to the function in FN, together with the fixed
- parameter DATA. If FN returns false, the iteration stops. */
+ parameters DATA1, DATA2, DATA3. If FN returns false, the iteration stops. */
static void
pointer_set_traverse (const struct dyn_pointer_set *pset,
- int (*fn) (const void *, void *), void *data)
+ int (*fn) (const void *, void *, void *, void *),
+ void *data1, void *data2, void *data3)
{
size_t i;
for (i = 0; i < pset->n_slots; ++i)
- if (pset->slots[i] && !fn (pset->slots[i], data))
+ if (pset->slots[i] && !fn (pset->slots[i], data1, data2, data3))
break;
}
-/* Callback function to propagate import module set (VALUE) from callee to
- caller (DATA). */
static int
-gcov_propagate_imp_modules (const void *value, void *data)
+imp_mod_set_insert (struct dyn_pointer_set *p, const struct gcov_info *imp_mod,
+ double wt)
{
- struct dyn_pointer_set *receiving_set
- = (struct dyn_pointer_set *) data;
+ struct dyn_imp_mod **m = (struct dyn_imp_mod **)
+ pointer_set_find_or_insert (p, imp_mod->mod_info->ident);
+ if (*m)
+ {
+ (*m)->weight += wt;
+ return 1;
+ }
+ else
+ {
+ *m = XNEW (struct dyn_imp_mod);
+ (*m)->imp_mod = imp_mod;
+ (*m)->weight = wt;
+ p->n_elements++;
+ return 0;
+ }
+}
- pointer_set_insert (receiving_set, value);
+/* Callback function to propagate import module (VALUE) from callee to
+ caller's imported-module-set (DATA1).
+ The weight is scaled by the scaling-factor (DATA2) before propagation,
+ and accumulated into DATA3. */
+static int
+gcov_propagate_imp_modules (const void *value, void *data1, void *data2,
+ void *data3)
+{
+ const struct dyn_imp_mod *m = (const struct dyn_imp_mod *) value;
+ struct dyn_pointer_set *receiving_set = (struct dyn_pointer_set *) data1;
+ double *scale = (double *) data2;
+ double *sum = (double *) data3;
+ double wt = m->weight;
+ if (scale)
+ wt *= *scale;
+ if (sum)
+ (*sum) += wt;
+ imp_mod_set_insert (receiving_set, m->imp_mod, wt);
return 1;
}
@@ -668,6 +722,7 @@ gcov_compute_cutoff_count (void)
unsigned cutoff_perc;
unsigned num_perc;
int do_dump;
+ const char *dump_str;
capacity = 100;
/* allocate an edge array */
@@ -687,7 +742,9 @@ gcov_compute_cutoff_count (void)
fi_ptr = the_dyn_call_graph.functions[m_ix][f_ix];
- node = &the_dyn_call_graph.call_graph_nodes[m_ix][fi_ptr->ident];
+ node = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
callees = node->callees;
while (callees != 0)
@@ -708,7 +765,7 @@ gcov_compute_cutoff_count (void)
/* Now sort */
qsort (edges, num_edges, sizeof (void *), sort_by_count);
-#define CUM_CUTOFF_PERCENT 95
+#define CUM_CUTOFF_PERCENT 80
#define MIN_NUM_EDGE_PERCENT 0
cutoff_str = getenv ("GCOV_DYN_CGRAPH_CUTOFF");
if (cutoff_str && strlen (cutoff_str))
@@ -736,11 +793,12 @@ gcov_compute_cutoff_count (void)
total += edges[i]->count;
cum_cutoff = (total * cutoff_perc)/100;
- do_dump = (getenv ("GCOV_DYN_CGRAPH_DUMP") != 0);
+ dump_str = getenv ("GCOV_DYN_CGRAPH_DUMP");
+ do_dump = (dump_str != 0 && strlen (dump_str));
for (i = 0; i < num_edges; i++)
{
cum += edges[i]->count;
- if (do_dump)
+ if (do_dump && dump_str[0] == '1')
fprintf (stderr, "// edge[%d] count = %.0f [%llx --> %llx]\n",
i, (double) edges[i]->count,
(long long) edges[i]->caller->guid,
@@ -752,7 +810,7 @@ gcov_compute_cutoff_count (void)
}
}
- if (do_dump)
+ if (do_dump && dump_str[0] == '1')
fprintf (stderr, "// total = %.0f cum = %.0f cum/total = %.0f%%"
" cutoff_count = %lld [total edges: %d hot edges: %d perc: %d%%]\n"
" total_zero_count_edges = %d total_insane_count_edgess = %d\n"
@@ -765,13 +823,19 @@ gcov_compute_cutoff_count (void)
return cutoff_count;
}
+static inline unsigned
+imp_mod_get_key (const void *p)
+{
+ return ((const struct dyn_imp_mod *) p)->imp_mod->mod_info->ident;
+}
+
/* Return the imported module set for NODE. */
static struct dyn_pointer_set *
gcov_get_imp_module_set (struct dyn_cgraph_node *node)
{
if (!node->imported_modules)
- node->imported_modules = pointer_set_create ();
+ node->imported_modules = pointer_set_create (imp_mod_get_key);
return node->imported_modules;
}
@@ -782,7 +846,7 @@ static struct dyn_pointer_set *
gcov_get_module_imp_module_set (struct dyn_module_info *mi)
{
if (!mi->imported_modules)
- mi->imported_modules = pointer_set_create ();
+ mi->imported_modules = pointer_set_create (imp_mod_get_key);
return mi->imported_modules;
}
@@ -790,10 +854,13 @@ gcov_get_module_imp_module_set (struct dyn_module_info *mi)
/* Callback function to mark if a module needs to be exported. */
static int
-gcov_mark_export_modules (const void *value, void *data ATTRIBUTE_UNUSED)
+gcov_mark_export_modules (const void *value,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
{
const struct gcov_info *module_info
- = (const struct gcov_info *)value;
+ = ((const struct dyn_imp_mod *) value)->imp_mod;
module_info->mod_info->is_exported = 1;
return 1;
@@ -801,7 +868,7 @@ gcov_mark_export_modules (const void *value, void *data ATTRIBUTE_UNUSED)
struct gcov_import_mod_array
{
- const struct gcov_info **imported_modules;
+ const struct dyn_imp_mod **imported_modules;
struct gcov_info *importing_module;
unsigned len;
};
@@ -809,10 +876,12 @@ struct gcov_import_mod_array
/* Callback function to compute pointer set size. */
static int
-gcov_compute_pset_size (const void *value ATTRIBUTE_UNUSED,
- void *data)
+gcov_compute_mset_size (const void *value ATTRIBUTE_UNUSED,
+ void *data1,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
{
- unsigned *len = (unsigned *) data;
+ unsigned *len = (unsigned *) data1;
(*len)++;
return 1;
}
@@ -820,36 +889,44 @@ gcov_compute_pset_size (const void *value ATTRIBUTE_UNUSED,
/* Callback function to collect imported modules. */
static int
-gcov_collect_imported_modules (const void *value, void *data)
+gcov_collect_imported_modules (const void *value,
+ void *data1,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
{
struct gcov_import_mod_array *out_array;
- const struct gcov_info *module_info
- = (const struct gcov_info *)value;
+ const struct dyn_imp_mod *m
+ = (const struct dyn_imp_mod *) value;
- out_array = (struct gcov_import_mod_array *) data;
+ out_array = (struct gcov_import_mod_array *) data1;
- if (module_info != out_array->importing_module)
- out_array->imported_modules[out_array->len++] = module_info;
+ if (m->imp_mod != out_array->importing_module)
+ out_array->imported_modules[out_array->len++] = m;
return 1;
}
-/* Comparitor for sorting imported modules using module ids. */
+/* Comparator for sorting imported modules using weights. */
static int
-sort_by_module_id (const void *pa, const void *pb)
+sort_by_module_wt (const void *pa, const void *pb)
{
- const struct gcov_info *m_a = *(struct gcov_info * const *)pa;
- const struct gcov_info *m_b = *(struct gcov_info * const *)pb;
+ const struct dyn_imp_mod *m_a = *((const struct dyn_imp_mod * const *) pa);
+ const struct dyn_imp_mod *m_b = *((const struct dyn_imp_mod * const *) pb);
- return (int) m_a->mod_info->ident - (int) m_b->mod_info->ident;
+ /* We want to sort in descending order of weights. */
+ if (m_a->weight < m_b->weight)
+ return +1;
+ if (m_a->weight > m_b->weight)
+ return -1;
+ return get_module_idx (m_a->imp_mod) - get_module_idx (m_b->imp_mod);
}
/* Return a dynamic array of imported modules that is sorted for
the importing module MOD_INFO. The length of the array is returned
in *LEN. */
-const struct gcov_info **
+const struct dyn_imp_mod **
gcov_get_sorted_import_module_array (struct gcov_info *mod_info,
unsigned *len)
{
@@ -865,28 +942,86 @@ gcov_get_sorted_import_module_array (struct gcov_info *mod_info,
return 0;
pointer_set_traverse (sup_mod_info->imported_modules,
- gcov_compute_pset_size, &array_len);
- imp_array.imported_modules = XNEWVEC (const struct gcov_info *, array_len);
+ gcov_compute_mset_size, &array_len, 0, 0);
+ imp_array.imported_modules = XNEWVEC (const struct dyn_imp_mod *, array_len);
imp_array.len = 0;
imp_array.importing_module = mod_info;
pointer_set_traverse (sup_mod_info->imported_modules,
- gcov_collect_imported_modules, &imp_array);
+ gcov_collect_imported_modules, &imp_array, 0, 0);
*len = imp_array.len;
qsort (imp_array.imported_modules, imp_array.len,
- sizeof (void *), sort_by_module_id);
+ sizeof (void *), sort_by_module_wt);
return imp_array.imported_modules;
}
/* Compute modules that are needed for NODE (for cross module inlining).
- CUTTOFF_COUNT is the call graph edge count cutoff value. */
+ CUTTOFF_COUNT is the call graph edge count cutoff value.
+ IMPORT_SCALE is the scaling-factor (percent) by which to scale the
+ weights of imported modules of a callee before propagating them to
+ the caller, if the callee and caller are in different modules.
+
+ Each imported module is assigned a weight that corresponds to the
+ expected benefit due to cross-module inlining. When the imported modules
+ are written out, they are sorted with highest weight first.
+
+ The following example illustrates how the weight is computed:
+
+ Suppose we are processing call-graph node A. It calls function B 50 times,
+ which calls function C 1000 times, and function E 800 times. Lets say B has
+ another in-edge from function D, with edge-count of 50. Say all the
+ functions are in separate modules (modules a, b, c, d, e, respectively):
+
+ D
+ |
+ | 50
+ |
+ 50 v 1000
+ A --------> B ----------> C
+ |
+ | 800
+ |
+ v
+ E
+
+ Nodes are processed in depth-first order, so when processing A, we first
+ process B. For node B, we are going to add module c to the imported-module
+ set, with weight 1000 (edge-count), and module e with weight 800.
+ Coming back to A, we are going to add the imported-module-set of B to A,
+ after doing some scaling.
+ The first scaling factor comes from the fact that A calls B 50 times, but B
+ has in-edge-count total of 100. So this scaling factor is 50/100 = 0.5
+ The second scaling factor is that since B is in a different module than A,
+ we want to slightly downgrade imported modules of B, before adding to the
+ imported-modules set of A. This scaling factor has a default value of 50%
+ (can be set via env variable GCOV_DYN_IMPORT_SCALE).
+ So we end up adding modules c and e to the imported-set of A, with weights
+ 0.5*0.5*1000=250 and 0.5*0.5*800=200, respectively.
+
+ Next, we have to add module b itself to A. The weight is computed as the
+ edge-count plus the sum of scaled-weights of all modules in the
+ imported-module set of B, i.e., 50 + 250 + 200 = 500.
+
+ In computing the weight of module b, we add the sum of scaled-weights of
+ imported modules of b, because it doesn't make sense to import c, e in
+ module a, until module b is imported. */
static void
gcov_process_cgraph_node (struct dyn_cgraph_node *node,
- gcov_type cutoff_count)
+ gcov_type cutoff_count,
+ unsigned import_scale)
{
unsigned mod_id;
struct dyn_cgraph_edge *callees;
+ struct dyn_cgraph_edge *callers;
node->visited = 1;
+ node->sum_in_count = 0;
+
+ callers = node->callers;
+ while (callers)
+ {
+ node->sum_in_count += callers->count;
+ callers = callers->next_caller;
+ }
callees = node->callees;
mod_id = get_module_idx_from_func_glob_uid (node->guid);
@@ -895,7 +1030,8 @@ gcov_process_cgraph_node (struct dyn_cgraph_node *node,
{
if (!callees->callee->visited)
gcov_process_cgraph_node (callees->callee,
- cutoff_count);
+ cutoff_count,
+ import_scale);
callees = callees->next_callee;
}
@@ -911,16 +1047,24 @@ gcov_process_cgraph_node (struct dyn_cgraph_node *node,
callee_mod_id
= get_module_idx_from_func_glob_uid (callees->callee->guid);
+ double callee_mod_wt = (double) callees->count;
+ if (callees->callee->imported_modules)
+ {
+ double scale = ((double) callees->count) /
+ ((double) callees->callee->sum_in_count);
+ /* Reduce weight if callee is in different module. */
+ if (mod_id != callee_mod_id)
+ scale = (scale * import_scale) / 100.0;
+ pointer_set_traverse (callees->callee->imported_modules,
+ gcov_propagate_imp_modules,
+ imp_modules, &scale, &callee_mod_wt);
+ }
if (mod_id != callee_mod_id)
{
struct gcov_info *callee_mod_info
= get_module_info (callee_mod_id);
- pointer_set_insert (imp_modules, callee_mod_info);
+ imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt);
}
- if (callees->callee->imported_modules)
- pointer_set_traverse (callees->callee->imported_modules,
- gcov_propagate_imp_modules,
- imp_modules);
}
callees = callees->next_callee;
@@ -930,11 +1074,18 @@ gcov_process_cgraph_node (struct dyn_cgraph_node *node,
/* Compute module grouping using CUTOFF_COUNT as the hot edge
threshold. */
+#define DEFAULT_IMPORT_SCALE 100
static void
gcov_compute_module_groups (gcov_type cutoff_count)
{
unsigned m_ix;
struct gcov_info *gi_ptr;
+ const char *import_scale_str;
+ unsigned import_scale = DEFAULT_IMPORT_SCALE;
+
+ import_scale_str = getenv ("GCOV_DYN_IMPORT_SCALE");
+ if (import_scale_str && strlen (import_scale_str))
+ import_scale = atoi (import_scale_str);
for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
{
@@ -948,11 +1099,13 @@ gcov_compute_module_groups (gcov_type cutoff_count)
struct dyn_cgraph_node *node;
fi_ptr = the_dyn_call_graph.functions[m_ix][f_ix];
- node = &the_dyn_call_graph.call_graph_nodes[m_ix][fi_ptr->ident];
+ node = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
if (node->visited)
continue;
- gcov_process_cgraph_node (node, cutoff_count);
+ gcov_process_cgraph_node (node, cutoff_count, import_scale);
}
}
@@ -970,7 +1123,9 @@ gcov_compute_module_groups (gcov_type cutoff_count)
struct dyn_pointer_set *imp_modules;
fi_ptr = the_dyn_call_graph.functions[m_ix][f_ix];
- node = &the_dyn_call_graph.call_graph_nodes[m_ix][fi_ptr->ident];
+ node = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
if (!node->imported_modules)
continue;
@@ -984,7 +1139,7 @@ gcov_compute_module_groups (gcov_type cutoff_count)
pointer_set_traverse (node->imported_modules,
gcov_propagate_imp_modules,
- imp_modules);
+ imp_modules, 0, 0);
}
}
@@ -995,7 +1150,7 @@ gcov_compute_module_groups (gcov_type cutoff_count)
= &the_dyn_call_graph.sup_modules[m_ix];
if (mi->imported_modules)
pointer_set_traverse (mi->imported_modules,
- gcov_mark_export_modules, 0);
+ gcov_mark_export_modules, 0, 0, 0);
}
}
@@ -1023,7 +1178,7 @@ gcov_compute_random_module_groups (unsigned max_group_size)
if (mod_id == m_ix)
continue;
imp_mod_info = get_module_info (mod_id);
- if (!pointer_set_insert (imp_modules, imp_mod_info))
+ if (!imp_mod_set_insert (imp_modules, imp_mod_info, 1.0))
i++;
}
}
@@ -1035,7 +1190,7 @@ gcov_compute_random_module_groups (unsigned max_group_size)
= &the_dyn_call_graph.sup_modules[m_ix];
if (mi->imported_modules)
pointer_set_traverse (mi->imported_modules,
- gcov_mark_export_modules, 0);
+ gcov_mark_export_modules, 0, 0, 0);
}
}
@@ -1118,7 +1273,7 @@ void
gcov_write_module_infos (struct gcov_info *mod_info)
{
unsigned mod_id, imp_len = 0;
- const struct gcov_info **imp_mods;
+ const struct dyn_imp_mod **imp_mods;
mod_id = get_module_idx (mod_info);
gcov_write_module_info (mod_info, 1);
@@ -1130,7 +1285,7 @@ gcov_write_module_infos (struct gcov_info *mod_info)
for (i = 0; i < imp_len; i++)
{
- const struct gcov_info *imp_mod = imp_mods[i];
+ const struct gcov_info *imp_mod = imp_mods[i]->imp_mod;
gcov_write_module_info (imp_mod, 0);
}
free (imp_mods);
@@ -1186,7 +1341,8 @@ gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node)
/* Dumper function for NODE. M is the module id and F is the function id. */
static void
-gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f)
+gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f,
+ const char *n)
{
unsigned mod_id, func_id;
struct gcov_info *mod_info;
@@ -1199,9 +1355,9 @@ gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f)
mod_info = the_dyn_call_graph.modules[mod_id];
- fprintf (stderr, "NODE(%llx) module(%s) func(%x)\n",
+ fprintf (stderr, "NODE(%llx) module(%s):%s(%x)\n",
(long long) node->guid,
- mod_info->mod_info->source_filename, f);
+ mod_info->mod_info->source_filename, n, f);
/* Now dump callers. */
callers = node->callers;
@@ -1228,13 +1384,12 @@ gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f)
/* Dumper function for NODE. M is the module id and F is the function id. */
static void
-gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
- unsigned m, unsigned f,
- gcov_type cutoff_count)
+gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node, unsigned m,
+ unsigned f, const char * n, gcov_type cutoff_count)
{
unsigned mod_id, func_id, imp_len = 0, i;
struct gcov_info *mod_info;
- const struct gcov_info **imp_mods;
+ const struct dyn_imp_mod **imp_mods;
struct dyn_cgraph_edge *callees;
mod_id = get_module_idx_from_func_glob_uid (node->guid);
@@ -1243,15 +1398,15 @@ gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
mod_info = the_dyn_call_graph.modules[mod_id];
- fprintf (stderr, "NODE_%llx[label=\"MODULE\\n(%s)\\n FUNC(%x)\\n",
- (long long) node->guid, mod_info->mod_info->source_filename, f);
+ fprintf (stderr, "NODE_%llx[label=\"MODULE\\n(%s)\\n %s(%x)\\n",
+ (long long) node->guid, mod_info->mod_info->source_filename, n, f);
imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
fprintf (stderr, "IMPORTS:\\n");
if (imp_mods)
{
for (i = 0; i < imp_len; i++)
- fprintf (stderr, "%s\\n", imp_mods[i]->mod_info->source_filename);
+ fprintf (stderr, "%s\\n", imp_mods[i]->imp_mod->mod_info->source_filename);
fprintf (stderr, "\"]\n");
free (imp_mods);
}
@@ -1302,17 +1457,19 @@ gcov_dump_callgraph (gcov_type cutoff_count)
struct dyn_cgraph_node *node;
fi_ptr = the_dyn_call_graph.functions[m_ix][f_ix];
- node = &the_dyn_call_graph.call_graph_nodes[m_ix][fi_ptr->ident];
+ node = *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
/* skip dead functions */
if (!node->callees && !node->callers)
continue;
if (dyn_cgraph_dump[0] == '1')
- gcov_dump_cgraph_node (node, m_ix, fi_ptr->ident);
+ gcov_dump_cgraph_node (node, m_ix, fi_ptr->ident, fi_ptr->name);
else
gcov_dump_cgraph_node_dot (node, m_ix, fi_ptr->ident,
- cutoff_count);
+ fi_ptr->name, cutoff_count);
}
}
fprintf (stderr,"}\n");