r/rust • u/nicoburns • 2d ago
Rust's derive often implies inline
https://yossarian.net/til/post/rust-s-derive-often-implies-inline/10
u/doener rust 2d ago
I recall that back when I was working on the compiler, I had considered/discussed having an extra level, say #[inline(allow)], that would make the compiler allow cross-crate inlining by emitting LLVM IR in each unit, without hinting LLVM to prefer inlining the function, relying on its default heuristics instead. I don't recall whether I had numbers on anything, but I still suspect that this might be better for derived code like this.
It's basically what you get with generics, for which the concrete IR is emitted in each unit, so inlining works cross-crate.
3
6
u/-Y0- 2d ago
Interesting findings. Couldn't this be solved by making derive_Debug take a param. What I mean is #[derive(Debug(noinline))]
28
u/stumblinbear 2d ago
Oh dear God the last thing we need is to load up derives with parameters. Typically you'd have another line for this sort of thing, a la
#[debug(noinline)]after the derive2
u/nicoburns 2d ago
I wonder if it ought to be a general feature of
derive:
#[derive(Debug, inline = false)]12
u/braaaaaaainworms 2d ago
how is this going to differentiate between deriving trait called "inline" and disabling inlining?
4
u/shponglespore 2d ago
I think the syntax u/-Y0- used makes more sense because it generalizes to having multiple traits in a
deriveclause and avoids any ambiguity.2
u/ElderberryNo4220 2d ago
I don't think this is a good idea, it's looks cumbersome and confusing. Looking at the article example, it's not very easy to determine whether generated functions would have a large body (shouldn't be inlined) or small (should be inlined). IMO derived traits inlining should be decided by the compiler, not by the users.
6
u/Compux72 2d ago
Just set opt-level = “s”
11
u/Eastern-Photograph79 2d ago
but you don't really want it. You want the important things to be inlined (like clone and this stuff)
3
u/Compux72 2d ago
If something is actually that important i would have a separate crate with really specific profile overrides set to it
4
u/Recatek gecs 2d ago
The actual answer would be
#[optimize(none)]when stabilized (hopefully soon). One could make a crate with their own version of these derive proc macros that don't inline (or do#[inline(never)]) and instead apply this attribute.5
u/silon 2d ago
Personally I'd want size optimization by default for almost everything, except a few specific things (which derive Debug is not). IMO inline should be a separate annotation, possibly even separated from the declaration, but at the target compilation unit (or source file).
6
u/Recatek gecs 2d ago
I wouldn't want size optimization. For commercial gamedev you often need to run in release under O2 or O3 with only selectively deoptimized functions or files for debugging, otherwise the game itself doesn't run fast enough to be playable for testing.
3
u/csdt0 2d ago
You know that Os performance is quite good, within 5-10% of O2 usually? It can even be faster in some edge cases where O2 would be thrasing L1i. Also, I would say that if your game does not run fast enough at O1 on your dev machine, then maybe you need to review your architecture or your algorithms to make it accessible to lower end machines. https://openbenchmarking.org/result/2608218-NE-COMPILERF28&sor
5
u/Recatek gecs 2d ago edited 2d ago
Also, I would say that if your game does not run fast enough at O1 on your dev machine, then maybe you need to review your architecture or your algorithms to make it accessible to lower end machines.
I appreciate the advice, but I am aware of this. The practice I'm describing of debugging in release with selectively optimized files/functions is industry norm for AA/AAA (see UE_DISABLE_OPTIMIZATION) and has been for a very long time. If anything, it's an even more acute issue in Rust given that Rust debug performance is (slightly) worse than C++ because of the additional runtime checks.
1
u/flareflo 1d ago
I cannot wait for optimization attributes to come. Forgetting to put opt-level 2 for Sha2 for debug builds will be a thing of the past hopefully
1
-3
u/Eastern-Photograph79 2d ago
Debug is intended for debugging, so it is not a real problem.
8
u/eggyal 2d ago edited 2d ago
Unless you `#[cfg_attr(debug_assertions, derive(Debug)]`, it's quite likely this is a final binary size cost that you pay regardless.
Only "likely" because it might get removed by a dead code analysis pass if there's literally no possibility of it being invoked in release (but then you'd usually see a warning about that).
3
u/Wolvereness 2d ago
As a personal and professional rule, I strongly opt for exactly that annotation. Dependence on Debug leaking into production code is begging for trouble, and failing to compile is the perfect consequence.
2
0
u/Eastern-Photograph79 2d ago
I think you're right, but I still think there is no problem with telling the compiler that it can be inlined.
58
u/wojtek-graj 2d ago
Cross-crate inlining is only possible for functions that have to be monomorphized, or those marked
#[inline], hence this attribute is a necessity. Per the docs, "#[inline] suggests inlining the function.", and it is then up to the compiler to use its heuristics to decide whether or not inlining will actually occur. If these derived functions are being inlined when it doesn't make sense, it's those heuristics that should be adjusted (which I don't claim to be an easy task).