Patchwork [google] dump inline decisions to stderr under -fopt-info

login
register
mail settings
Submitter Dehao Chen
Date Dec. 1, 2011, 1:59 a.m.
Message ID <CAO2gOZUmffJhhxX7oWiwWy_ssNOLsN35J605sR++yw4Sf6Mw6g@mail.gmail.com>
Download mbox | patch
Permalink /patch/128626/
State New
Headers show

Comments

Dehao Chen - Dec. 1, 2011, 1:59 a.m.
This patch is for google-{main|gcc_4.6} only.

Tested with bootstrap and regression tests.

Dump inline decisions, also output the inline chain.

Dehao

2011-12-01  Dehao Chen  <dehao@google.com>

	* ipa-inline.c (dump_inline_decision): New function.
	(inline_small_functions): Use it to dump the inline decisions to stderr.
Dehao Chen - Dec. 14, 2011, 1:13 a.m.
I've updated the patch to fix a bug in dump_inline_decision.

Thanks,
Dehao

On Thu, Dec 1, 2011 at 9:59 AM, Dehao Chen <dehao@google.com> wrote:
>
> This patch is for google-{main|gcc_4.6} only.
>
> Tested with bootstrap and regression tests.
>
> Dump inline decisions, also output the inline chain.
>
> Dehao
>
> 2011-12-01  Dehao Chen  <dehao@google.com>
>
>        * ipa-inline.c (dump_inline_decision): New function.
>        (inline_small_functions): Use it to dump the inline decisions to stderr.
>
> Index: gcc/ipa-inline.c
> ===================================================================
> --- gcc/ipa-inline.c    (revision 181835)
> +++ gcc/ipa-inline.c    (working copy)
> @@ -1377,6 +1377,45 @@
>  }
>
>
> +/* Dump the inline decision of EDGE to stderr.  */
> +
> +static void
> +dump_inline_decision (struct cgraph_edge *edge)
> +{
> +  location_t locus;
> +  size_t buf_size = 4096;
> +  size_t current_string_len = 0;
> +  char *buf = (char *) xmalloc (buf_size);
> +  struct cgraph_node *inlined_to;
> +  gcov_type callee_count = edge->callee->count;
> +  buf[0] = 0;
> +  if (edge->inline_failed == CIF_OK && edge->callee->clone_of)
> +    callee_count += edge->callee->clone_of->count;
> +  for (inlined_to = edge->caller->global.inlined_to;
> +       inlined_to; inlined_to = inlined_to->global.inlined_to)
> +    {
> +      const char *name = cgraph_node_name (inlined_to);
> +      if (!name)
> +       name = "unknown";
> +      current_string_len += (strlen (name) + 4);
> +      while (current_string_len >= buf_size)
> +       {
> +         buf_size *= 2;
> +         buf = (char *) xrealloc (buf, buf_size);
> +       }
> +      strcat (buf, "-->");
> +      strcat (buf, name);
> +    }
> +  locus = gimple_location (edge->call_stmt);
> +  inform (locus, "%s ("HOST_WIDEST_INT_PRINT_DEC") --"
> +         HOST_WIDEST_INT_PRINT_DEC"--> %s ("
> +         HOST_WIDEST_INT_PRINT_DEC") %s : %s",
> +         cgraph_node_name (edge->callee), callee_count, edge->count,
> +         cgraph_node_name (edge->caller), edge->caller->count, buf,
> +         edge->inline_failed == CIF_OK ? "INLINED": "IGNORED");
> +}
> +
> +
>  /* We use greedy algorithm for inlining of small functions:
>    All inline candidates are put into prioritized heap ordered in
>    increasing badness.
> @@ -1428,6 +1467,7 @@
>   overall_size = initial_size;
>   max_size = compute_max_insns (overall_size);
>   min_size = overall_size;
> +  edge = NULL;
>
>   /* Populate the heeap with all edges we might inline.  */
>
> @@ -1462,6 +1502,9 @@
>       int current_badness;
>       int growth;
>
> +      if (edge && flag_opt_info >= OPT_INFO_MIN)
> +       dump_inline_decision (edge);
> +
>       edge = (struct cgraph_edge *) fibheap_extract_min (heap);
>       gcc_assert (edge->aux);
>       edge->aux = NULL;
> @@ -1482,6 +1525,7 @@
>       if (current_badness != badness)
>        {
>          edge->aux = fibheap_insert (heap, current_badness, edge);
> +         edge = NULL;
>          continue;
>        }
>
> @@ -1636,6 +1680,8 @@
>            fprintf (dump_file, "New minimal size reached: %i\n", min_size);
>        }
>     }
> +  if (edge && flag_opt_info >= OPT_INFO_MIN)
> +    dump_inline_decision (edge);
>
>   free_growth_caches ();
>   if (new_indirect_edges)
Xinliang David Li - Dec. 14, 2011, 7:18 a.m.
There are a couple of problems with the patch (the patch is only
compatible with 4_6 branch)

1) the dump_inline_decision should be called inside
cgraph_mark_inline_edge when the edge is finally picked (and when the
callee node is cloned)
2) The source location is not printed which makes the dumping less useful
3) the information line should clearly print out the final caller
where the inlining happens, and the intermediate inline instance
information should be clearly printed as additional information
showing the inline context. For instance,

  foo1->foo2->foo3->foo4

If all callsites are inlined in top down order, the messages I expect
to see are:

a.c:5: note: 'foo2' is inlined into 'foo1' with call count xxxx
a.c:10: note: 'foo3' is inlined into 'foo1' with call count yyyy (via
inline instance 'foo2')
a.c:20: note: 'foo4' is inlined into foo1' with call count zzzz (via
inline instances 'foo3', 'foo2')


If the decision is bottom up, the messages should look like:

a.c:20: note: 'foo4' is inlined into 'foo3' with call count zzzz
a.c:10: note: 'foo3' is inlined into 'foo2' with call count yyyy
a.c:5: note: 'foo2' is inlined into 'foo1' with call count xxxx

Ideally, the caller and callee should also be marked with 'entry count
and max bb count' information -- but that probably should be
controlled by opt-info level.

4) Also notice that for inline node clones, the right way to walk up
the call context chain is via 'edge->caller->callers'.
5) there should be a test case.

Thanks,

David

On Tue, Dec 13, 2011 at 5:13 PM, Dehao Chen <dehao@google.com> wrote:
> I've updated the patch to fix a bug in dump_inline_decision.
>
> Thanks,
> Dehao
>
> On Thu, Dec 1, 2011 at 9:59 AM, Dehao Chen <dehao@google.com> wrote:
>>
>> This patch is for google-{main|gcc_4.6} only.
>>
>> Tested with bootstrap and regression tests.
>>
>> Dump inline decisions, also output the inline chain.
>>
>> Dehao
>>
>> 2011-12-01  Dehao Chen  <dehao@google.com>
>>
>>        * ipa-inline.c (dump_inline_decision): New function.
>>        (inline_small_functions): Use it to dump the inline decisions to stderr.
>>
>> Index: gcc/ipa-inline.c
>> ===================================================================
>> --- gcc/ipa-inline.c    (revision 181835)
>> +++ gcc/ipa-inline.c    (working copy)
>> @@ -1377,6 +1377,45 @@
>>  }
>>
>>
>> +/* Dump the inline decision of EDGE to stderr.  */
>> +
>> +static void
>> +dump_inline_decision (struct cgraph_edge *edge)
>> +{
>> +  location_t locus;
>> +  size_t buf_size = 4096;
>> +  size_t current_string_len = 0;
>> +  char *buf = (char *) xmalloc (buf_size);
>> +  struct cgraph_node *inlined_to;
>> +  gcov_type callee_count = edge->callee->count;
>> +  buf[0] = 0;
>> +  if (edge->inline_failed == CIF_OK && edge->callee->clone_of)
>> +    callee_count += edge->callee->clone_of->count;
>> +  for (inlined_to = edge->caller->global.inlined_to;
>> +       inlined_to; inlined_to = inlined_to->global.inlined_to)
>> +    {
>> +      const char *name = cgraph_node_name (inlined_to);
>> +      if (!name)
>> +       name = "unknown";
>> +      current_string_len += (strlen (name) + 4);
>> +      while (current_string_len >= buf_size)
>> +       {
>> +         buf_size *= 2;
>> +         buf = (char *) xrealloc (buf, buf_size);
>> +       }
>> +      strcat (buf, "-->");
>> +      strcat (buf, name);
>> +    }
>> +  locus = gimple_location (edge->call_stmt);
>> +  inform (locus, "%s ("HOST_WIDEST_INT_PRINT_DEC") --"
>> +         HOST_WIDEST_INT_PRINT_DEC"--> %s ("
>> +         HOST_WIDEST_INT_PRINT_DEC") %s : %s",
>> +         cgraph_node_name (edge->callee), callee_count, edge->count,
>> +         cgraph_node_name (edge->caller), edge->caller->count, buf,
>> +         edge->inline_failed == CIF_OK ? "INLINED": "IGNORED");
>> +}
>> +
>> +
>>  /* We use greedy algorithm for inlining of small functions:
>>    All inline candidates are put into prioritized heap ordered in
>>    increasing badness.
>> @@ -1428,6 +1467,7 @@
>>   overall_size = initial_size;
>>   max_size = compute_max_insns (overall_size);
>>   min_size = overall_size;
>> +  edge = NULL;
>>
>>   /* Populate the heeap with all edges we might inline.  */
>>
>> @@ -1462,6 +1502,9 @@
>>       int current_badness;
>>       int growth;
>>
>> +      if (edge && flag_opt_info >= OPT_INFO_MIN)
>> +       dump_inline_decision (edge);
>> +
>>       edge = (struct cgraph_edge *) fibheap_extract_min (heap);
>>       gcc_assert (edge->aux);
>>       edge->aux = NULL;
>> @@ -1482,6 +1525,7 @@
>>       if (current_badness != badness)
>>        {
>>          edge->aux = fibheap_insert (heap, current_badness, edge);
>> +         edge = NULL;
>>          continue;
>>        }
>>
>> @@ -1636,6 +1680,8 @@
>>            fprintf (dump_file, "New minimal size reached: %i\n", min_size);
>>        }
>>     }
>> +  if (edge && flag_opt_info >= OPT_INFO_MIN)
>> +    dump_inline_decision (edge);
>>
>>   free_growth_caches ();
>>   if (new_indirect_edges)
Xinliang David Li - Dec. 14, 2011, 6:07 p.m.
Another usability related issue for C++. The long demangled function
names will make the info messages very hard to swallow. Since there
will be source lines to show the source context, it might be better to
just use the short decl names. The downside is it can be ambiguous for
template functions.

David

On Tue, Dec 13, 2011 at 11:18 PM, Xinliang David Li <davidxl@google.com> wrote:
> There are a couple of problems with the patch (the patch is only
> compatible with 4_6 branch)
>
> 1) the dump_inline_decision should be called inside
> cgraph_mark_inline_edge when the edge is finally picked (and when the
> callee node is cloned)
> 2) The source location is not printed which makes the dumping less useful
> 3) the information line should clearly print out the final caller
> where the inlining happens, and the intermediate inline instance
> information should be clearly printed as additional information
> showing the inline context. For instance,
>
>  foo1->foo2->foo3->foo4
>
> If all callsites are inlined in top down order, the messages I expect
> to see are:
>
> a.c:5: note: 'foo2' is inlined into 'foo1' with call count xxxx
> a.c:10: note: 'foo3' is inlined into 'foo1' with call count yyyy (via
> inline instance 'foo2')
> a.c:20: note: 'foo4' is inlined into foo1' with call count zzzz (via
> inline instances 'foo3', 'foo2')
>
>
> If the decision is bottom up, the messages should look like:
>
> a.c:20: note: 'foo4' is inlined into 'foo3' with call count zzzz
> a.c:10: note: 'foo3' is inlined into 'foo2' with call count yyyy
> a.c:5: note: 'foo2' is inlined into 'foo1' with call count xxxx
>
> Ideally, the caller and callee should also be marked with 'entry count
> and max bb count' information -- but that probably should be
> controlled by opt-info level.
>
> 4) Also notice that for inline node clones, the right way to walk up
> the call context chain is via 'edge->caller->callers'.
> 5) there should be a test case.
>
> Thanks,
>
> David
>
> On Tue, Dec 13, 2011 at 5:13 PM, Dehao Chen <dehao@google.com> wrote:
>> I've updated the patch to fix a bug in dump_inline_decision.
>>
>> Thanks,
>> Dehao
>>
>> On Thu, Dec 1, 2011 at 9:59 AM, Dehao Chen <dehao@google.com> wrote:
>>>
>>> This patch is for google-{main|gcc_4.6} only.
>>>
>>> Tested with bootstrap and regression tests.
>>>
>>> Dump inline decisions, also output the inline chain.
>>>
>>> Dehao
>>>
>>> 2011-12-01  Dehao Chen  <dehao@google.com>
>>>
>>>        * ipa-inline.c (dump_inline_decision): New function.
>>>        (inline_small_functions): Use it to dump the inline decisions to stderr.
>>>
>>> Index: gcc/ipa-inline.c
>>> ===================================================================
>>> --- gcc/ipa-inline.c    (revision 181835)
>>> +++ gcc/ipa-inline.c    (working copy)
>>> @@ -1377,6 +1377,45 @@
>>>  }
>>>
>>>
>>> +/* Dump the inline decision of EDGE to stderr.  */
>>> +
>>> +static void
>>> +dump_inline_decision (struct cgraph_edge *edge)
>>> +{
>>> +  location_t locus;
>>> +  size_t buf_size = 4096;
>>> +  size_t current_string_len = 0;
>>> +  char *buf = (char *) xmalloc (buf_size);
>>> +  struct cgraph_node *inlined_to;
>>> +  gcov_type callee_count = edge->callee->count;
>>> +  buf[0] = 0;
>>> +  if (edge->inline_failed == CIF_OK && edge->callee->clone_of)
>>> +    callee_count += edge->callee->clone_of->count;
>>> +  for (inlined_to = edge->caller->global.inlined_to;
>>> +       inlined_to; inlined_to = inlined_to->global.inlined_to)
>>> +    {
>>> +      const char *name = cgraph_node_name (inlined_to);
>>> +      if (!name)
>>> +       name = "unknown";
>>> +      current_string_len += (strlen (name) + 4);
>>> +      while (current_string_len >= buf_size)
>>> +       {
>>> +         buf_size *= 2;
>>> +         buf = (char *) xrealloc (buf, buf_size);
>>> +       }
>>> +      strcat (buf, "-->");
>>> +      strcat (buf, name);
>>> +    }
>>> +  locus = gimple_location (edge->call_stmt);
>>> +  inform (locus, "%s ("HOST_WIDEST_INT_PRINT_DEC") --"
>>> +         HOST_WIDEST_INT_PRINT_DEC"--> %s ("
>>> +         HOST_WIDEST_INT_PRINT_DEC") %s : %s",
>>> +         cgraph_node_name (edge->callee), callee_count, edge->count,
>>> +         cgraph_node_name (edge->caller), edge->caller->count, buf,
>>> +         edge->inline_failed == CIF_OK ? "INLINED": "IGNORED");
>>> +}
>>> +
>>> +
>>>  /* We use greedy algorithm for inlining of small functions:
>>>    All inline candidates are put into prioritized heap ordered in
>>>    increasing badness.
>>> @@ -1428,6 +1467,7 @@
>>>   overall_size = initial_size;
>>>   max_size = compute_max_insns (overall_size);
>>>   min_size = overall_size;
>>> +  edge = NULL;
>>>
>>>   /* Populate the heeap with all edges we might inline.  */
>>>
>>> @@ -1462,6 +1502,9 @@
>>>       int current_badness;
>>>       int growth;
>>>
>>> +      if (edge && flag_opt_info >= OPT_INFO_MIN)
>>> +       dump_inline_decision (edge);
>>> +
>>>       edge = (struct cgraph_edge *) fibheap_extract_min (heap);
>>>       gcc_assert (edge->aux);
>>>       edge->aux = NULL;
>>> @@ -1482,6 +1525,7 @@
>>>       if (current_badness != badness)
>>>        {
>>>          edge->aux = fibheap_insert (heap, current_badness, edge);
>>> +         edge = NULL;
>>>          continue;
>>>        }
>>>
>>> @@ -1636,6 +1680,8 @@
>>>            fprintf (dump_file, "New minimal size reached: %i\n", min_size);
>>>        }
>>>     }
>>> +  if (edge && flag_opt_info >= OPT_INFO_MIN)
>>> +    dump_inline_decision (edge);
>>>
>>>   free_growth_caches ();
>>>   if (new_indirect_edges)

Patch

Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c	(revision 181835)
+++ gcc/ipa-inline.c	(working copy)
@@ -1377,6 +1377,45 @@ 
 }


+/* Dump the inline decision of EDGE to stderr.  */
+
+static void
+dump_inline_decision (struct cgraph_edge *edge)
+{
+  location_t locus;
+  size_t buf_size = 4096;
+  size_t current_string_len = 0;
+  char *buf = (char *) xmalloc (buf_size);
+  struct cgraph_node *inlined_to;
+  gcov_type callee_count = edge->callee->count;
+  buf[0] = 0;
+  if (edge->inline_failed == CIF_OK && edge->callee->clone_of)
+    callee_count += edge->callee->clone_of->count;
+  for (inlined_to = edge->caller->global.inlined_to;
+       inlined_to; inlined_to = inlined_to->global.inlined_to)
+    {
+      const char *name = cgraph_node_name (inlined_to);
+      if (!name)
+	name = "unknown";
+      current_string_len += (strlen (name) + 4);
+      while (current_string_len >= buf_size)
+	{
+	  buf_size *= 2;
+	  buf = (char *) xrealloc (buf, buf_size);
+	}
+      strcat (buf, "-->");
+      strcat (buf, name);
+    }
+  locus = gimple_location (edge->call_stmt);
+  inform (locus, "%s ("HOST_WIDEST_INT_PRINT_DEC") --"
+	  HOST_WIDEST_INT_PRINT_DEC"--> %s ("
+	  HOST_WIDEST_INT_PRINT_DEC") %s : %s",
+	  cgraph_node_name (edge->callee), callee_count, edge->count,
+	  cgraph_node_name (edge->caller), edge->caller->count, buf,
+	  edge->inline_failed == CIF_OK ? "INLINED": "IGNORED");
+}
+
+
 /* We use greedy algorithm for inlining of small functions:
    All inline candidates are put into prioritized heap ordered in
    increasing badness.
@@ -1428,6 +1467,7 @@ 
   overall_size = initial_size;
   max_size = compute_max_insns (overall_size);
   min_size = overall_size;
+  edge = NULL;

   /* Populate the heeap with all edges we might inline.  */

@@ -1462,6 +1502,9 @@ 
       int current_badness;
       int growth;

+      if (edge && flag_opt_info >= OPT_INFO_MIN)
+	dump_inline_decision (edge);
+
       edge = (struct cgraph_edge *) fibheap_extract_min (heap);
       gcc_assert (edge->aux);
       edge->aux = NULL;
@@ -1482,6 +1525,7 @@ 
       if (current_badness != badness)
 	{
 	  edge->aux = fibheap_insert (heap, current_badness, edge);
+	  edge = NULL;
 	  continue;
 	}

@@ -1636,6 +1680,8 @@ 
 	    fprintf (dump_file, "New minimal size reached: %i\n", min_size);
 	}
     }
+  if (edge && flag_opt_info >= OPT_INFO_MIN)
+    dump_inline_decision (edge);

   free_growth_caches ();
   if (new_indirect_edges)