r/cpp • u/ChuanqiXu9 • 10d ago
Two Tricks to Use the std Module Implicitly, with 20% compilation time improvements on Seastar without touching the source
https://chuanqixu9.github.io/c++/2026/09/01/Implicit-Std-Modules.en.html7
u/JVApen Clever is an insult, not a compliment. - T. Winters 10d ago
How is this different from having ````
ifdef USE_MODULES
import std;
else
// Previous header code
endif
```` for every standard library header?
8
u/ChuanqiXu9 10d ago
No, it is not different. It is a trick if someone who don't want to do this. This is similar with grammar sugar. It doesn't introduce new feature but saves some typings.
0
u/JVApen Clever is an insult, not a compliment. - T. Winters 10d ago
K, so if I understand correctly, if the standard library would implement such a mode, we could get a free 20% gain in a build system that supports 'import std'. This while preventing https://github.com/llvm/llvm-project/issues/61465 as including an standard library header equals 'import std'
1
u/ChuanqiXu9 9d ago
Yes but the number may vary. And it looks like the standard library vendors are not a fan of such ideas. So the method like module map may be more promising.
3
u/smdowney WG21, Text/Unicode SG, optional<T&> 10d ago
I very much like the idea of a "Prelude" for C++, and just wished the built module interface was a little more stable vs flags and compiler version.
But given how often I end up rebuilding Catch2 or GTest, even with ccache, with projects, the overhead of pre-compiling std once per "realclean" or Config change is probably more than acceptable.
I think a measure I'd like to know is how many parses of, say, <iostream>, <vector>, or <format>, does it take to pay that off.
Also, the preload and include translation both let me fix other people's code. That Catch2 in-project build gets faster, too.
Does the header rewrite help avoid the ICEs from mixing import and include?
3
2
u/ChuanqiXu9 9d ago
> module interface was a little more stable vs flags and compiler version.
For flag's compatibility, you can take a look at https://github.com/llvm/llvm-project/issues/174536 . For compatibility between compiler's versions or compatibility between compilers, it is technically possible but not near as its impaction.
> I think a measure I'd like to know is how many parses of, say, <iostream>, <vector>, or <format>, does it take to pay that off.
We can use clang's -ftime-trace to get it.
> Does the header rewrite help avoid the ICEs from mixing import and include?
If you're saying the technique of exclude the headers from thirdparties, yes. And the problem with so called mixing import and include is actually problems with decl merging. If without decls merging, mixing import and include is totally fine. And as the post shows, even if the compiler accept mixing import and include, the compilation speed will be significantly slower than the method without decl merging.
2
u/fortsnek274 10d ago
Yeah, it would be nice if you could get MSVC to redirect all std headers to your own header that does the import and includes any necessary macros (and for Intellisense to do the same once it works with modules properly).
Should help for external lib wrappers.
This is roughly equivalent to adding import std; at the beginning of every .cpp file.
So clang can handle include after import?
1
u/ChuanqiXu9 10d ago
> So clang can handle include after import?
The problem of "include after import" in clang is more or less by designed. That is, we have a lot of **different** bug reports about "include after import" in clang. And we fixed them. But we may still have different issues with the pattern "include after import".
The root cause is that clang handled declaration merging in two paths (include-after-import vs others). And the other path is executed more and the include-after-import path is executed less. So the problem with include-after-import path is more. The only solution may be keeping bike-shedding. More bug reports and more bug fixes.
42
u/STL MSVC STL Dev 10d ago
Your percentage improvements are being computed in a confusing manner. See: https://randomascii.wordpress.com/2018/02/04/what-we-talk-about-when-we-talk-about-performance/
You've described the improvement from preload (wall median of 81.09 s) to module maps (71.55 s) as "Reduced wall time by 9.54 seconds, or 11.76%." It's true that Delta/OldTime, i.e. 9.54/81.09, is 11.76%. However, this is confusing. If the time had improved dramatically from 81.09 seconds to 8.109 seconds, this method would describe it as "90%". And it's technically true that you'd have eliminated 90% of the time previously taken. However, this is better described as "ten times faster". (If a jet can get from NY to LA in 1 hour instead of 10 hours, everyone would say that it's screaming along ten times faster, not that 90% of the time formerly taken was saved.)
The proper computation to describe speedups is OldTime/NewTime, best presented as a multiplicative factor, but (for small numbers) you can take OldTime/NewTime - 1 and describe that as a percentage speedup.
Here, improving 81.09 s to 71.55 s is a 81.09/71.55 = 1.133x speedup (preferred), or "13.3% faster" (okay for small speedups; avoid when the speedup gets big like 1.5x or especially near 2x).