diff options
author | Paul Yuan <yingbo.com@gmail.com> | 2008-08-18 19:02:44 +0000 |
---|---|---|
committer | Seongbae Park <spark@gcc.gnu.org> | 2008-08-18 19:02:44 +0000 |
commit | 52c76998c7109adca55106b881b9945fea860015 (patch) | |
tree | 60eb8bcbffe0c58454ecbc0a68eeff80b6a19db3 /gcc/profile.c | |
parent | 808cc41726a4f1b3ab1b87521e086baf3de66432 (diff) | |
download | gcc-52c76998c7109adca55106b881b9945fea860015.zip gcc-52c76998c7109adca55106b881b9945fea860015.tar.gz gcc-52c76998c7109adca55106b881b9945fea860015.tar.bz2 |
cgraph.c (cgraph_edge): Handle inconsistent counts when setting count_scale.
2008-08-18 Paul Yuan <yingbo.com@gmail.com>
Vinodha Ramasamy <vinodha@google.com>
* cgraph.c (cgraph_edge): Handle inconsistent counts when setting
count_scale.
* value-prof.c (check_counter): Fix the counter if
flag_profile_correction is true.
(tree_divmod_fixed_value_transform, tree_mod_pow2_value_transform,
tree_mod_subtract_transform):
Follow check_counter parameter change.
* common.opt (fprofile-correction): New option.
* mcf.c: New file.
* profile.c (edge_info, EDGE_INFO): Moved to new file profile.h.
(sum_edge_counts, is_edge_inconsistent, correct_negative_edge_counts,
is_inconsistent, set_bb_counts, read_profile_edge_counts): New
functions.
(compute_branch_probabilities): Refactored. Invokes mcf_smooth_cfg if
flag_profile_correction is set.
Co-Authored-By: Vinodha Ramasamy <vinodha@google.com>
From-SVN: r139208
Diffstat (limited to 'gcc/profile.c')
-rw-r--r-- | gcc/profile.c | 200 |
1 files changed, 145 insertions, 55 deletions
diff --git a/gcc/profile.c b/gcc/profile.c index 7489579..761c8ad 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -69,21 +69,11 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-pass.h" +#include "profile.h" + /* Hooks for profiling. */ static struct profile_hooks* profile_hooks; -/* Additional information about the edges we need. */ -struct edge_info { - unsigned int count_valid : 1; - - /* Is on the spanning tree. */ - unsigned int on_tree : 1; - - /* Pretend this edge does not exist (it is abnormal and we've - inserted a fake to compensate). */ - unsigned int ignore : 1; -}; - struct bb_info { unsigned int count_valid : 1; @@ -92,7 +82,6 @@ struct bb_info { gcov_type pred_count; }; -#define EDGE_INFO(e) ((struct edge_info *) (e)->aux) #define BB_INFO(b) ((struct bb_info *) (b)->aux) @@ -124,7 +113,6 @@ static gcov_type * get_exec_counts (void); static basic_block find_group (basic_block); static void union_groups (basic_block, basic_block); - /* Add edge instrumentation code to the entire insn chain. F is the first insn of the chain. @@ -278,64 +266,84 @@ get_exec_counts (void) return counts; } - -/* Compute the branch probabilities for the various branches. - Annotate them accordingly. */ + +static bool +is_edge_inconsistent (VEC(edge,gc) *edges) +{ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, edges) + { + if (!EDGE_INFO (e)->ignore) + { + if (e->count < 0) + return true; + } + } + return false; +} static void -compute_branch_probabilities (void) +correct_negative_edge_counts (void) { basic_block bb; - int i; - int num_edges = 0; - int changes; - int passes; - int hist_br_prob[20]; - int num_never_executed; - int num_branches; - gcov_type *exec_counts = get_exec_counts (); - int exec_counts_pos = 0; + edge e; + edge_iterator ei; - /* Very simple sanity checks so we catch bugs in our profiling code. */ - if (profile_info) + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { - if (profile_info->run_max * profile_info->runs < profile_info->sum_max) - { - error ("corrupted profile info: run_max * runs < sum_max"); - exec_counts = NULL; - } + FOR_EACH_EDGE (e, ei, bb->succs) + { + if (e->count < 0) + e->count = 0; + } + } +} - if (profile_info->sum_all < profile_info->sum_max) - { - error ("corrupted profile info: sum_all is smaller than sum_max"); - exec_counts = NULL; - } +/* Check consistency. + Return true if inconsistency is found. */ +static bool +is_inconsistent (void) +{ + basic_block bb; + FOR_EACH_BB (bb) + { + if (is_edge_inconsistent (bb->preds)) + return true; + if (is_edge_inconsistent (bb->succs)) + return true; + if ( bb->count != sum_edge_counts (bb->preds) + || (bb->count != sum_edge_counts (bb->succs) && + !(find_edge (bb, EXIT_BLOCK_PTR) != NULL && + block_ends_with_call_p (bb)))) + return true; } - /* Attach extra info block to each bb. */ + return false; +} - alloc_aux_for_blocks (sizeof (struct bb_info)); +/* Set each basic block count to the sum of its outgoing edge counts */ +static void +set_bb_counts (void) +{ + basic_block bb; FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { - edge e; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, bb->succs) - if (!EDGE_INFO (e)->ignore) - BB_INFO (bb)->succ_count++; - FOR_EACH_EDGE (e, ei, bb->preds) - if (!EDGE_INFO (e)->ignore) - BB_INFO (bb)->pred_count++; + bb->count = sum_edge_counts (bb->succs); + gcc_assert (bb->count >= 0); } +} - /* Avoid predicting entry on exit nodes. */ - BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2; - BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2; - +/* Reads profile data and returns total number of edge counts read */ +static int +read_profile_edge_counts (gcov_type *exec_counts) +{ + basic_block bb; + int num_edges = 0; + int exec_counts_pos = 0; /* For each edge not on the spanning tree, set its execution count from the .da file. */ - /* The first count in the .da file is the number of times that the function was entered. This is the exec_count for block zero. */ @@ -373,6 +381,63 @@ compute_branch_probabilities (void) } } + return num_edges; +} + +/* Compute the branch probabilities for the various branches. + Annotate them accordingly. */ + +static void +compute_branch_probabilities (void) +{ + basic_block bb; + int i; + int num_edges = 0; + int changes; + int passes; + int hist_br_prob[20]; + int num_never_executed; + int num_branches; + gcov_type *exec_counts = get_exec_counts (); + int inconsistent = 0; + + /* Very simple sanity checks so we catch bugs in our profiling code. */ + if (profile_info) + { + if (profile_info->run_max * profile_info->runs < profile_info->sum_max) + { + error ("corrupted profile info: run_max * runs < sum_max"); + exec_counts = NULL; + } + + if (profile_info->sum_all < profile_info->sum_max) + { + error ("corrupted profile info: sum_all is smaller than sum_max"); + exec_counts = NULL; + } + } + + /* Attach extra info block to each bb. */ + alloc_aux_for_blocks (sizeof (struct bb_info)); + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) + { + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (!EDGE_INFO (e)->ignore) + BB_INFO (bb)->succ_count++; + FOR_EACH_EDGE (e, ei, bb->preds) + if (!EDGE_INFO (e)->ignore) + BB_INFO (bb)->pred_count++; + } + + /* Avoid predicting entry on exit nodes. */ + BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2; + BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2; + + num_edges = read_profile_edge_counts (exec_counts); + if (dump_file) fprintf (dump_file, "\n%d edge counts read\n", num_edges); @@ -502,6 +567,31 @@ compute_branch_probabilities (void) gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count); } + /* Check for inconsistent basic block counts */ + inconsistent = is_inconsistent (); + + if (inconsistent) + { + if (flag_profile_correction) + { + /* Inconsistency detected. Make it flow-consistent. */ + static int informed = 0; + if (informed == 0) + { + informed = 1; + inform ("correcting inconsistent profile data"); + } + correct_negative_edge_counts (); + /* Set bb counts to the sum of the outgoing edge counts */ + set_bb_counts (); + if (dump_file) + fprintf (dump_file, "\nCalling mcf_smooth_cfg\n"); + mcf_smooth_cfg (); + } + else + error ("corrupted profile info: profile data is not flow-consistent"); + } + /* For every edge, calculate its branch probability and add a reg_note to the branch insn to indicate this. */ |