This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Add quality tracking for profile counter


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  10000
@@ -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;
     }
   profile_count operator+ (const profile_count &other) const
     {
@@ -136,6 +158,7 @@ public:
 
       profile_count ret;
       ret.m_val = m_val + other.m_val;
+      ret.m_quality = MIN (m_quality, other.m_quality);
       return ret;
     }
   profile_count &operator+= (const profile_count &other)
@@ -150,7 +173,10 @@ public:
       if (!initialized_p () || !other.initialized_p ())
 	return *this = profile_count::uninitialized ();
       else
-	m_val += other.m_val;
+	{
+	  m_val += other.m_val;
+          m_quality = MIN (m_quality, other.m_quality);
+	}
       return *this;
     }
   profile_count operator- (const profile_count &other) const
@@ -160,7 +186,8 @@ public:
       if (!initialized_p () || !other.initialized_p ())
 	return profile_count::uninitialized ();
       profile_count ret;
-      ret.m_val = MAX (m_val - other.m_val, 0);
+      ret.m_val = m_val >= other.m_val ? m_val - other.m_val : 0;
+      ret.m_quality = MIN (m_quality, other.m_quality);
       return ret;
     }
   profile_count &operator-= (const profile_count &other)
@@ -170,14 +197,17 @@ public:
       if (!initialized_p () || !other.initialized_p ())
 	return *this = profile_count::uninitialized ();
       else
-	m_val = MAX (m_val - other.m_val, 0);
+	{
+	  m_val = m_val >= other.m_val ? m_val - other.m_val: 0;
+          m_quality = MIN (m_quality, other.m_quality);
+	}
       return *this;
     }
 
   /* Return false if profile_count is bogus.  */
   bool verify () const
     {
-      return m_val >= -1;
+      return m_val != uninitialized_count || m_quality == count_guessed;
     }
 
   /* Comparsions are three-state and conservative.  False is returned if
@@ -192,11 +222,13 @@ public:
     }
   bool operator< (const gcov_type other) const
     {
-      return initialized_p () && m_val < other;
+      gcc_checking_assert (other >= 0);
+      return initialized_p () && m_val < (uint64_t) other;
     }
   bool operator> (const gcov_type other) const
     {
-      return initialized_p () && m_val > other;
+      gcc_checking_assert (other >= 0);
+      return initialized_p () && m_val > (uint64_t) other;
     }
 
   bool operator<= (const profile_count &other) const
@@ -209,11 +241,13 @@ public:
     }
   bool operator<= (const gcov_type other) const
     {
-      return initialized_p () && m_val <= other;
+      gcc_checking_assert (other >= 0);
+      return initialized_p () && m_val <= (uint64_t) other;
     }
   bool operator>= (const gcov_type other) const
     {
-      return initialized_p () && m_val >= other;
+      gcc_checking_assert (other >= 0);
+      return initialized_p () && m_val >= (uint64_t) other;
     }
 
   /* PROB is a probability in scale 0...REG_BR_PROB_BASE.  Scale counter
@@ -227,6 +261,7 @@ public:
 	return profile_count::uninitialized ();
       profile_count ret;
       ret.m_val = RDIV (m_val * prob, REG_BR_PROB_BASE);
+      ret.m_quality = MIN (m_quality, count_adjusted);
       return ret;
     }
   /* Return *THIS * NUM / DEN.  */
@@ -243,6 +278,7 @@ public:
 			        || den <= REG_BR_PROB_BASE)
 			    && den > 0) || 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
@@ -251,14 +287,18 @@ public:
 	return profile_count::zero ();
       if (!initialized_p () || !num.initialized_p () || !den.initialized_p ())
 	return profile_count::uninitialized ();
-      profile_count ret;
       gcc_checking_assert (den > 0);
+      if (num == den)
+	return *this;
+
+      profile_count ret;
       /* Take care for overflows!  */
       if (num.m_val < max_safe_multiplier || m_val < max_safe_multiplier)
         ret.m_val = RDIV (m_val * num.m_val, den.m_val);
       else
         ret.m_val = RDIV (m_val * RDIV (num.m_val * max_safe_multiplier,
 					den.m_val), max_safe_multiplier);
+      ret.m_quality = MIN (m_quality, count_adjusted);
       return ret;
     }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]