Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix various uses of inline #14158

Closed
wants to merge 2 commits into from
Closed

Conversation

arvidn
Copy link

@arvidn arvidn commented Sep 6, 2018

This is C++, inline functions in a headers do not need to be static. Making it so is a pessimization as it will generate functions with internal linkage in every translation unit including the header. (Note that inline in C is different from inline in C++).

Furthermore, a static function in a cpp file already has internal linkage, making it inline has no effect.

Templates already have an inline-like property of being allowed to be defined multiple times, and having the linker deal with it. Making them inline is also redundant.

This change does 3 things:

  1. removes static from all inlined functions in header files
  2. removes inline from all static inline functions in .cpp files
  3. removes inline from templates

Arvid Norberg added 2 commits September 5, 2018 18:33
…licate definitions. In cpp files, don't make functions with internal linkage inline, since it's unnecessary in that case
@ken2812221
Copy link
Contributor

Furthermore, a static function in a cpp file already has internal linkage, making it inline has no effect.

Is there any document that can prove this? I don't think they act different when they are in .cpp and .h files

@DrahtBot
Copy link
Contributor

DrahtBot commented Sep 6, 2018

Note to reviewers: This pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@arvidn
Copy link
Author

arvidn commented Sep 6, 2018

Is there any document that can prove this? I don't think they act different when they are in .cpp and .h files

[decl.inline] say:

An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case ([basic.def.odr]).

which is really the main definition of inline in C++. Since a static function has internal linkage, it will already be defined in every translation unit it appears in.

regarding the distinction of .h vs. .cpp, they do behave the same, however, when a static function appear in a cpp file, there will only ever be one version of it. if a static function appear in a header, it's likely there will be multiple copies. It's potentially more space efficient to just have a single copy, that's why I removed static from headers but not from .cpp files.

@practicalswift
Copy link
Contributor

practicalswift commented Sep 6, 2018

utACK ee258a0

Excellent first-time contribution! I'm so glad to see you as a Bitcoin Core contributor @arvidn. I love your work on libtorrent and I'm also a fan of your C++ talks.

The high quality standards you strive for in the libtorrent project and enforce by use of automated testing/linting is really impressive. Thanks for some really inspiring work and hope you'll bring some of that drive for high quality and correctness over here in the form of future contributions!

Welcome to Bitcoin Core! :-)

@promag
Copy link
Member

promag commented Sep 6, 2018

@arvidn I'm curious if you found these with grep or other tool? I mean, is this complete? And can we add check to prevent more "wrong" code?

@arvidn
Copy link
Author

arvidn commented Sep 6, 2018

@promag good question. I used vim for the bulk of the change, specifically:

:argadd src/*.cpp src/*/*.cpp
:argdo %s/static inline /static /ge

and

:argadd src/*.h src/*/*.h
:argdo %s/static inline /inline /ge

Then I grepped out the templates from the diff that created.

So, any code outside of those globs was not included.

@sipa
Copy link
Member

sipa commented Sep 6, 2018

Furthermore, a static function in a cpp file already has internal linkage, making it inline has no effect.

Templates already have an inline-like property of being allowed to be defined multiple times, and having the linker deal with it. Making them inline is also redundant.

As far as I know, inline has two effects. One is allowing the function to be defined in multiple translation units (as long as they're all identical). The second is a hint to the compiler (but just a hint) that it may be worthwhile to inline the function at call sites. I'd like to be sure that removing inline does not hurt performance through that second effect.

@arvidn
Copy link
Author

arvidn commented Sep 6, 2018

@sipa that's exactly right, those are the two effects. I believe it's widely understood that all major compilers these days ignore the hint and base inlining entirely on their own heuristics. It's a fair concern though. I'll see what I can come up with. Are there any performance regression tests by any chance?

@maflcko
Copy link
Member

maflcko commented Sep 6, 2018

There is ./src/bench/bench_bitcoin, but it has not full coverage.

@arvidn
Copy link
Author

arvidn commented Sep 6, 2018

it appears at least clang does take the inline keyword into account in its heuristic [ref]. I wouldn't expect it to really make a significant difference in this case (either direction).

Perhaps a better approach would be to split this PR into two. I could revert the removal of inline and submit that as a separate PR where I can put some more work into investigating potential performance impact

@arvidn
Copy link
Author

arvidn commented Sep 7, 2018

I put some work into investigating whether any of the inline decisions changed by this patch. Given that it's primarily decided by heuristics, this may differ on GCC. I tested this with clang using the -Rpass=inline command line switch. This logs every time the inliner fires.

Specifically I ran:

CFLAGS=-Rpass=inline ./configure
make V=1 -j1 2> master-inlining.log
grep "remark:" -A 3 master-inlining.log >master.log

and then the same thing in this branch (after cleaning obviously):

make V=1 -j1 2> branch-inlining.log
grep "remark:" -A 3 branch-inlining.log >branch.log

My hope was that the output would be identical, but it wasn't for various reasons. However, all the actual inline decisions were the same. The difference was that some names were mangled differently (presumably because of the linkage change) and some logs quoting lines in the source changed, because the source changed.

for example:

-./primitives/transaction.h:404:116: remark: _ZNSt3__17forwardI19CMutableTransactionEEOT_RNS_16remove_referenceIS2_E4typeE inlined into _Z18MakeTransactionRefI19CMutableTransactionENSt3__110shared_ptrIK12CTransactionEEOT_ [-Rpass=inline]
+./primitives/transaction.h:404:130: remark: _ZNSt3__17forwardI19CMutableTransactionEEOT_RNS_16remove_referenceIS2_E4typeE inlined into _ZL18MakeTransactionRefI19CMutableTransactionENSt3__110shared_ptrIK12CTransactionEEOT_ [-Rpass=inline]

(note the additional "L" in the mangled name)

-template <typename Tx> CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
-                                                                                                                   ^
+template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
+                                                                                                                                 ^

So, at least for for clang, this patch does not change any inlining decisions.

@sipa
Copy link
Member

sipa commented Sep 8, 2018

@arvidn I just observed inline on a member function inside an anonymous namespace having an effect with GCC (version 7.3.0, -O2), in a different project with pretty complicated templated code.

I very much doubt the same effect would be observed in Bitcoin Core (nothing similarly complex happens here), but I thought I'd point it out as it may mean we need to consider GCC as well.

@DrahtBot
Copy link
Contributor

Needs rebase

@maflcko
Copy link
Member

maflcko commented Sep 20, 2018

Still needs rebase, so closing for now. Let me know when you work on this again, so I can reopen.

@maflcko maflcko closed this Sep 20, 2018
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants