[HN Gopher] For software performance, can you always trust inlin...
___________________________________________________________________
For software performance, can you always trust inlining?
Author : chmaynard
Score : 30 points
Date : 2021-10-10 11:21 UTC (11 hours ago)
(HTM) web link (lemire.me)
(TXT) w3m dump (lemire.me)
| asdfasgasdgasdg wrote:
| Article doesn't really address the question of whether you can
| ALWAYS trust inlining. I can tell you from experience the answer
| is no. We have some libraries at work that implement generic
| evaluation of functions over pages of objects, as in the context
| of a database. The authors did this in the "proper" C++ way,
| which involved a lot of generics and templates. They also
| sprinkled inline directives all over the place, apparently
| without ever actually benchmarking each individual case.
|
| What it ended up with is a bunch of absolutely enormous modules,
| each generating tens of megabytes of mostly identical code, but
| with the leaf functions in each case handling floats, ints,
| strings, etc.
|
| Removing some of these inline directives probably would not
| impact the code at all, since most of the inlined code was cold.
| But it would likely benefit build performance quite a bit. It
| might even improve runtime performance by putting less pressure
| on the cache.
|
| This is probably not a surprise, but inlining is best for hot
| leaf code. Cold code should probably not be inlined unless it is
| used exactly once.
| detaro wrote:
| And of course there is still the difference between "has an
| inline directive" and "gets inlined" - it's merely a strong
| suggestion in most compilers.
| asdfasgasdgasdg wrote:
| Sure. In this case I was reading the disassembled code, so I
| could verify that large swathes of code were in fact getting
| inlined. I believe the code in question was using the clang-
| specific always_inline attribute.
|
| https://clang.llvm.org/docs/AttributeReference.html#always-i.
| ..
| stkdump wrote:
| I'm not so sure it is even a strong suggestion. Actually
| inline nowadays mostly has a semantic meaning - the symbol
| can be defined in multiple compilation units without causing
| multiple definition errors from the linker. Usually you can't
| remove it without moving the definition from a header file to
| an implementation file.
|
| Edit: it is correct though, that the inline keyword often is
| a neccessity to allow the compiler to inline in the first
| place. After all, the compiler can only inline a function at
| the callsite, when both are in the same translation unit.
| Either the function is only used in one translation unit, or
| it has to be defined as inline (or worse as hidden to the
| linker by static or anonymous namespace). Disregarding LTO,
| of course.
| [deleted]
| nickysielicki wrote:
| > It might even improve runtime performance by putting less
| pressure on the cache.
|
| Not so much a possibility as a certainty on modern processors.
| Easiest way to tell: run it through perf stat and read the
| output.
| marton78 wrote:
| I doubt that would help, since generic code is implicitly
| inline.
| asdfasgasdgasdg wrote:
| Generic code has to be declared before use, in C++, if you're
| not predeclaring the types the template supports. But that is
| orthogonal to whether it is actually inlined in the generated
| code.
| missblit wrote:
| AFAIK nothing requires generic code to be compiled inline in
| C++.
|
| Heck with explicit template instantiation the generic code
| may not even be in the same translation unit as the calling
| code. At that point it'd require link time optimization to
| inline it.
| nickysielicki wrote:
| Not true! This is true in monomorphized languages like Rust,
| but C++ has vtables which allows for generic code at an
| assembly level.
|
| Maybe I'm misunderstanding you.
| yakubin wrote:
| What _jcelerier_ said, but also as for:
|
| _> This is true in monomorphized languages like Rust_
|
| It's not necessarily true for monomorphized code. Inlining
| is enabled by monomorphization, but is not required.
|
| You can see it with templates in C++: function template
| instantiations aren't always inlined. They are instantiated
| in every TU separately, if they are defined in headers, but
| then they may be called in this TU just like any other
| function without inlining. This requires the linker to
| deduplicate the instantiations later. In another scenario
| you may declare a function template in a header without the
| implementation, putting the implementation in a CPP file
| along with explicit instantiation. In that case the
| compiler is not able to inline this function in another TU
| (without LTO).
|
| As for Rust, Rust is not universally monomorphized. The
| user of generic code in Rust gets to decide whether they
| want to use monomorphization or vtables, regardless of the
| ideas of the author of said generic code.
| nickysielicki wrote:
| Thanks for this comment, I have a lot to learn.
| jcelerier wrote:
| run-time polymorphism is generally not called "generics"
| Zababa wrote:
| I've heard a lot that when you want to focus on performance,
| you should benchmark instead of relying on intuition, and I
| think this is another example of that.
| jl6 wrote:
| i.e. "Stop thinking and start looking"
___________________________________________________________________
(page generated 2021-10-10 23:02 UTC)