←back to thread

141 points vblanco | 7 comments | | HN request time: 0s | source | bottom
Show context
Asooka ◴[] No.44436332[source]
I would like to see a comparison between modules and precompiled headers. I have a suspicion that using precompiled headers could provide the same build time gains with much less work.
replies(4): >>44436478 #>>44436777 #>>44436830 #>>44439283 #
w4rh4wk5 ◴[] No.44436830[source]
From my experience, compile times ain't an issue if you pay a little attention. Precompiled header, thoughtful forward declarations, and not abusing templates get you a long way.

We are commonly working with games that come with a custom engine and tooling. Compiling everything from scratch (around 1M lines of modern C++ code) takes about 30-40 seconds on my desktop. Rebuilding 1 source file + linking comes in typically under 2 seconds (w/o LTO). We might get this even lower by introducing unity builds, but there's no need for that right now.

replies(1): >>44436956 #
ttoinou ◴[] No.44436956[source]
40 seconds for 1M lines seems super fast, do you have a fast computer and/or did you spend a lot of time optimizing the compilation pipeline ?
replies(3): >>44437056 #>>44437789 #>>44441379 #
vblanco ◴[] No.44437056[source]
The modern cryengine compiles very fast. Their trick is that they have architected everything to go through interfaces that are on very thin headers, and thus their headers end very light and they dont compile the class properties over and over. But its a shame we need to do tricks like this for compile speed as they harm runtime performance.
replies(1): >>44437223 #
1. ttoinou ◴[] No.44437223[source]
Why does it ruin runtime performance ? The code should be almost the same
replies(2): >>44437281 #>>44439322 #
2. vblanco ◴[] No.44437281[source]
Because you now need to go through virtual calls on functions that dont really need to be virtual, which means the possible cache miss from loading the virtual function from vtable, and then the impossibility of them being inlined. For example they have a ITexture interface with a function like virtual GetSize(). If it wasnt all through virtuals, that size would just be a vec2 in the class and then its a simple load that gets inlined.
replies(2): >>44437305 #>>44441425 #
3. ttoinou ◴[] No.44437305[source]
Ah yes this kind of interface ok indeed this doesn't seem like a useful layer when running the program. Maybe the compilers could optimize this though
replies(2): >>44439278 #>>44441694 #
4. jeremiahar ◴[] No.44439278{3}[source]
In my experience, as long as there's only a single implementation, devirtualization works well, and can even inline the functions. But you need to pass something along the lines of "-fwhole-program-vtables -fstrict-vtable-pointer" + LTO. Of course the vtable pointer is still present in the object. So I personally only use the aforementioned "thin headers" at a system level (IRenderer), rather than for each individual object (ITexture).
5. barchar ◴[] No.44439322[source]
In addition to what everyone else has said it also makes it difficult to allocate the type on the stack. Even if you do allow it you'll at least need a probe.
6. pjmlp ◴[] No.44441425[source]
At least on clang with LTO, with bitcode variant, that should be possible to devirtualize, assuming most of those interfaces only have a single implementation.
7. drysine ◴[] No.44441694{3}[source]
They can sometimes

https://quuxplusone.github.io/blog/2021/02/15/devirtualizati...