6

In order to reduce the compilation time of a fairly large framework at work I was considering moving class method definitions in .h files to their associated .cpp file if they were either very large or required includes to compile that could be moved to the associated .cpp file. For clarity, below is a contrived example (although Foo::inc is a tiny method)

main.cpp:

#include "Foo.h"

int main(int argc, char** argv) {
    Foo foo(argc);
    foo.inc();
    return foo.m_argc;
}

Foo.h before (no need for Foo.cpp yet):

class Foo {
public:
    int m_argc;
    Foo (int argc) : m_argc(argc) {}
    void inc() { m_argc++; }
};

Foo.h after:

class Foo {
public:
    int m_argc;
    Foo (int argc) : m_argc(argc) {}
    void inc();
};

Foo.cpp:

#include "Foo.h"

void Foo::inc() { m_argc++; }

A long time ago a coworker mentioned that there may be cases where this can cause run time performance to slowdown. I was looking for this case on Google but could not seem to find it, the accepted answer to this question is the closest I could find but it does not give the case, just a mention that it can happen: Moving inline methods from a header file to a .cpp files

On a side note, I am not interested in the case where a method explicitly uses inline, the answer I linked above was just the closest I could find to what I was looking for

What case (if any) could cause a run time slowdown?

Community
  • 1
  • 1
asimes
  • 5,749
  • 5
  • 39
  • 76
  • 3
    Your example is one where there would probably be a slowdown. In the current code, the `inc` function is defined inline and non-virtual, so the compiler can inline the function without the function call overhead. The new version requires a full function call. The inlined function could represent a considerable saving if the `inc` function is used a lot. If it is seldom used, then the overhead won't matter. – Jonathan Leffler Jun 28 '15 at 19:55
  • 1
    @JonathanLeffler, thank you, didn't realize this was already the case I was looking for. I realize that it is up to the compiler to inline in the original implementation but is there a way to preserve the compiler's decision in the moved version? – asimes Jun 28 '15 at 20:05
  • 1
    (Just putting this information here I found after reading comments) As far as I can tell I'd need `-flto` for the cross module link time optimization. Without it the second case will involve a function call and so will be slower. However `-flto` comes with some side effects (it can increase the size of files) – asimes Jun 28 '15 at 21:00
  • Just wanted to add two good references: [Can the linker inline functions?](http://stackoverflow.com/questions/5987020/can-the-linker-inline-functions) and a more general discussion about [Benefits of inline functions in C++?](http://stackoverflow.com/questions/145838/benefits-of-inline-functions-in-c). – Florian Jun 29 '15 at 07:19

2 Answers2

7

Your original method void inc() { m_argc++; } was automatically inline so the compiler was allowed to replace the call with the inlined version.

As soon as you move the method out of the class definition to the module, this method is not inline anymore, the inline expansion doesn't happen, the standard method call is there, and the result can be slower.

dlask
  • 8,776
  • 1
  • 26
  • 30
  • 1
    Why won't be inlined?? The compiler can't detect that the method is so trivial that should be inlined if it is in a diferent file?? – DGomez Jun 28 '15 at 20:01
  • @DGomez, just a reminder, that method I posted was trivial for the sake of SO – asimes Jun 28 '15 at 20:02
  • dlask, is there a way to preserve the compilers original decision to have the method be inlined when it is moved to the .cpp? – asimes Jun 28 '15 at 20:03
  • 3
    Modules are compiled independently. In order to have a function/method inlined, its source code must be available so, usually, it must be present in the header. – dlask Jun 28 '15 at 20:04
  • 1
    This may be true if you're using a compiler from 1995 or one designed for some obscure embedded environment, but all the major compilers now support some form of link-time code generation and optimization, and are able to inline functions defined in other translation units. – bcrist Jun 28 '15 at 20:06
  • See [Is link time optimization in gcc 5.1 good enough to give up on inlining simple functions?](http://stackoverflow.com/questions/29835512/is-link-time-optimization-in-gcc-5-1-good-enough-to-give-up-on-inlining-simple-f) – Florian Jun 28 '15 at 20:13
  • I suggest you to take the g++ 5.1 compiler, compile the OP's example, and look at the produced assembly code. I've made it. – dlask Jun 28 '15 at 20:21
  • 2
    After reading around a bit it seems like I would have to use `-flto` for cross module link time optimization so I think dlask's answer is correct. There are side effects of `-flto` that I don't like so I guess the answer is yes, the second case is slower – asimes Jun 28 '15 at 20:49
  • 1
    This answer is completely wrong. Any reasonably modern (< 10 years old) compiler features whole-module optimization. – The Paramagnetic Croissant Jun 30 '15 at 08:41
2

Reducing the header dependencies is always a good idea to reduce the compilation time. It's one of the top items in listings like What techniques can be used to speed up C++ compilation times?

I would recommend to - if not already done - take a look into the major players eating up your compilation time with Profiling the C++ compilation process

And there are helpers to sort through your include dependencies, see Automate #include refactoring in C++

About the question if moving code to the source files will slow down your runtime performance: It depends. Generally speaking you can say you give the compiler a chance to inline if you have the function in the header.

I like to quote from the C++ FAQ - Inlining:

Do inline functions improve performance?

Yes and no. Sometimes. Maybe.

There are no simple answers. inline functions might make the code faster, they might make it slower. They might make the executable larger, they might make it smaller. They might cause thrashing, they might prevent thrashing. And they might be, and often are, totally irrelevant to speed.

What the compiler - and maybe later the linker - does with it depends on what compiler toolchain you are using and what compiler/linker options you give.

See e.g. all the what-happens-when in inline - Using the GNU Compiler Collection:

... GCC does not inline any functions when not optimizing ...

Some references:

Community
  • 1
  • 1
Florian
  • 39,996
  • 9
  • 133
  • 149
  • Basically none of this is relevant to the question, you could have just made an answer based on the LTO link you put at the top – asimes Jun 29 '15 at 13:11
  • @asimes You are right. I got distracted by the "my colleague said it will slow down the runtime performance". I reduced the scope of my answer and added something on reducing C++ compilation times because I think you can save the effort of moving code in the .cpp files. – Florian Jun 29 '15 at 15:35