4

Based on my understanding, the chief benefits of creating a program with multiple compilation units are reusability of components and shorter compile times when incorporating small changes.

I also think (possibly wrongly) that there is a penalty associated with this, in that functions which are defined in their own compilation units cannot be declared as "inline".
[I recognize that this keyword does not actually force the compiler to inline-expand functions, but my understanding is that it gives the compiler more flexibility to optimize, and is therefore worth including wherever possible.]

So far so good?

My real question is whether the cost/benefit analysis still favours multiple compilation units when the program is solving a complicated modelling problem, and is required to iterate through its main loop for months on a cluster in order to generate useful output.

Say a multi-compilation unit program takes a few minutes to compile while the same program re-configured as a single compilation unit takes a few hours to compile... if the single compilation unit declares all functions as inline and thus presents more optimization opportunities, it seems reasonable to me to expect that execution time could decrease by a few percent, more than making up for the extra compile time.

Are there good rules of thumb for situations like this, or is it heavily situation-dependent?

Mat
  • 202,337
  • 40
  • 393
  • 406
user1476176
  • 1,045
  • 1
  • 7
  • 15
  • 1
    Now before everyone spams "premature optimization". I will say that yes, it is indeed possible to get more than a few % from cramming everything into a single compiling unit. I've done it and seen it myself. – Mysticial Jul 26 '12 at 06:21
  • 1
    As ever with performance questions, data trumps argument. Test and measure. – High Performance Mark Jul 26 '12 at 06:23
  • It's very easy to underestimate the number of times you will hit 'compile' while you are working on the code, even if your change is trivial. – Ian Goldby Jul 26 '12 at 07:05

3 Answers3

2

Some compilers/linkers are able to automatically inline functions even when they are defined in one compilation unit and used in another. Microsoft's linker can certainly do this.

To me the main benefit of splitting code into separate compilation units is the overall organization of the code and I always make decisions based on this fact rather than the considerations you have. Also don't forget that larger programs are often worked on by more than one person at a time. Obviously separate compilation units is a great benefit then.

In short I think it's heavily situation dependent. I think your situation is a rare one however.

jahhaj
  • 3,021
  • 1
  • 15
  • 8
  • 3
    Should add that your characterization of the inline keyword is wrong. A compiler can inline function not declared inline and can fail to inline a function that is declared inline. The real meaning of the inline keyword is to avoid multiple definition errors when functions are defined in header files. It tells the compiler/linker that it might see this function defined several times, and it's not an error if it does. – jahhaj Jul 26 '12 at 06:32
2

As already stated by others, the main benefit of decomposing a program into different compilation units is readability. Shorter compilation times is somehow a nice side-effect of the idea.

If you care about inlining, you can resort to Link Time Code Generation and Link-Time Optimization. The combination of program decomposition into compilation units and LTO looks like the ideal solution, although it is not clear if the kind of optimizations performed by a compiler when the full definition of the function is available could be performed by LTO. For example, I don't know if LTO could support return-value optimization in C++, since it is something done at an high level of abstraction. Performance tests are needed. (Edit: RVO is performed even in absence of LTO and advanced tricks like these, at least on gcc and clang [I tried]. Most probably, this optimization is performed by changing the ABI of the function, which takes a "hidden pointer" to the object which has to be constructed and returned in the function.)

A third solution which could be worth investigating is to use something like sqlite amalgamation, a process of putting different compilation units into one giant .c file. Looks like something which requires a kinda heavy user-made infrastructure, although.

Community
  • 1
  • 1
akappa
  • 10,220
  • 3
  • 39
  • 56
0

Don't forget the 80-20 rule. 80% of your programs runtime is spent in 20% of code. Maybe you can have those 20% in a single compiling unit, and the rest well organized?

And about the sources organization, you still can put algorithms into headers (either as templates or as inline functions) and then compose the source from them.

Adam Trhon
  • 2,915
  • 1
  • 20
  • 51