diff mbox

[GOOGLE] Report the difference between profiled and guessed or annotated branch probabilities.

Message ID CADvRsebhLsjHkfWN58tdDU7CmgjDJZ9SDNXFwpq5JWEQLKpECA@mail.gmail.com
State New
Headers show

Commit Message

Yi Yang June 27, 2014, 6:07 p.m. UTC
Hi,

This patch adds an option. When the option is enabled, GCC will add a
record about it in an elf section called
".gnu.switches.text.branch.annotation" for every branch.

gcc/

2014-06-27 Yi Yang <ahyangyi@google.com>

        * auto-profile.c: Main comparison and reporting logic.
        * cfg-flags.def: Add an extra flag representing an edge's
probability is predicted by annotations.
        * predict.c: Set up the extra flag on an edge when appropriate.
        * common.opt: Add an extra GCC option to turn on this report mechanism

Comments

Gerald Pfeifer June 27, 2014, 6:59 p.m. UTC | #1
On Fri, 27 Jun 2014, Yi Yang wrote:
> 2014-06-27 Yi Yang <ahyangyi@google.com>
> 
>         * auto-profile.c: Main comparison and reporting logic.
>         * cfg-flags.def: Add an extra flag representing an edge's
> probability is predicted by annotations.
>         * predict.c: Set up the extra flag on an edge when appropriate.
>         * common.opt: Add an extra GCC option to turn on this report mechanism

Shouldn't there be documentation for this as well?  (In gcc/doc/*.texi?)

Gerald
Andi Kleen June 27, 2014, 7:18 p.m. UTC | #2
Yi Yang <ahyangyi@google.com> writes:

> Hi,
>
> This patch adds an option. When the option is enabled, GCC will add a
> record about it in an elf section called
> ".gnu.switches.text.branch.annotation" for every branch.

This would be nice to have even in mainline for the normal profiling.

-Andi
Yi Yang June 27, 2014, 10:06 p.m. UTC | #3
I'm glad this feature is useful to people.

I haven't looked at the normal profiling process though. If anybody
would like to port this code to normal profiling, I'm more than
pleased to see that happen. Maybe I'll do that myself when I have
time, but do not count on that :)

On Fri, Jun 27, 2014 at 12:18 PM, Andi Kleen <andi@firstfloor.org> wrote:
> Yi Yang <ahyangyi@google.com> writes:
>
>> Hi,
>>
>> This patch adds an option. When the option is enabled, GCC will add a
>> record about it in an elf section called
>> ".gnu.switches.text.branch.annotation" for every branch.
>
> This would be nice to have even in mainline for the normal profiling.
>
> -Andi
>
> --
> ak@linux.intel.com -- Speaking for myself only
Xinliang David Li June 27, 2014, 10:20 p.m. UTC | #4
Hi Yi,

1) please add comments before new functions as documentation -- follow
the coding style guideline
2) missing documenation on the new flags (pointed out by Gerald)
3) Please refactor the check code in afdo_calculate_branch_prob into a
helper function

4) the change log is not needed for google branches, but if provided,
the format should follow the style guide (e.g, function name in () ).

David


On Fri, Jun 27, 2014 at 11:07 AM, Yi Yang <ahyangyi@google.com> wrote:
> Hi,
>
> This patch adds an option. When the option is enabled, GCC will add a
> record about it in an elf section called
> ".gnu.switches.text.branch.annotation" for every branch.
>
> gcc/
>
> 2014-06-27 Yi Yang <ahyangyi@google.com>
>
>         * auto-profile.c: Main comparison and reporting logic.
>         * cfg-flags.def: Add an extra flag representing an edge's
> probability is predicted by annotations.
>         * predict.c: Set up the extra flag on an edge when appropriate.
>         * common.opt: Add an extra GCC option to turn on this report mechanism
diff mbox

Patch

diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c
index 74d3d1d..f7698cd 100644
--- a/gcc/auto-profile.c
+++ b/gcc/auto-profile.c
@@ -40,6 +40,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "opts.h"	      /* for in_fnames.	 */
 #include "tree-pass.h"	      /* for ipa pass.  */
 #include "cfgloop.h"	      /* for loop_optimizer_init.  */
+#include "md5.h"	      /* for hashing function names. */
 #include "gimple.h"
 #include "cgraph.h"
 #include "tree-flow.h"
@@ -1367,6 +1368,80 @@  afdo_propagate (void)
     }
 }
 
+struct locus_information_t {
+  char filename[1024];
+  unsigned lineno;
+  unsigned function_lineno;
+  char function_hash[33];
+};
+
+static bool
+get_locus_information (location_t locus, locus_information_t* li) {
+  if (locus == UNKNOWN_LOCATION || !LOCATION_FILE(locus))
+    return false;
+  snprintf(li->filename, 1024, "%s", LOCATION_FILE(locus));
+  li->lineno = LOCATION_LINE(locus);
+
+  tree block = LOCATION_BLOCK (locus);
+  tree function_decl = current_function_decl;
+  
+  if (block && TREE_CODE (block) == BLOCK)
+    {
+      for (block = BLOCK_SUPERCONTEXT (block);
+	   block && (TREE_CODE (block) == BLOCK);
+	   block = BLOCK_SUPERCONTEXT (block))
+	{
+	  location_t tmp_locus = BLOCK_SOURCE_LOCATION (block);
+	  if (LOCATION_LOCUS (tmp_locus) == UNKNOWN_LOCATION)
+	    continue;
+
+	  tree decl = get_function_decl_from_block (block);
+	  function_decl = decl;
+	  break;
+	}
+    }
+
+  if (!(function_decl && TREE_CODE (function_decl) == FUNCTION_DECL))
+    return false;
+  unsigned function_length = 0;
+  function *f = DECL_STRUCT_FUNCTION(function_decl);
+
+  li->function_lineno = LOCATION_LINE(DECL_SOURCE_LOCATION(function_decl));
+
+  if (f)
+    {
+      function_length = LOCATION_LINE(f->function_end_locus) -
+	li->function_lineno;
+    }
+
+  const char *fn_name = fndecl_name(function_decl);
+  unsigned char md5_result[16];
+
+  md5_ctx ctx;
+
+  md5_init_ctx(&ctx);
+  md5_process_bytes(fn_name, strlen(fn_name), &ctx);
+  md5_process_bytes(&function_length, sizeof(function_length), &ctx);
+  md5_finish_ctx(&ctx, md5_result);
+
+  for (int i = 0; i < 16; ++i)
+    {
+      sprintf(li->function_hash + i*2, "%02x", md5_result[i]);
+    }
+  
+  return true;
+}
+
+void
+fill_invalid_locus_information(locus_information_t* li) {
+  snprintf(li->filename, 1024, "<unknown>");
+  li->lineno = 0;
+  li->function_lineno = 0;
+  for (int i = 0; i < 32; ++i)
+    li->function_hash[i] = '0';
+  li->function_hash[32] = '\0';
+}
+
 /* Propagate counts on control flow graph and calculate branch
    probabilities.  */
 
@@ -1407,8 +1482,62 @@  afdo_calculate_branch_prob (void)
       if (num_unknown_succ == 0 && total_count > 0)
 	{
 	  FOR_EACH_EDGE (e, ei, bb->succs)
-	    e->probability =
-		(double) e->count * REG_BR_PROB_BASE / total_count;
+	    {
+	      double probability =
+		  (double) e->count * REG_BR_PROB_BASE / total_count;
+
+	      if (flag_check_branch_annotation &&
+		  bb->succs->length() == 2 &&
+		  maybe_hot_count_p (cfun, bb->count) &&
+		  bb->count >= 100)
+		{
+		  gimple_stmt_iterator gsi;
+		  gimple last = NULL;
+
+		  for (gsi = gsi_last_nondebug_bb (bb);
+		       !gsi_end_p (gsi);
+		       gsi_prev_nondebug (&gsi))
+		    {
+		      last = gsi_stmt (gsi);
+
+		      if (gimple_has_location (last))
+			break;
+		    }
+
+		  struct locus_information_t li;
+		  bool annotated;
+
+		  if (e->flags & EDGE_PREDICTED_BY_EXPECT)
+		    annotated = true;
+		  else
+		    annotated = false;
+
+		  if (get_locus_information(e->goto_locus, &li))
+		    ;
+		  else if (get_locus_information(gimple_location(last), &li))
+		    ;
+		  else
+		    fill_invalid_locus_information(&li);
+
+		  switch_to_section (get_section (
+		      ".gnu.switches.text.branch.annotation",
+		      SECTION_DEBUG | SECTION_MERGE |
+		      SECTION_STRINGS | (SECTION_ENTSIZE & 1),
+		      NULL));
+		  char buf[1024];
+		  snprintf (buf, 1024, "%s;%u;%d;"
+			    HOST_WIDEST_INT_PRINT_DEC";%.6lf;%.6lf;%s;%u",
+			    li.filename, li.lineno, bb->count, annotated?1:0,
+			    probability/REG_BR_PROB_BASE,
+			    e->probability/(double)REG_BR_PROB_BASE,
+			    li.function_hash, li.function_lineno);
+		  dw2_asm_output_nstring (buf, (size_t)-1, NULL);
+
+		  break;
+		}
+
+	      e->probability = probability;
+	    }
 	}
     }
   FOR_ALL_BB (bb)
@@ -1417,8 +1546,11 @@  afdo_calculate_branch_prob (void)
       edge_iterator ei;
 
       FOR_EACH_EDGE (e, ei, bb->succs)
-	e->count =
-		(double) bb->count * e->probability / REG_BR_PROB_BASE;
+	{
+	  e->count =
+		  (double) bb->count * e->probability / REG_BR_PROB_BASE;
+	  e->flags &= ~EDGE_PREDICTED_BY_EXPECT;
+	}
       bb->aux = NULL;
     }
 
@@ -1542,9 +1674,9 @@  afdo_annotate_cfg (const stmt_set &promoted_stmts)
   afdo_source_profile->mark_annotated (cfun->function_end_locus);
   if (max_count > 0)
     {
+      profile_status = PROFILE_READ;
       afdo_calculate_branch_prob ();
       counts_to_freqs ();
-      profile_status = PROFILE_READ;
     }
   if (flag_value_profile_transformations)
     gimple_value_profile_transformations ();
diff --git a/gcc/cfg-flags.def b/gcc/cfg-flags.def
index 42a0473..5904d8d 100644
--- a/gcc/cfg-flags.def
+++ b/gcc/cfg-flags.def
@@ -186,6 +186,9 @@  DEF_EDGE_FLAG(TM_ABORT, 16)
 /* Annotated during AutoFDO profile attribution.  */
 DEF_EDGE_FLAG(ANNOTATED, 17)
 
+/* Edge probability predicted by __builtin_expect. */
+DEF_EDGE_FLAG(PREDICTED_BY_EXPECT, 18)
+
 #endif
 
 /*
diff --git a/gcc/common.opt b/gcc/common.opt
index 4305c89..5ac159e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -950,6 +950,10 @@  fauto-profile-record-coverage-in-elf
 Common Report Var(flag_auto_profile_record_coverage_in_elf) Optimization
 Whether to record annotation coverage info in elf.
 
+fcheck-branch-annotation
+Common Report Var(flag_check_branch_annotation)
+Record branch prediction information in elf.
+
 ; -fcheck-bounds causes gcc to generate array bounds checks.
 ; For C, C++ and ObjC: defaults off.
 ; For Java: defaults to on.
diff --git a/gcc/predict.c b/gcc/predict.c
index f27c58c..cecc801 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -1014,6 +1014,11 @@  combine_predictions_for_bb (basic_block bb)
     {
       first->probability = combined_probability;
       second->probability = REG_BR_PROB_BASE - combined_probability;
+      if (first_match && best_predictor == PRED_BUILTIN_EXPECT)
+	{
+	  first->flags |= EDGE_PREDICTED_BY_EXPECT;
+	  second->flags |= EDGE_PREDICTED_BY_EXPECT;
+	}
     }
 }

--