This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: question about inlining


On 12/06/2017 11:45 PM, Richard Biener wrote:
On December 7, 2017 2:15:53 AM GMT+01:00, Martin Sebor <msebor@gmail.com> wrote:
On 12/06/2017 12:11 PM, Richard Biener wrote:
On December 6, 2017 6:38:11 PM GMT+01:00, Martin Sebor
<msebor@gmail.com> wrote:
While testing a libstdc++ patch that relies on inlining to
expose a GCC limitation I noticed that the same member function
of a class template is inlined into one function in the test but
not into the other, even though it is inlined into each if each
is compiled separately (i.e., in a file on its own).

I wasn't aware that inlining decisions made in one function could
affect those in another, or in the whole file.  Is that expected?
And if yes, what's the rationale?

Here's a simplified test case.  When compiled with -O2 or -O3
and either just -DFOO or just -DBAR, the call to vector::resize()
and all the functions called from it, including (crucially)
vector::_M_default_append, are inlined.  But when compiled with
-DFOO -DBAR _M_default_append is not inlined.  With a somewhat
more involved test case I've also seen the first call inlined
but not the second, which was also surprising to me.

There are unit and function growth limits that can be hit.

I see, thank you for reminding me.

Nothing brings the implications into sharp focus like two virtually
identical functions optimized differently as a result of exceeding
some size limit.  It would make perfect sense to me if I were using
-Os but I can't help but wonder how useful this heuristic is at -O3.

Well. The inlining process is basically inlining functions sorted by priority until the limits are hit (or nothing is profitable anymore). Without such limit we'd blow size through the roof.

I understand why it's done.  What I'm wondering is if the logic
that controls it or the selected per-translation unit limits do,
in fact, yield optimal results at all optimization levels, and
if they do, what it means for users and how they structure their
source code.

It obviously surprised me to have the compiler optimize a simple,
trivial function on its own one way only to then disable the same
optimization when another equivalent function was added to the
file.  It rendered my test ineffective and I only found out by
accident.  I suspect others would find this effect surprising as
well, and not in a good way.  If the inlining algorithm is tuned
to deliver optimal results at all optimization levels (but even
if it isn't) then its effects seem worth pointing out in the
manual.  What advice should we give to users when it comes to
inlining?  I'm thinking of something that might go in section
An Inline Function is As Fast As a Macro:
https://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Inline.html
(unless there's a better place for it).

Martin


It also makes me wonder if users are aware of how this impacts
their decisions to structure code.  If adding a new function to
a file containing carefully optimized code can result in outlining
what was previously inlined, it's probably best to define one
function per file.  I've seen C libraries laid out like that but
never a C++ program.

Martin

  #include <vector>

  void sink (std::vector<int>&);

  #if FOO
  void foo (unsigned n)
  {
    std::vector<int> a;
    a.resize (n);
    sink (a);
  }
  #endif

  #if BAR
  void bar (unsigned long n)
  {
    std::vector<int> a;
    a.resize (n);
    sink (a);
  }
  #endif

Thanks
Martin




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]