From: Jan Hubicka Date: Mon, 19 Jun 2017 09:47:31 +0000 (+0200) Subject: profile-count.c (profile_count::dump): Dump quality. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4e9a497f07457d63c74962ee0d90c96bdd98f918;p=gcc.git profile-count.c (profile_count::dump): Dump quality. * 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 49a8109df1d..78ded852f32 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2017-06-19 Jan Hubicka + + * 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 * tree-ssa-loop-niter.h (estimate_numbers_of_iterations): Take diff --git a/gcc/profile-count.c b/gcc/profile-count.c index 5ad7178c159..e64d1b56421 100644 --- a/gcc/profile-count.c +++ b/gcc/profile-count.c @@ -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); } diff --git a/gcc/profile-count.h b/gcc/profile-count.h index 78ffee99ad0..cdd79060ee2 100644 --- a/gcc/profile-count.h +++ b/gcc/profile-count.h @@ -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; }