Live data from Hacker News

C++ Headers are Expensive

virtuallyrandom.com

61–70 of 115 posts

Re: C++ Headers are Expensive

#61

> The test was done with the source code and includes on a regular hard drive, not an SSD. In my opinion, this makes any conclusion dubious. If you really care about compile times in C++, step 0 is to make sure you have an adequate machine (at least quadcore CPU/ lot of RAM/SSD). If the choice is between spending programmer time trying to optimize compile times, versus spending a couple hundred dollars for an SSD, 99…

Just to address part of your concern: Traditionally disk speed makes very little difference to compile times for real world C/C++ projects. This is because real world projects have many files, and each one can be compiled in parallel. Once you spawn sufficient compilers in parallel, the CPU becomes the bottleneck, not the disk. (I.e. when a compilation asks for I/O, it then yields the CPU to other compilers which have CPU work to do)

Note that Visual Studio, for example, does a poor job of this because it only spawns one compilation per CPU thread. This results in individual threads being idle more than they ought to be.

Re: C++ Headers are Expensive

#62
post #3

Earlier quoted context omitted.

As far as I understand it's also one of the reasons modules are a thing... or at least people want them to be. Precompiled headers are a pretty ugly solution and the way they've been implemented in the past could be really nasty. (IIRC in old GCC versions it would copy some internal state to disk, then later load it from disk and manually adjust pointers!)

This isn't uncommon, especially for file formats which are meant for internal consumption. Of course, they end up being huge cans of worms in terms of security, stability and maintainability going forward. Basically, instead of defining a real serialization format (and thus having to write serializer/deserializer code), it's way easier to just `fwrite` out your internal structs to disk, one after another, and write s…

Which is mostly due to the lack of run-time reflection. OTOH, with a little creativity its possible to create code generators to attach a commonly named (say .serialize method) to classes to dump their POD fields, and call serialize on directly encapsulated classes.

But your basically right, everyone ends up doing it their own way which just ends up being a PITA.

Re: C++ Headers are Expensive

#63
post #39

Earlier quoted context omitted.

One hickup is that with unique_ptr you now have a rule of 5 thing, you need to declare a destructor which means you need to declar the copy/move constructor and assignment too. Not usually a big deal, but is extra code.

This is why the rule of zero advocates are getting louder.

Rule of zero classes are awesome. It forces a separation of concerns too, generally a good thing :), as the handling of special things is done by a class that does that(e.g. unique_ptr, vector...) and your class describes only what is in it and how to interact with it. But no more detailed than that.

Re: C++ Headers are Expensive

#64

Earlier quoted context omitted.

You should read the paper a bit more closely. "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3 %. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified" We know that c…

I think you may want to read the quote from the paper a bit more carefully. "...he will be wise to look carefully at the critical code; but only after that code has been identified" I was told that "premature optimization is not really a thing" as a response to a reply I received that pImpls should be avoided at all costs. When we analyze the performance impact of software, we don't shotgun change things because of a…

> EDIT: the downvoting on this comment is amusing, given that "avoid pImpls" is exactly the sort of 97% cruft that Knuth was addressing

Again, no, it isn't. You seem to be severely underestimating the systemic impact of cache misses if you are considering them a "small" impact to efficiency.

It's a well-proven, well-known problem. Ignoring it falls under Knuth's guidance of "A good programmer will not be lulled into complacency by such reasoning."

pImpls are the sort of thing you use at API boundaries to avoid leaking implementation details into users, but that's trading efficiency & complexity for a more stable API boundary. Scattering them throughout your code base would be like compiling with -O0. It's a silly, nonsensical waste of a user's constrained resources for a slight gain at compile time at a cost of code complexity.

Or, alternatively, using pImpls to optimize for compile time is a premature optimization. You should only optimize for compile time at most 3% of your source files, ever. The other 97% of your source files should be written for clarity & simplicity, which means no pImpls.

Re: C++ Headers are Expensive

#65

> The test was done with the source code and includes on a regular hard drive, not an SSD. In my opinion, this makes any conclusion dubious. If you really care about compile times in C++, step 0 is to make sure you have an adequate machine (at least quadcore CPU/ lot of RAM/SSD). If the choice is between spending programmer time trying to optimize compile times, versus spending a couple hundred dollars for an SSD, 99…

Its that RAM that is the key, you want enough to keep all the source files and intermediate files sitting in cache, so the only disk activity is updating timestamps and flushing the .O files to disk.

I've seen this problem a few times, someone looks at their N core machine with M GB and says, oh look i'm only using 3/4 of M so when I buy the 4xN cores machine I'm going to put M ram in it again. Then everything runs poorly because the disks are getting hammered now that there are another 32 jobs (or whatever) each consuming a GB. Keep adding ram until their is still free RAM during the build. Its going to run faster from ram that waiting for a super speedy disk to read the next c/.o/etc file.

Re: C++ Headers are Expensive

#66

Earlier quoted context omitted.

The pImpl pattern costs programmer time as it's more code to write. By contrast compiling is just CPU time and you can trivially throw a bigger workstation at the problem.

This depends on who is writing the code and who is compiling the headers. A software developer who is building headers for someone else (an internal or external client) may trade the overhead of this pattern for a faster compilation time. Reducing compilation time by 80% may be well worth the overhead of adding 10% more code to an interface. It is not always possible to just throw more hardware at the problem of comp…

> It is not always possible to just throw more hardware at the problem of compilation. For instance, one may be using a build pipeline that requires specific steps to be followed as part of gating tasks. The time it takes to compile code over and over again for unit testing, behavioral testing, acceptance testing, integration testing, etc., each impacts delivery time and handoff.

All of that is solved by throwing more hardware at it.

Alternatively if compile time is not the slow part of that pipeline, then you're prematurely optimizing the wrong thing anyway.

> Earlier in my career, I worked with a code base that was approximately 10 million lines of code in size. Compiling this code base would take approximately 7 hours on the best hardware we could buy. The C++ developers were adamant about ensuring that their headers were "complete" as they called it. With a few changes, such as forward declarations, abstract interfaces, and encapsulation, my team was able to reduce that compile time to less than 35 minutes.

In other words you only optimized the critical 3% of the codebase rather than prematurely optimizing everything with pImpl abstractions?

Re: C++ Headers are Expensive

#67

Earlier quoted context omitted.

I think you may want to read the quote from the paper a bit more carefully. "...he will be wise to look carefully at the critical code; but only after that code has been identified" I was told that "premature optimization is not really a thing" as a response to a reply I received that pImpls should be avoided at all costs. When we analyze the performance impact of software, we don't shotgun change things because of a…

> EDIT: the downvoting on this comment is amusing, given that "avoid pImpls" is exactly the sort of 97% cruft that Knuth was addressing Again, no, it isn't. You seem to be severely underestimating the systemic impact of cache misses if you are considering them a "small" impact to efficiency. It's a well-proven, well-known problem. Ignoring it falls under Knuth's guidance of "A good programmer will not be lulled into…

> Again, no, it isn't. You seem to be severely underestimating the systemic impact of cache misses if you are considering them a "small" impact to efficiency.

You are severely overestimating the impact of cache misses if you think that all indirection must be eliminated and any use of pImpls at all is always wrong, as you seem to be implying.

> pImpls are the sort of thing you use at API boundaries to avoid leaking implementation details into users, but that's trading efficiency & complexity for a more stable API boundary. Scattering them throughout your code base would be like compiling with -O0.

It's a good thing that I never advocated using them everywhere then. Where did you read me saying this?

> Or, alternatively, using pImpls to optimize for compile time is a premature optimization.

Only if this is done by default, which I have not advocated for anywhere in this thread. I called it a tool in the toolbox. I mentioned it as one of several possibilities. Somehow you have translated this into "use pImpls everywhere", which is a strawman.

Re: C++ Headers are Expensive

#68

Earlier quoted context omitted.

This depends on who is writing the code and who is compiling the headers. A software developer who is building headers for someone else (an internal or external client) may trade the overhead of this pattern for a faster compilation time. Reducing compilation time by 80% may be well worth the overhead of adding 10% more code to an interface. It is not always possible to just throw more hardware at the problem of comp…

> It is not always possible to just throw more hardware at the problem of compilation. For instance, one may be using a build pipeline that requires specific steps to be followed as part of gating tasks. The time it takes to compile code over and over again for unit testing, behavioral testing, acceptance testing, integration testing, etc., each impacts delivery time and handoff. All of that is solved by throwing mor…

> Alternatively if compile time is not the slow part of that pipeline, then you're prematurely optimizing the wrong thing anyway.

Developer productivity does not matter in your world?

> In other words you only optimized the critical 3% of the codebase rather than prematurely optimizing everything with pImpl abstractions?

Yes, because nowhere in this thread have I advocated prematurely optimizing everything with pImpl abstractions. Those are words you have put in my mouth. pImpl abstraction is a single tool that can be used to improve compile-time performance. Not all the time, but in a fraction of the 3% of the time where it is appropriate.

Re: C++ Headers are Expensive

#69
If C++ compile time is a concern and/or impediment to productivity, I recommend the seminal work regarding this topic by Lakos:

Large-Scale C++ Software Design[0]

The techniques set forth therein are founded in real-world experience and can significantly address large-scale system build times. Granted, the book is dated and likely not entirely applicable to modern C++, yet remains the best resource regarding insulating modules/subsystems and optimizing compilation times IMHO.

0 - https://www.pearson.com/us/higher-education/program/Lakos-La...

Re: C++ Headers are Expensive

#70
post #61

> The test was done with the source code and includes on a regular hard drive, not an SSD. In my opinion, this makes any conclusion dubious. If you really care about compile times in C++, step 0 is to make sure you have an adequate machine (at least quadcore CPU/ lot of RAM/SSD). If the choice is between spending programmer time trying to optimize compile times, versus spending a couple hundred dollars for an SSD, 99…

Just to address part of your concern: Traditionally disk speed makes very little difference to compile times for real world C/C++ projects. This is because real world projects have many files, and each one can be compiled in parallel. Once you spawn sufficient compilers in parallel, the CPU becomes the bottleneck, not the disk. (I.e. when a compilation asks for I/O, it then yields the CPU to other compilers which hav…

I guess it depends on how you define "very little", and what system includes you have.

I've just tested one of my ~300 KLOC C++ projects, broken into 479 .cpp files and 583 .h files.

Using Linux (GCC) after dropping the disk cache, on a 5400 RPM HD, the full build on 14 threads took: 78 seconds.

On a fast SSD (same machine, after dropping caches again) it took 61 seconds.

Linking was ~7 seconds faster on the SSD, so arguably you could say that actual compilation wasn't the same ratio as fast, but overall build time is most definitely faster.

Source was on the same drive as the build target directory.

At a previous company I worked at, we got SSDs to speed up compilation (and it did).

Post reply on HN