From daf5c7705fe749beef4971a4cbaff770f784d4d6 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 9 Sep 2013 09:37:53 +0200 Subject: [PATCH] ipa-profile.c: Add toplevel comment. * ipa-profile.c: Add toplevel comment. (ipa_propagate_frequency_1): Be more conservative when profile is read. (contains_hot_call_p): New function. (ipa_propagate_frequency): Set frequencies based on counts when profile is read. * predict.c (compute_function_frequency): Use PROFILE_READ gueard for profile; do not tamper with profile after inlining if it is read. From-SVN: r202382 --- gcc/ChangeLog | 10 ++++++ gcc/ipa-profile.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/predict.c | 11 ++++-- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 38f1e95c330..9c0e334f689 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2013-09-08 Jan Hubicka + + * ipa-profile.c: Add toplevel comment. + (ipa_propagate_frequency_1): Be more conservative when profile is read. + (contains_hot_call_p): New function. + (ipa_propagate_frequency): Set frequencies based on counts when + profile is read. + * predict.c (compute_function_frequency): Use PROFILE_READ gueard for + profile; do not tamper with profile after inlining if it is read. + 2013-09-08 Jan Hubicka * ipa-prop.c (try_make_edge_direct_simple_call): Do not special case diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c index cb42c8f0f45..2b22333d1b9 100644 --- a/gcc/ipa-profile.c +++ b/gcc/ipa-profile.c @@ -17,6 +17,33 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ +/* ipa-profile pass implements the following analysis propagating profille + inter-procedurally. + + - Count histogram construction. This is a histogram analyzing how much + time is spent executing statements with a given execution count read + from profile feedback. This histogram is complette only with LTO, + otherwise it contains information only about the current unit. + + Similar histogram is also estimated by coverage runtime. This histogram + is not dependent on LTO, but it suffers from various defects; first + gcov runtime is not weighting individual basic block by estimated execution + time and second the merging of multiple runs makes assumption that the + histogram distribution did not change. Consequentely histogram constructed + here may be more precise. + + The information is used to set hot/cold thresholds. + - Next speculative indirect call resolution is performed: the local + profile pass assigns profile-id to each function and provide us with a + histogram specifying the most common target. We look up the callgraph + node corresponding to the target and produce a speculative call. + + This call may or may not survive through IPA optimization based on decision + of inliner. + - Finally we propagate the following flags: unlikely executed, executed + once, executed at startup and executed at exit. These flags are used to + control code size/performance threshold and and code placement (by producing + .text.unlikely/.text.hot/.text.startup/.text.exit subsections). */ #include "config.h" #include "system.h" #include "coretypes.h" @@ -301,6 +328,18 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data) d->only_called_at_startup = 0; d->only_called_at_exit &= edge->caller->only_called_at_exit; } + + /* When profile feedback is available, do not try to propagate too hard; + counts are already good guide on function frequencies and roundoff + errors can make us to push function into unlikely section even when + it is executed by the train run. Transfer the function only if all + callers are unlikely executed. */ + if (profile_info && flag_branch_probabilities + && (edge->caller->frequency != NODE_FREQUENCY_UNLIKELY_EXECUTED + || (edge->caller->global.inlined_to + && edge->caller->global.inlined_to->frequency + != NODE_FREQUENCY_UNLIKELY_EXECUTED))) + d->maybe_unlikely_executed = false; if (!edge->frequency) continue; switch (edge->caller->frequency) @@ -332,6 +371,24 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data) return edge != NULL; } +/* Return ture if NODE contains hot calls. */ + +bool +contains_hot_call_p (struct cgraph_node *node) +{ + struct cgraph_edge *e; + for (e = node->callees; e; e = e->next_callee) + if (cgraph_maybe_hot_edge_p (e)) + return true; + else if (!e->inline_failed + && contains_hot_call_p (e->callee)) + return true; + for (e = node->indirect_calls; e; e = e->next_callee) + if (cgraph_maybe_hot_edge_p (e)) + return true; + return false; +} + /* See if the frequency of NODE can be updated based on frequencies of its callers. */ bool @@ -343,6 +400,7 @@ ipa_propagate_frequency (struct cgraph_node *node) /* We can not propagate anything useful about externally visible functions nor about virtuals. */ if (!node->local.local + || node->symbol.alias || (flag_devirtualize && DECL_VIRTUAL_P (node->symbol.decl))) return false; gcc_assert (node->symbol.analyzed); @@ -369,6 +427,36 @@ ipa_propagate_frequency (struct cgraph_node *node) cgraph_node_name (node)); changed = true; } + + /* With profile we can decide on hot/normal based on count. */ + if (node->count) + { + bool hot = false; + if (node->count >= get_hot_bb_threshold ()) + hot = true; + if (!hot) + hot |= contains_hot_call_p (node); + if (hot) + { + if (node->frequency != NODE_FREQUENCY_HOT) + { + if (dump_file) + fprintf (dump_file, "Node %s promoted to hot.\n", + cgraph_node_name (node)); + node->frequency = NODE_FREQUENCY_HOT; + return true; + } + return false; + } + else if (node->frequency == NODE_FREQUENCY_HOT) + { + if (dump_file) + fprintf (dump_file, "Node %s reduced to normal.\n", + cgraph_node_name (node)); + node->frequency = NODE_FREQUENCY_NORMAL; + changed = true; + } + } /* These come either from profile or user hints; never update them. */ if (node->frequency == NODE_FREQUENCY_HOT || node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) diff --git a/gcc/predict.c b/gcc/predict.c index ddf72d2d14a..affed79ae9d 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -2871,13 +2871,14 @@ compute_function_frequency (void) { basic_block bb; struct cgraph_node *node = cgraph_get_node (current_function_decl); + if (DECL_STATIC_CONSTRUCTOR (current_function_decl) || MAIN_NAME_P (DECL_NAME (current_function_decl))) node->only_called_at_startup = true; if (DECL_STATIC_DESTRUCTOR (current_function_decl)) node->only_called_at_exit = true; - if (!profile_info || !flag_branch_probabilities) + if (profile_status != PROFILE_READ) { int flags = flags_from_decl_or_type (current_function_decl); if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)) @@ -2895,7 +2896,13 @@ compute_function_frequency (void) node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; return; } - node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; + + /* Only first time try to drop function into unlikely executed. + After inlining the roundoff errors may confuse us. + Ipa-profile pass will drop functions only called from unlikely + functions to unlikely and that is most of what we care about. */ + if (!cfun->after_inlining) + node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; FOR_EACH_BB (bb) { if (maybe_hot_bb_p (cfun, bb))