cargo
cargo copied to clipboard
Add more optimizations to the release build profile.
Problem
The release profile is used when wanting to build an optimized binary. Thus, I think it would be logical to optimize it to the fullest, sometimes at the cost of a greater build time, but I think it is a good compromise for many people, including me.
Proposed Solution
More optimizations flags should be added to the release build profile, notably lto=true and codegen-units=1, as well as optimizing all the packages with opt-level=3. This greatly enhances runtime performance, although yes, at the cost of a bigger binary size and longer build time.
Notes
I have tested what I am proposing, with the following added in my cargo.toml:
[profile.release]
lto = true
codegen-units = 1
[profile.release.package."*"]
opt-level = 3
This improved the output binary's runtime performance by orders of magnitude, thus this issue.
I suspect lto = "thin"
is a sufficient compromise that it'd be worth being the default compared to "fat"
/ true
.
Compile times are a sensitive area and increasing them in any way is always a worry.
I ran a test on my machine (M1 Max chip 32GB ram) against a private project that has 395 dependencies (many are very heavy) and the jump in compile time is large for "fat" LTO. The results also appear to agree that lto = "thin"
could work.
One thing to consider is if changing the release
profile could be breaking in some unintended way. Crater might need to be run to see if it changes anything. Either way, it might be a good idea to add a new profile that contains these changes, instead of changing release
.
Test Results
profile |
time |
---|---|
"fat" LTO codegen=1 | 2m 30s |
"fat" | 2m 27s |
"thin" LTO codegen=1 | 1m 44s |
"thin" | 1m 08s |
No LTO codegen=1 | 1m 39s |
release |
1m 09s |
"fat" codegen=1
[profile.production]
inherits = "release"
lto = true
codegen-units = 1
opt-level = 3
"fat"
[profile.production]
inherits = "release"
lto = true
opt-level = 3
"thin" codegen=1
[profile.production]
inherits = "release"
lto = "thin"
codegen-units = 1
opt-level = 3
"thin"
[profile.production]
inherits = "release"
lto = "thin"
opt-level = 3
No LTO codegen=1
[profile.production]
inherits = "release"
codegen-units = 1
opt-level = 3
I completely agree with you, lto is, whatever the value, a great performance increase
Either way, it might be a good idea to add a new profile that contains these changes, instead of changing
release
.
That's what I thought at first, adding a "production" profile that would optimize the binary to the maximum and which would use the flags I mentioned in the issue.
adding a "production" profile that would optimize the binary to the maximum
Just want to make it clear. Are we proposing a new built-in profile here?
One thing to consider is if changing the release profile could be breaking in some unintended way.
Currently ThinLTO creates issues with at least one common target while linking with lld
; a potential fix was opened recently https://github.com/rust-lang/rust/pull/103353
Just want to make it clear. Are we proposing a new built-in profile here?
It depends on what the majority of devs think. It could be a new built-in profile or it could simply be en enhancement to the current release build profile.
I don't think the release
profile should be made to optimize harder, because Rust's build times are already slow, and a full LTO can be extremely slow and memory-hungry (I have some projects that I can't build with fat LTO at all because they run out of memory).
It may be difficult to get everyone agree on what is desired for some "dist"/"production" profile. For example, I care about small executable sizes more than backtraces, so my preferred dist profiles include panic=abort
, strip
, and even panic_immediate_abort
and -Zlocation-detail=none
where possible.
Agreeing on a dist profile would be near impossible, yeah. I think that a better way would be to add some guidance/templates/profile wizard to cargo, which would help users build the desired profile interactively, with some predefined presets.
Each option for a build configuration has pros and cons, depending on the needs of the developer. But I do need some predefined templates or configurations to make the build accomplish certain goals, such as faster builds, smaller binaries. It would be nice to have written guidance from an official. It is also acceptable if there are unofficial plug-ins that implement predefined templates out of the box
Created a Cargo subcommand for configuring Cargo projects (focused on performance aspects of configuration), might be useful to automate the creation of optimized Cargo profiles: https://github.com/Kobzol/cargo-wizard.
I agree that making everyone agree on one new profile is impossible. I think it should then be considered to possibly add multiple new build profiles, each fulfilling a goal, or at least mention new ones in the docs, offering the developers the possibility to modify their 'release' profile to maximize(or minimize) a certain aspect. For example, I think there could be at least two new ones: 'performance' (or 'speed'), and 'size' (or 'binary-size'). The first one would have the modifications pointed out in my first comment, and the second one would modify parameters to minimize the final binary size. This would then allow developers to overwrite certain parameters in those profiles as they please while having a build profile aimed towards a certain aspect, as pointed out here by @kornelski :
my preferred dist profiles include panic=abort, strip, and even panic_immediate_abort and -Zlocation-detail=none where possible.