Re: Add quality tracking for profile counter

2017-06-22 Thread Jan Hubicka
Hi,
I proofread the code and noticed that in some cases I may trigger division by 0 
that may
get different outputs depending on optimization setting on Itanium.

This is what I comitted after profiledbootstrap and regtesting at x86_64.

* profile-count.h (apply_probability,
apply_scale, probability_in): Fix checks for zero.
Index: profile-count.h
===
--- profile-count.h (revision 249364)
+++ profile-count.h (working copy)
@@ -255,7 +255,7 @@ public:
   profile_count apply_probability (int prob) const
 {
   gcc_checking_assert (prob >= 0 && prob <= REG_BR_PROB_BASE);
-  if (*this == profile_count::zero ())
+  if (m_val == 0)
return *this;
   if (!initialized_p ())
return profile_count::uninitialized ();
@@ -267,24 +267,25 @@ public:
   /* Return *THIS * NUM / DEN.  */
   profile_count apply_scale (int64_t num, int64_t den) const
 {
-  if (*this == profile_count::zero ())
+  if (m_val == 0)
return *this;
   if (!initialized_p ())
return profile_count::uninitialized ();
   profile_count ret;
+  gcc_checking_assert (num >= 0 && den > 0);
   /* FIXME: shrink wrapping violates this sanity check.  */
-  gcc_checking_assert ((num >= 0
-   && (num <= REG_BR_PROB_BASE
-   || den <= REG_BR_PROB_BASE)
-   && den > 0) || 1);
+  gcc_checking_assert ((num <= REG_BR_PROB_BASE
+   || den <= REG_BR_PROB_BASE) || 1);
   ret.m_val = RDIV (m_val * num, den);
   ret.m_quality = MIN (m_quality, count_adjusted);
   return ret;
 }
   profile_count apply_scale (profile_count num, profile_count den) const
 {
-  if (*this == profile_count::zero () || num == profile_count::zero ())
-   return profile_count::zero ();
+  if (m_val == 0)
+   return *this;
+  if (num.m_val == 0)
+   return num;
   if (!initialized_p () || !num.initialized_p () || !den.initialized_p ())
return profile_count::uninitialized ();
   gcc_checking_assert (den > 0);
@@ -306,7 +307,7 @@ public:
  OVERALL.  */
   int probability_in (profile_count overall)
 {
-  if (*this == profile_count::zero ())
+  if (!m_val)
return 0;
   if (!initialized_p () || !overall.initialized_p ())
return REG_BR_PROB_BASE / 2;


Re: Add quality tracking for profile counter

2017-06-21 Thread Andreas Schwab
On Jun 19 2017, Jan Hubicka  wrote:

> this patch makes us to track quality of the profile.  This is useful
> to disable some agressive optimizations when counts are known to be
> unreliable.

This breaks bootstrap on ia64 with a comparison failure in value-prof.o.

The only difference is in gimple_value_profile_transformations:

@@ -8962,14 +8962,14 @@ Disassembly of section .text:
 ad06:  10 00 a0 01 42 80   mov r1=r104
 ad0c:  0d e0 02 84 mov r108=r92;;
 ad10:  09 00 cc 1c 90 11   [MMI]   st4 [r14]=r51
-ad16:  e0 00 20 30 20 60   ld8 r14=[r8]
+ad16:  00 00 00 02 00 60   nop.m 0x0
 ad1c:  0d 08 01 84 mov r107=r33;;
-ad20:  0b 70 d8 1c 0c 20   [MMI]   and r14=r54,r14;;
-ad26:  e0 38 39 1c 40 00   or r14=r39,r14
+ad20:  0b 70 00 10 18 10   [MMI]   ld8 r14=[r8];;
+ad26:  e0 b0 39 18 40 00   and r14=r54,r14
 ad2c:  00 00 04 00 nop.i 0x0;;
-ad30:  01 00 00 00 01 00   [MII]   nop.m 0x0
-ad36:  e0 90 39 22 20 00   dep r14=r50,r14,62,2
-ad3c:  00 00 04 00 nop.i 0x0;;
+ad30:  0b 70 9c 1c 0e 20   [MMI]   or r14=r39,r14;;
+ad36:  00 00 00 02 00 c0   nop.m 0x0
+ad3c:  21 73 44 40 dep r14=r50,r14,62,2;;
 ad40:  09 00 38 10 98 11   [MMI]   st8 [r8]=r14
 ad46:  00 98 41 20 23 00   st4 [r16]=r51
 ad4c:  00 00 04 00 nop.i 0x0;;


Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Add quality tracking for profile counter

2017-06-19 Thread Jan Hubicka
Hi,
this patch makes us to track quality of the profile.  This is useful
to disable some agressive optimizations when counts are known to be
unreliable.

Bootstrapped/regtested x86_64-linux,
Honza
* profile-count.c (profile_count::dump): Dump quality.
(profile_count::differs_from_p): Update for unsigned val.
* profile-count.h (profile_count_quality): New enum.
(profile_count): Turn m_val to 62bit unsigned, add quality tracking.
Index: profile-count.c
===
--- profile-count.c (revision 249347)
+++ profile-count.c (working copy)
@@ -37,7 +37,15 @@ profile_count::dump (FILE *f) const
   if (!initialized_p ())
 fprintf (f, "uninitialized");
   else
-fprintf (f, "%" PRId64, m_val);
+{
+  fprintf (f, "%" PRId64, m_val);
+  if (m_quality == count_adjusted)
+   fprintf (f, "(adjusted)");
+  else if (m_quality == count_afdo)
+   fprintf (f, "(auto FDO)");
+  else if (m_quality == count_guessed)
+   fprintf (f, "(guessed)");
+}
 }
 
 void
@@ -51,7 +59,7 @@ profile_count::differs_from_p (profile_c
 {
   if (!initialized_p () || !other.initialized_p ())
 return false;
-  if (m_val - other.m_val < 100 && other.m_val - m_val < 100)
+  if (m_val - other.m_val < 100 || other.m_val - m_val < 100)
 return false;
   if (!other.m_val)
 return true;
@@ -64,6 +72,7 @@ profile_count::stream_in (struct lto_inp
 {
   profile_count ret;
   ret.m_val = streamer_read_gcov_count (ib);
+  ret.m_quality = (profile_count_quality) streamer_read_uhwi (ib);
   return ret;
 }
 
@@ -71,10 +80,12 @@ void
 profile_count::stream_out (struct output_block *ob)
 {
   streamer_write_gcov_count (ob, m_val);
+  streamer_write_uhwi (ob, m_quality);
 }
 
 void
 profile_count::stream_out (struct lto_output_stream *ob)
 {
   streamer_write_gcov_count_stream (ob, m_val);
+  streamer_write_uhwi_stream (ob, m_quality);
 }
Index: profile-count.h
===
--- profile-count.h (revision 249347)
+++ profile-count.h (working copy)
@@ -21,6 +21,22 @@ along with GCC; see the file COPYING3.
 #ifndef GCC_PROFILE_COUNT_H
 #define GCC_PROFILE_COUNT_H
 
+/* Quality of the proflie count.  Because gengtype does not support enums
+   inside of clases, this is in global namespace.  */
+enum profile_count_quality {
+  /* Profile is based on static branch prediction heuristics.  It may or may
+ not reflect the reality.  */
+  count_guessed = 0,
+  /* Profile was determined by autofdo.  */
+  count_afdo = 1,
+  /* Profile was originally based on feedback but it was adjusted 
+ by code duplicating optimization.  It may not precisely reflect the
+ particular code path.  */
+  count_adjusted = 2,
+  /* Profile was read from profile feedback or determined by accurate static
+ method.  */
+  count_read = 3
+};
 
 /* The base value for branch probability notes and edge probabilities.  */
 #define REG_BR_PROB_BASE  1
@@ -58,17 +74,21 @@ along with GCC; see the file COPYING3.
 
  */
 
-
 class GTY(()) profile_count
 {
-  /* Use int64_t to hold basic block counters.  Should be at least
+  /* Use 62bit to hold basic block counters.  Should be at least
  64bit.  Although a counter cannot be negative, we use a signed
  type to hold various extra stages.  */
 
-  int64_t m_val;
+  static const int n_bits = 62;
+  static const uint64_t max_count = ((uint64_t) 1 << n_bits) - 2;
+  static const uint64_t uninitialized_count = ((uint64_t) 1 << n_bits) - 1;
+
+  uint64_t m_val : n_bits;
+  enum profile_count_quality m_quality : 2;
 
   /* Assume numbers smaller than this to multiply.  This is set to make
- testsuite pass, in future we may implement precise multiples in higer
+ testsuite pass, in future we may implement precise multiplication in higer
  rangers.  */
   static const int64_t max_safe_multiplier = 131072;
 public:
@@ -87,7 +107,8 @@ public:
   static profile_count uninitialized ()
 {
   profile_count c;
-  c.m_val = -1;
+  c.m_val = uninitialized_count;
+  c.m_quality = count_guessed;
   return c;
 }
 
@@ -97,8 +118,9 @@ public:
   static profile_count from_gcov_type (gcov_type v)
 {
   profile_count ret;
-  gcc_checking_assert (v>=0);
+  gcc_checking_assert (v >= 0 && (uint64_t) v <= max_count);
   ret.m_val = v;
+  ret.m_quality = count_read;
   return ret;
 }
 
@@ -112,7 +134,7 @@ public:
   /* Return true if value has been initialized.  */
   bool initialized_p () const
 {
-  return m_val != -1;
+  return m_val != uninitialized_count;
 }
   /* Return true if value can be trusted.  */
   bool reliable_p () const
@@ -123,7 +145,7 @@ public:
   /* Basic operations.  */
   bool operator== (const profile_count &other) const
 {
-  return m_val == other.m_val;
+  return m_val == other.m_val && m_quality == other.m_quality;
 }
   profil