76

This question is perhaps somehow odd, but how can I speed up g++ compile time? My C++ code heavily uses boost and templates. I already moved as much as possible out of the headers files and use the -j option, but still it takes quite a while to compile (and link).

Are there any tools out there which analyse my code and point out bottle-necks for the compiler? Or can one somehow profile the compiler running on my code? This would be really nice, because sometimes I have the impression, that I spent too much time staring at the compiler console log ...

Danvil
  • 22,240
  • 19
  • 65
  • 88
  • 2
    Possible duplicate of http://stackoverflow.com/questions/373142/what-techniques-can-be-used-to-speed-up-c-compilation-times – strager Aug 03 '10 at 15:04
  • 1
    @Neil: Too long. Especially if there is a change in a widely used template header file almost every piece of code re-compiles. – Danvil Aug 04 '10 at 11:53

10 Answers10

57

What has been most useful for me:

  • Build on a RAM filesystem. This is trivial on Linux. You may want to keep a copy of common header files (precompiled or the actual .h files) on the RAM filesystem as well.
  • Precompiled headers. I have one per (major) library (e.g. Boost, Qt, stdlib).
  • Declare instead of include classes where possible. This reduces dependencies, thus reduces the number of files which need to be recompiled when you change a header file.
  • Parallelize make. This usually helps on a case-by-case basis, but I have -j3 globally for make. Make sure your dependency graphs are correct in your Makefile, though, or you may have problems.
  • Use -O0 if you're not testing execution speed or code size (and your computer is fast enough for you not to care much about the (probably small) performance hit).
  • Compile each time you save. Some people don't like this, but it allows you to see errors early and can be done in the background, reducing the time you have to wait when you're done writing and ready to test.
strager
  • 88,763
  • 26
  • 134
  • 176
  • 1
    FYI, just tried making a precompiled header with a bunch of boost and stl libs. I put it on ram fs. no speed up. – kirill_igum Jul 29 '14 at 05:31
  • I think this lowered my compile (not complete) time by about ten times. – Evan Carslake Apr 04 '16 at 21:53
  • 2
    I doubt building in a RAM filesystem would improve anything. Given you got enough RAM, Linux kernel just caches writes and reads, and so reading/writing from/to files should already use RAM. – Hi-Angel Feb 22 '19 at 09:18
  • 1
    Instead of talking about RAM filesystem, today one should say: Don't use a network filesystem for anything: sources, object files, include files, tools. – Frank Puck Nov 14 '22 at 14:08
17

Here's what I've done to speed up builds under a very similar scenario that you describe (boost, templates, gcc)

  • build on local disk instead of a network file system like NFS
  • upgrade to a newer version of gcc
  • investigate distcc
  • faster build systems, especially more RAM
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • 4
    icecream/icecc is better than distcc: "Unlike distcc, Icecream uses a central server that schedules the compilation jobs to the fastest free server dynamically." – Zitrax Aug 03 '10 at 14:53
  • 1
    ccache helps only if you compile same source again. This is usually not the case when developing because Make should already recognize this and so the compiler is not started again. ccache helps for same files in different directories, e.g. all the "configure"-Tests on Linux systems or if you did a make clean or compile the same (or similar) sources in another directory. This often happens in source Linux distributions like Gentoo, where after a compilation failure and restart the working directory of the compile is cleaned. In this scenario, ccache can speed up the compilation a lot. – IanH Aug 03 '10 at 15:14
  • 5
    `ccache` helps greatly when you use DVCS or are in a team, because in both cases chances are the file has already been compiled, even though it was from another location. – Matthieu M. Aug 03 '10 at 15:18
17

I assume that we are talking about minutes to compile a file, i.e. precompiled headers or local disk issues aren't the problem.

Long compilation times with deep template code (boost etc.) is often rooted in the unfriendly asymptotic behavior of gcc when it comes to template instantiation, in particular when variadic templates are emulated with template default arguments.

Here's a document which names reduced compilation time as a motivation for variadic templates:

cpptruths had an article about how gcc-4.5 is much better in this behalf and how it does brilliantly with its variadic templates:

IIRC then BOOST has a way to limit the generation of template default parameters for the pseudo-variadics, I think 'g++ -DBOOST_MPL_LIMIT_LIST_SIZE=10' should work (the default is 20)

UPDATE: There is also a nice thread with general techniques to speed up compiling here on SO which might be useful:

UPDATE: This one is about the performance issues when compiling templates, the accepted answer recommends gcc-4.5 too, also clang is mentioned as a positive example:

Community
  • 1
  • 1
Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
  • 3
    see also http://gcc.gnu.org/gcc-4.5/changes.html: `Compilation time for code that uses templates should now scale linearly with the number of instantiations rather than quadratically, as template instantiations are now looked up using hash tables.` – Sebastian Mach Dec 22 '11 at 11:14
12

If you're doing a lot of recompilation, ccache might help. It doesn't actually speed up the compilation, but it will give you a cached result if you happen to do a useless recompilation for some reason. It might give an impression of tackling the wrong problem, but sometimes the rebuilding rules are so complicated that you actually do end up with the same compilation step during a new build.

Additional idea: if your code compiles with clang, use it instead. It's usually faster than gcc.

viraptor
  • 33,322
  • 10
  • 107
  • 191
3

On top of what everybody else added and what you're already doing (parallelized build, compiler options, etc), consider hiding templates in implementation classes, accessed through interfaces. That means that instead of having a class like:

// ClsWithNoTemplates.h file, included everywhere

class ClsWithTemplates
{
    ComplicatedTemplate<abc> member;
    // ...

public:
    void FunctionUsingYourMember();
};

you should have:

// ClsWithNoTemplates.h file:

class ClsWithTemplatesImplementation; // forward declaration
  // definition included in the ClsWithNoTemplates.cpp file
  // this class will have a ComplicatedTemplate<abc> member, but it is only 
  // included in your ClsWithNoTemplates definition file (that is only included once)


class ClsWithNoTemplates
{
     ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
    void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};

This changes your OOP design a bit, but it's for the good: including the definition of 'ClsWithNoTemplates' is now fast and you only (pre)compile the definition of 'ClsWithNoTemplates' once.

Aditionally, if you change the implementation code, any code that included ClsWithNoTemplates.h will probably not need to be redefined.

This change should dramatically increase your partial compilation time, and it will also help in the case where your ClsWithNoTemplates is a public interface exported from a library file: since the file is not changed when you only change the implementation, your dependent client code doesn't need to be recompiled at all.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
3

Try the PIMPL technique, this question: What techniques can be used to speed up C++ compilation times?

It'll prevent the compiler from following the chain of header files and implementations every time you need to do something.

Community
  • 1
  • 1
gtrak
  • 5,598
  • 4
  • 32
  • 41
2

If there are a lot of files you can speed up compilation a lot by just having one .cpp file that #includes all the other .cpp files. This of course requires you to be more careful with macros and such that you already have defined per file as they will now be visible to other cpp files.

If there are many files this can reduce compile time a lot.

Zitrax
  • 19,036
  • 20
  • 88
  • 110
  • Maybe. Until your compiler eats through memory and starts swapping. – KeithB Aug 03 '10 at 16:48
  • Just combine in reasonable chunks, I am not saying you should put 3 million lines of code in one single file. I use this technique on a huge project with very good results, on some compilers down to 1/5 of the original time. – Zitrax Aug 03 '10 at 17:15
1

Instantiate less templates and inline functions. Precompile as much as you can and just link it rather than compiling everything from scratch. Make sure you're using the latest version of GCC.

However, it's a simple fact that C++ is an incredibly complex language and compiling it takes quite some time.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

This paper describes a method for compiling template code much like "traditional" non-template object files. Saves compile & link time, with only one line of code overhead per template instantiation.

Chris Tonkinson
  • 13,823
  • 14
  • 58
  • 90
  • I can't seem to download the pdf for this article without it wanting to sign in. Do you have to actually pay to get access to this paper? – greatwolf Dec 18 '10 at 12:04
0

Usually, the most expensive parts of compilation are (a) reading the source files (ALL of them) and (b) loading the compiler into memory for each source file.

If you have 52 source (.cc) files, each of which #includes 47 #include (.h) files, you are going to load the compiler 52 times, and you are going to plow through 2496 files. Depending on the density of comments in the files, you may be spending a fair chunk of time eating useless characters. (In one organization I have seen, header files varied between 66% and 90% comments, with only 10%-33% of the file being "meaningful". The single best thing that could be done to enhance readability of those files was strip out every last comment, leaving only code.)

Take a long look at how your program is physically organized. See whether you can combine source files, and simplify your hierarchy of #include files.

Decades ago, companies like IBM understood this, and would write their compilers so that the compiler could be handed a list of files to compile, not just one file, and the compiler would only be loaded once.

John R. Strohm
  • 7,547
  • 2
  • 28
  • 33
  • 2
    How much time does "compiling" comments take? (It's done by the preprocessor and shouldn't be very complicated, compared to making sense of template metaprogramming?) – UncleBens Aug 03 '10 at 13:57
  • So I g++ can not do this? And is there some tool which tells my how much include files the compiler has to read for a given source file? – Danvil Aug 03 '10 at 13:58
  • 7
    Loading the compiler is unlikely to happen more than once; it will almost certainly stay in the disk cache after the first file, along with common header files. Computer architectures and speeds have changed a lot over the decades, and common wisdom from IBM's heyday might not so useful today. – Mike Seymour Aug 03 '10 at 14:18
  • 4
    -1, Code comments are meaningful and removing them could be dangerous. Removing comments will not make source code more "readable" as you claim – Malfist Aug 03 '10 at 16:11
  • @Danvil, the key is that the compiler must READ the comment, to get to the executable line(s) after the comment. Even if it is "read" by the preprocessor, it still has to be read, and you still pay the cost of reading it. – John R. Strohm Aug 03 '10 at 19:58
  • @Malfist, I stand by my statement. Comments exist to help the programmers understand the code. If the comments are such as to get in the way of that understanding, then they are not helping. I have seen too much code where that was precisely what was going on. – John R. Strohm Aug 03 '10 at 20:02
  • Anyway, boost libraries don't seem to have excessive comments (boost.bind doesn't seem to have virtually any, except for copywrite notes, closing namespaces and #ifdef's). – UncleBens Aug 03 '10 at 22:11
  • The Intel compiler works exactly the way you describe (handing it a list of files). Even if you don't and call the compiler in multiple processes for each file, it starts a compile daemon in the background and does the work there to minimize initialization times. – BenG Aug 04 '10 at 05:56
  • (I know it's 4 years ago) Code comments are not always a good thing, but not always a bad thing. They need to be evaluated on a need-to-be basis and stripped out. As always, if it smells, get rid of it. But not all comments smell (even though many comments do, like all of ours in this post!). – osirisgothra Feb 01 '14 at 11:18