profile-count.c (profile_count::dump): Dump quality.
authorJan Hubicka <hubicka@ucw.cz>
Mon, 19 Jun 2017 09:47:31 +0000 (11:47 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 19 Jun 2017 09:47:31 +0000 (09:47 +0000)
* 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.

From-SVN: r249360

gcc/ChangeLog
gcc/profile-count.c
gcc/profile-count.h

index 49a8109df1d247c079e6df26126ed1cf27a62bb6..78ded852f32755e06a3045390a500d43c39f10c4 100644 (file)
@@ -1,3 +1,10 @@
+2017-06-19  Jan Hubicka <hubicka@ucw.cz>
+
+       * 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.
+
 2017-06-19  Richard Biener  <rguenther@suse.de>
 
        * tree-ssa-loop-niter.h (estimate_numbers_of_iterations): Take
index 5ad7178c15978be2d53e547cf1ccdfa505c87f92..e64d1b564214c0ebf99ce753b7aee5c071447fe8 100644 (file)
@@ -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_count other) const
 {
   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_input_block *ib)
 {
   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 78ffee99ad031cb6d687c9f121d895a8d49281c8..cdd79060ee290535dcab25b6925e9143ba6bb574 100644 (file)
@@ -21,6 +21,22 @@ along with GCC; see the file COPYING3.  If not see
 #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 = 2,
+  /* 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 = 1,
+  /* 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.  If not see
 
  */
 
-
 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;
     }