From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 106636 invoked by alias); 19 Jun 2017 09:49:52 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 104996 invoked by uid 89); 19 Jun 2017 09:49:50 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-9.4 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,KAM_LAZY_DOMAIN_SECURITY,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=reality, Quality, counters, guessed X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 19 Jun 2017 09:49:48 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id EF81454810E; Mon, 19 Jun 2017 11:49:49 +0200 (CEST) Date: Mon, 19 Jun 2017 09:49:00 -0000 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Add quality tracking for profile counter Message-ID: <20170619094949.GA49407@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-SW-Source: 2017-06/txt/msg01281.txt.bz2 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; }