From 37e5402bb30e9c81fa62393c112f56a5cfe42e16 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 6 Oct 2012 16:06:04 +0200 Subject: [PATCH] invoke.texi (-fprofile-report): Document. * doc/invoke.texi (-fprofile-report): Document. * common.opt (-fprofile-report): New option. * toplev.c (finalize): Call dump_profile_report. * toplev.h (profile_report): Declare. * passes.c (profile_record): New static var. (check_profile_consistency): New function. (dump_profile_record): New function. (execute_one_ipa_transform_pass): Call check_profile_consistency. (execute_one_pass): Likewise. From-SVN: r192161 --- gcc/ChangeLog | 12 +++ gcc/common.opt | 4 + gcc/doc/invoke.texi | 7 +- gcc/passes.c | 221 ++++++++++++++++++++++++++++++++++++++++++++ gcc/toplev.c | 3 + gcc/toplev.h | 1 + 6 files changed, 247 insertions(+), 1 deletion(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 74b3f0ea217..649f45eebb9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2012-10-06 Jan Hubicka + + * doc/invoke.texi (-fprofile-report): Document. + * common.opt (-fprofile-report): New option. + * toplev.c (finalize): Call dump_profile_report. + * toplev.h (profile_report): Declare. + * passes.c (profile_record): New static var. + (check_profile_consistency): New function. + (dump_profile_record): New function. + (execute_one_ipa_transform_pass): Call check_profile_consistency. + (execute_one_pass): Likewise. + 2012-10-06 Jan Hubicka PR lto/54790 diff --git a/gcc/common.opt b/gcc/common.opt index f0e757ca6fa..6de670b8ae5 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1654,6 +1654,10 @@ fprofile-values Common Report Var(flag_profile_values) Insert code to profile values of expressions +fprofile-report +Common Report Var(profile_report) +Report on consistency of profile + frandom-seed Common Var(common_deferred_options) Defer diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 297b651adfe..711c1513373 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -388,7 +388,7 @@ Objective-C and Objective-C++ Dialects}. -fno-toplevel-reorder -fno-trapping-math -fno-zero-initialized-in-bss @gol -fomit-frame-pointer -foptimize-register-move -foptimize-sibling-calls @gol -fpartial-inlining -fpeel-loops -fpredictive-commoning @gol --fprefetch-loop-arrays @gol +-fprefetch-loop-arrays -fprofile-report @gol -fprofile-correction -fprofile-dir=@var{path} -fprofile-generate @gol -fprofile-generate=@var{path} @gol -fprofile-use -fprofile-use=@var{path} -fprofile-values @gol @@ -5153,6 +5153,11 @@ allocation for the WPA phase only. Makes the compiler print some statistics about permanent memory allocation before or after interprocedural optimization. +@item -fprofile-report +@opindex fprofile-report +Makes the compiler print some statistics about consistency of the +(estimated) profile and effect of individual passes. + @item -fstack-usage @opindex fstack-usage Makes the compiler output stack usage information for the program, on a diff --git a/gcc/passes.c b/gcc/passes.c index 86c8255450c..1b0a1967020 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1778,6 +1778,209 @@ execute_function_dump (void *data ATTRIBUTE_UNUSED) } } +/* Make statistic about profile consistency. */ + +struct profile_record +{ + int num_mismatched_freq_in[2]; + int num_mismatched_freq_out[2]; + int num_mismatched_count_in[2]; + int num_mismatched_count_out[2]; + bool run; + gcov_type time[2]; + int size[2]; +}; + +static struct profile_record *profile_record; + +static void +check_profile_consistency (int index, int subpass, bool run) +{ + basic_block bb; + edge_iterator ei; + edge e; + int sum; + gcov_type lsum; + + if (index == -1) + return; + if (!profile_record) + profile_record = XCNEWVEC (struct profile_record, + passes_by_id_size); + gcc_assert (index < passes_by_id_size && index >= 0); + gcc_assert (subpass < 2); + profile_record[index].run |= run; + + FOR_ALL_BB (bb) + { + if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun) + && profile_status != PROFILE_ABSENT) + { + sum = 0; + FOR_EACH_EDGE (e, ei, bb->succs) + sum += e->probability; + if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100) + profile_record[index].num_mismatched_freq_out[subpass]++; + lsum = 0; + FOR_EACH_EDGE (e, ei, bb->succs) + lsum += e->count; + if (EDGE_COUNT (bb->succs) + && (lsum - bb->count > 100 || lsum - bb->count < -100)) + profile_record[index].num_mismatched_count_out[subpass]++; + } + if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) + && profile_status != PROFILE_ABSENT) + { + sum = 0; + FOR_EACH_EDGE (e, ei, bb->preds) + sum += EDGE_FREQUENCY (e); + if (abs (sum - bb->frequency) > 100 + || (MAX (sum, bb->frequency) > 10 + && abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10)) + profile_record[index].num_mismatched_freq_in[subpass]++; + lsum = 0; + FOR_EACH_EDGE (e, ei, bb->preds) + lsum += e->count; + if (lsum - bb->count > 100 || lsum - bb->count < -100) + profile_record[index].num_mismatched_count_in[subpass]++; + } + if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun) + || bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)) + continue; + if ((cfun && (cfun->curr_properties & PROP_trees))) + { + gimple_stmt_iterator i; + + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + profile_record[index].size[subpass] + += estimate_num_insns (gsi_stmt (i), &eni_size_weights); + if (profile_status == PROFILE_READ) + profile_record[index].time[subpass] + += estimate_num_insns (gsi_stmt (i), + &eni_time_weights) * bb->count; + else if (profile_status == PROFILE_GUESSED) + profile_record[index].time[subpass] + += estimate_num_insns (gsi_stmt (i), + &eni_time_weights) * bb->frequency; + } + } + else if (cfun && (cfun->curr_properties & PROP_rtl)) + { + rtx insn; + for (insn = NEXT_INSN (BB_HEAD (bb)); insn && insn != NEXT_INSN (BB_END (bb)); + insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + profile_record[index].size[subpass] + += insn_rtx_cost (PATTERN (insn), false); + if (profile_status == PROFILE_READ) + profile_record[index].time[subpass] + += insn_rtx_cost (PATTERN (insn), true) * bb->count; + else if (profile_status == PROFILE_GUESSED) + profile_record[index].time[subpass] + += insn_rtx_cost (PATTERN (insn), true) * bb->frequency; + } + } + } +} + +/* Output profile consistency. */ + +void +dump_profile_report (void) +{ + int i, j; + int last_freq_in = 0, last_count_in = 0, last_freq_out = 0, last_count_out = 0; + gcov_type last_time, last_size; + double rel_time_change, rel_size_change; + int last_reported; + + if (!profile_record) + return; + fprintf (stderr, "\nProfile consistency report:\n\n"); + fprintf (stderr, "Pass name |mismatch in |mismated out|Overall\n"); + fprintf (stderr, " |freq count |freq count |size time\n"); + + for (i = 0; i < passes_by_id_size; i++) + for (j = 0 ; j < 2; j++) + if (profile_record[i].run) + { + if (last_time) + rel_time_change = (profile_record[i].time[j] + - (double)last_time) * 100 / (double)last_time; + else + rel_time_change = 0; + if (last_size) + rel_size_change = (profile_record[i].size[j] + - (double)last_size) * 100 / (double)last_size; + else + rel_size_change = 0; + + if (profile_record[i].num_mismatched_freq_in[j] != last_freq_in + || profile_record[i].num_mismatched_freq_out[j] != last_freq_out + || profile_record[i].num_mismatched_count_in[j] != last_count_in + || profile_record[i].num_mismatched_count_out[j] != last_count_out + || rel_time_change || rel_size_change) + { + last_reported = i; + fprintf (stderr, "%-20s %s", + passes_by_id [i]->name, + j ? "(after TODO)" : " "); + if (profile_record[i].num_mismatched_freq_in[j] != last_freq_in) + fprintf (stderr, "| %+5i", + profile_record[i].num_mismatched_freq_in[j] + - last_freq_in); + else + fprintf (stderr, "| "); + if (profile_record[i].num_mismatched_count_in[j] != last_count_in) + fprintf (stderr, " %+5i", + profile_record[i].num_mismatched_count_in[j] + - last_count_in); + else + fprintf (stderr, " "); + if (profile_record[i].num_mismatched_freq_out[j] != last_freq_out) + fprintf (stderr, "| %+5i", + profile_record[i].num_mismatched_freq_out[j] + - last_freq_out); + else + fprintf (stderr, "| "); + if (profile_record[i].num_mismatched_count_out[j] != last_count_out) + fprintf (stderr, " %+5i", + profile_record[i].num_mismatched_count_out[j] + - last_count_out); + else + fprintf (stderr, " "); + + /* Size/time units change across gimple and RTL. */ + if (i == pass_expand.pass.static_pass_number) + fprintf (stderr, "|----------"); + else + { + if (rel_size_change) + fprintf (stderr, "| %+8.4f%%", rel_size_change); + else + fprintf (stderr, "| "); + if (rel_time_change) + fprintf (stderr, " %+8.4f%%", rel_time_change); + } + fprintf (stderr, "\n"); + last_freq_in = profile_record[i].num_mismatched_freq_in[j]; + last_freq_out = profile_record[i].num_mismatched_freq_out[j]; + last_count_in = profile_record[i].num_mismatched_count_in[j]; + last_count_out = profile_record[i].num_mismatched_count_out[j]; + } + else if (j && last_reported != i) + { + last_reported = i; + fprintf (stderr, "%-20s ------------| | |\n", + passes_by_id [i]->name); + } + last_time = profile_record[i].time[j]; + last_size = profile_record[i].size[j]; + } +} + /* Perform all TODO actions that ought to be done on each function. */ static void @@ -2042,9 +2245,14 @@ execute_one_ipa_transform_pass (struct cgraph_node *node, if (pass->tv_id != TV_NONE) timevar_pop (pass->tv_id); + if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) + check_profile_consistency (pass->static_pass_number, 0, true); + /* Run post-pass cleanup and verification. */ execute_todo (todo_after); verify_interpass_invariants (); + if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) + check_profile_consistency (pass->static_pass_number, 1, true); do_per_function (execute_function_dump, NULL); pass_fini_dump_file (pass); @@ -2144,6 +2352,13 @@ execute_one_pass (struct opt_pass *pass) if (!gate_status) { + /* Run so passes selectively disabling themselves on a given function + are not miscounted. */ + if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) + { + check_profile_consistency (pass->static_pass_number, 0, false); + check_profile_consistency (pass->static_pass_number, 1, false); + } current_pass = NULL; return false; } @@ -2210,8 +2425,14 @@ execute_one_pass (struct opt_pass *pass) clean_graph_dump_file (dump_file_name); } + if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) + check_profile_consistency (pass->static_pass_number, 0, true); + /* Run post-pass cleanup and verification. */ execute_todo (todo_after | pass->todo_flags_finish); + if (profile_report && cfun && (cfun->curr_properties & PROP_cfg)) + check_profile_consistency (pass->static_pass_number, 1, true); + verify_interpass_invariants (); do_per_function (execute_function_dump, NULL); if (pass->type == IPA_PASS) diff --git a/gcc/toplev.c b/gcc/toplev.c index 2aa3e40004b..04c17368101 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1815,6 +1815,9 @@ finalize (bool no_backend) if (mem_report) dump_memory_report (true); + if (dump_profile_report) + dump_profile_report (); + /* Language-specific end of compilation actions. */ lang_hooks.finish (); } diff --git a/gcc/toplev.h b/gcc/toplev.h index 307fb64ad57..9a41e075371 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -49,6 +49,7 @@ extern void emit_debug_global_declarations (tree *, int); extern void write_global_declarations (void); extern void dump_memory_report (bool); +extern void dump_profile_report (void); extern void target_reinit (void);