Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple source file executable slower than single source file executable

I had a single source file which had all the class definitions and functions.

For better organization, I moved the class declarations(.h) and implementations(.cpp) into separate files.

But when I compiled them, it resulted in a slower executable than the one I get from single source executable. Its around 20-30 seconds slower for the same input. I dint change any code.

Why is this happening? And how can I make it faster again?

Update: The single source executable completes in 40 seconds whereas the multiple source executable takes 60. And I'm referring to runtime and not compilation.

like image 752
questions Avatar asked Mar 16 '12 18:03

questions


3 Answers

I think, your program runs faster when compiled as a single file because in this case compiler has more information, needed to optimize the code. For example, it can automatically inline some functions, which is not possible in case of separate compilation.

To make it faster again, you can try to enable link-time optimizer (or whole program optimizer) with this option: -flto.


If -flto option is not available (and it is available only starting with gcc 4.6) or if you don't want to use it for some reason, you have at least 2 options:

  1. If you split your project only for better organization, you can create a single source file (like all.cxx) and #include all source files (all other *.cxx files) to this file. Then you need to build only this all.cxx, and all compiler optimizations are available again. Or, if you split it also to make compilation incremental, you may prepare 2 build options: incremental build and unity build. First one builds all separate sources, second one - only all.cxx. See more information on this here.
  2. You can find functions, that cost you performance after splitting the project, and move them either to the compilation unit, where they are used, or to header file. To do this, start with profiling (see "What can I use to profile C++ code in Linux?"). Further investigate parts of the program, that significantly impact program's performance; here are 2 options: either use profiler again to compare results of incremental and unity builds (but this time you need a sampling profiler, like oprofile, while, an instrumenting profiler, like gprof, most likely, is too heavy for this task); or apply 'experimental' strategy, as described by gbulmer.
like image 172
Evgeny Kluev Avatar answered Oct 29 '22 12:10

Evgeny Kluev


This probably has to do with link time optimization. When all your code is in a single source file, the compiler has more knowledge about what your code does so it can perform more optimizations. One such optimization is inlining: the compiler can only inline a function if it knows its implementation at compile time!

These optimizations can also be done at link time (rather than compile time) by passing the -flto flag to gcc, both for the compile and for the link stage (see here).

like image 6
Thomas Avatar answered Oct 29 '22 13:10

Thomas


This is a slower approach to get back to the faster runtime, but if you wanted to get a better understanding of what is causing the large change, you could do a few 'experiments'

One experiment would be to find which function might be responsible for the large change. To do that, you could 'profile' the runtime of each function.

For example, use GNU gprof, part of GNU binutils: http://www.gnu.org/software/binutils/
Docs at: http://sourceware.org/binutils/docs-2.22/gprof/index.html

This will measure the time consumed by each function in your program, and where it was called from. Doing these measurements will likely have an 'Heisenberg effect'; taking measurements will effect the performance of the program. So you might want to try an experiment to find which class is making the most difference.

Try to get a picture of how the runtime varies between having the class source code in the main source, and the same program but with the class compiled and linked in separately.

To get a class implementation into the final program, you can either compile and link it, or just #include it into the 'main' program then compile main.

To make it easier to try permutations, you could switch a #include on or off using #if:

#if defined(CLASSA)  // same as #ifdef CLASSA
#include "classa.cpp"
#endif
#if defined(CLASSB)
#include "classb.cpp"
#endif

Then you can control which files are #included using command line flags to the compiler, e.g.

g++ -DCLASSA -DCLASSB ... main.c classc.cpp classd.cpp classf.cpp  

It might only take you a few minutes to generate the permutations of the -Dflags, and link commands. Then you'd have a way to generate all permutations of compile 'in one unit' vs separately linked, then run (and time) each one.

I assume your header files are wrapped in the usual

#ifndef _CLASSA_H_
#define _CLASSA_H_
//...
#endif

You would then have some information about the class which is important.

These types of experiment might yield some insight into the behaviour of the program and compiler which might stimulate some other ideas for improvements.

like image 1
gbulmer Avatar answered Oct 29 '22 13:10

gbulmer