ipa-profile.c: Add toplevel comment.
authorJan Hubicka <jh@suse.cz>
Mon, 9 Sep 2013 07:37:53 +0000 (09:37 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 9 Sep 2013 07:37:53 +0000 (07:37 +0000)
* 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
gcc/ipa-profile.c
gcc/predict.c

index 38f1e95c330131c976aeb9ab19e4a34a75928975..9c0e334f689fa884bed93432d5b4b1601e84960a 100644 (file)
@@ -1,3 +1,13 @@
+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
index cb42c8f0f4593367427a03b3d73e96d9e08f1730..2b22333d1b910a8dcd85d7c1030a04bc0d8e141a 100644 (file)
@@ -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
 <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 "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)
index ddf72d2d14aea6c2b1cc6729dba366bda7efa329..affed79ae9d8f5da52ac83b339fdc482b15d101d 100644 (file)
@@ -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))