X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fprofile.c;h=ac460464697cef6abbb60cb8bce2fac952a26c97;hb=2abf995f90bb8441b573eba4ea14c0b8e0c1bba9;hp=b6cddc2295f81146ad40ae43fc297f2c48df3c24;hpb=75a70cf95f65fe9204b15ad9aba31c571381d224;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/profile.c b/gcc/profile.c index b6cddc2295f..ac460464697 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -1,6 +1,6 @@ /* Calculate branch probabilities, and basic block execution counts. Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 + 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by James E. Wilson, UC Berkeley/Cygnus Support; based on some ideas from Dain Samples of UC Berkeley. @@ -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) @@ -111,7 +100,6 @@ static int total_num_blocks_created; static int total_num_passes; static int total_num_times_called; static int total_hist_br_prob[20]; -static int total_num_never_executed; static int total_num_branches; /* Forward declarations. */ @@ -124,7 +112,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 +265,135 @@ 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 + && (!(e->flags & EDGE_FAKE) + || !block_ends_with_call_p (e->src))) + { + if (dump_file) + { + fprintf (dump_file, + "Edge %i->%i is inconsistent, count"HOST_WIDEST_INT_PRINT_DEC, + e->src->index, e->dest->index, e->count); + dump_bb (e->src, dump_file, 0); + dump_bb (e->dest, dump_file, 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) +/* Check consistency. + Return true if inconsistency is found. */ +static bool +is_inconsistent (void) +{ + basic_block bb; + bool inconsistent = false; + FOR_EACH_BB (bb) + { + inconsistent |= is_edge_inconsistent (bb->preds); + if (!dump_file && inconsistent) + return true; + inconsistent |= is_edge_inconsistent (bb->succs); + if (!dump_file && inconsistent) + return true; + if (bb->count < 0) + { + if (dump_file) + { + fprintf (dump_file, "BB %i count is negative " + HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; + } + if (bb->count != sum_edge_counts (bb->preds)) + { + if (dump_file) + { + fprintf (dump_file, "BB %i count does not match sum of incoming edges " + HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count, + sum_edge_counts (bb->preds)); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; + } + if (bb->count != sum_edge_counts (bb->succs) && + ! (find_edge (bb, EXIT_BLOCK_PTR) != NULL && block_ends_with_call_p (bb))) { - error ("corrupted profile info: sum_all is smaller than sum_max"); - exec_counts = NULL; + if (dump_file) + { + fprintf (dump_file, "BB %i count does not match sum of outgoing edges " + HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count, + sum_edge_counts (bb->succs)); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; } + if (!dump_file && inconsistent) + return true; } - /* Attach extra info block to each bb. */ + return inconsistent; +} - 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 +431,61 @@ 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_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) + return; + 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,12 +615,36 @@ 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 (input_location, "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. */ for (i = 0; i < 20; i++) hist_br_prob[i] = 0; - num_never_executed = 0; num_branches = 0; FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) @@ -601,16 +738,15 @@ compute_branch_probabilities (void) if (bb->index >= NUM_FIXED_BLOCKS && block_ends_with_condjump_p (bb) && EDGE_COUNT (bb->succs) >= 2) - num_branches++, num_never_executed; + num_branches++; } } counts_to_freqs (); + profile_status = PROFILE_READ; if (dump_file) { fprintf (dump_file, "%d branches\n", num_branches); - fprintf (dump_file, "%d branches never executed\n", - num_never_executed); if (num_branches) for (i = 0; i < 10; i++) fprintf (dump_file, "%d%% branches in range %d-%d%%\n", @@ -618,7 +754,6 @@ compute_branch_probabilities (void) 5 * i, 5 * i + 5); total_num_branches += num_branches; - total_num_never_executed += num_never_executed; for (i = 0; i < 20; i++) total_hist_br_prob[i] += hist_br_prob[i]; @@ -640,7 +775,7 @@ compute_value_histograms (histogram_values values) gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS]; gcov_type *act_count[GCOV_N_VALUE_COUNTERS]; gcov_type *aact_count; - + for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) n_histogram_counters[t] = 0; @@ -808,8 +943,8 @@ branch_prob (void) } /* Edge with goto locus might get wrong coverage info unless - it is the only edge out of BB. - Don't do that when the locuses match, so + it is the only edge out of BB. + Don't do that when the locuses match, so if (blah) goto something; is not computed twice. */ if (last @@ -819,10 +954,12 @@ branch_prob (void) && (LOCATION_FILE (e->goto_locus) != LOCATION_FILE (gimple_location (last)) || (LOCATION_LINE (e->goto_locus) - != LOCATION_LINE (gimple_location (last))))) + != LOCATION_LINE (gimple_location (last))))) { - basic_block new = split_edge (e); - single_succ_edge (new)->goto_locus = e->goto_locus; + basic_block new_bb = split_edge (e); + edge ne = single_succ_edge (new_bb); + ne->goto_locus = e->goto_locus; + ne->goto_block = e->goto_block; } if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL)) && e->dest != EXIT_BLOCK_PTR) @@ -990,7 +1127,7 @@ branch_prob (void) if (bb == ENTRY_BLOCK_PTR->next_bb) { - expanded_location curr_location = + expanded_location curr_location = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); output_location (curr_location.file, curr_location.line, &offset, bb); @@ -1064,8 +1201,6 @@ branch_prob (void) VEC_free (histogram_value, heap, values); free_edge_list (el); - if (flag_branch_probabilities) - profile_status = PROFILE_READ; coverage_end_function (); } @@ -1192,7 +1327,6 @@ init_branch_prob (void) total_num_passes = 0; total_num_times_called = 0; total_num_branches = 0; - total_num_never_executed = 0; for (i = 0; i < 20; i++) total_hist_br_prob[i] = 0; } @@ -1223,8 +1357,6 @@ end_branch_prob (void) / total_num_times_called); fprintf (dump_file, "Total number of branches: %d\n", total_num_branches); - fprintf (dump_file, "Total number of branches never executed: %d\n", - total_num_never_executed); if (total_num_branches) { int i;