Commit daf5c770 by Jan Hubicka Committed by Jan Hubicka

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
parent a12cd2db
2013-09-08 Jan Hubicka <jh@suse.cz> 2013-09-08 Jan Hubicka <jh@suse.cz>
* 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 <jh@suse.cz>
* ipa-prop.c (try_make_edge_direct_simple_call): Do not special case * ipa-prop.c (try_make_edge_direct_simple_call): Do not special case
speculative edges. speculative edges.
......
...@@ -17,6 +17,33 @@ You should have received a copy of the GNU General Public License ...@@ -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 along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* 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 "config.h"
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
...@@ -301,6 +328,18 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data) ...@@ -301,6 +328,18 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data)
d->only_called_at_startup = 0; d->only_called_at_startup = 0;
d->only_called_at_exit &= edge->caller->only_called_at_exit; 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) if (!edge->frequency)
continue; continue;
switch (edge->caller->frequency) switch (edge->caller->frequency)
...@@ -332,6 +371,24 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data) ...@@ -332,6 +371,24 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data)
return edge != NULL; 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 /* See if the frequency of NODE can be updated based on frequencies of its
callers. */ callers. */
bool bool
...@@ -343,6 +400,7 @@ ipa_propagate_frequency (struct cgraph_node *node) ...@@ -343,6 +400,7 @@ ipa_propagate_frequency (struct cgraph_node *node)
/* We can not propagate anything useful about externally visible functions /* We can not propagate anything useful about externally visible functions
nor about virtuals. */ nor about virtuals. */
if (!node->local.local if (!node->local.local
|| node->symbol.alias
|| (flag_devirtualize && DECL_VIRTUAL_P (node->symbol.decl))) || (flag_devirtualize && DECL_VIRTUAL_P (node->symbol.decl)))
return false; return false;
gcc_assert (node->symbol.analyzed); gcc_assert (node->symbol.analyzed);
...@@ -369,6 +427,36 @@ ipa_propagate_frequency (struct cgraph_node *node) ...@@ -369,6 +427,36 @@ ipa_propagate_frequency (struct cgraph_node *node)
cgraph_node_name (node)); cgraph_node_name (node));
changed = true; 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. */ /* These come either from profile or user hints; never update them. */
if (node->frequency == NODE_FREQUENCY_HOT if (node->frequency == NODE_FREQUENCY_HOT
|| node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) || node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
......
...@@ -2871,13 +2871,14 @@ compute_function_frequency (void) ...@@ -2871,13 +2871,14 @@ compute_function_frequency (void)
{ {
basic_block bb; basic_block bb;
struct cgraph_node *node = cgraph_get_node (current_function_decl); struct cgraph_node *node = cgraph_get_node (current_function_decl);
if (DECL_STATIC_CONSTRUCTOR (current_function_decl) if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
|| MAIN_NAME_P (DECL_NAME (current_function_decl))) || MAIN_NAME_P (DECL_NAME (current_function_decl)))
node->only_called_at_startup = true; node->only_called_at_startup = true;
if (DECL_STATIC_DESTRUCTOR (current_function_decl)) if (DECL_STATIC_DESTRUCTOR (current_function_decl))
node->only_called_at_exit = true; 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); int flags = flags_from_decl_or_type (current_function_decl);
if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)) if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl))
...@@ -2895,7 +2896,13 @@ compute_function_frequency (void) ...@@ -2895,7 +2896,13 @@ compute_function_frequency (void)
node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
return; 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) FOR_EACH_BB (bb)
{ {
if (maybe_hot_bb_p (cfun, bb)) if (maybe_hot_bb_p (cfun, bb))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment