'Improving Rust binary build times

I’m just starting a Rust project and already it takes ~7.6s to build what I’d consider a simple binary.

I’m using async/await a lot and commenting out some awaits, like the await on my hyper server, can improve build performance by about 4s. But I’m not sure if that’s because building async/await is slow or by removing that await the Rust compiler no longer needs to build my HTTP response handling code.

// Removing the equivalent of this line (from https://hyper.rs) in
// my codebase improves build times by ~4s.
if let Err(e) = server.await {
    eprintln!("server error: {}", e);
}

I’m not using Cargo which means I’m manually generating rustc commands. Here’s part of a command I’m using for one of these binaries:

rustc admin/dev/server/main.rs --edition=2018 --crate-name=dev_server --crate-type=bin --target=x86_64-apple-darwin --codegen=opt-level=0 --codegen=debuginfo=2 --cap-lints=allow --emit=link --color=always ...

I’ve also abstracted my code into smaller crates. I was hoping that would mean Rust could skip recompilation of smaller crates and third-party dependencies (like hyper), but my guess is that binary codegen is what’s taking all the time?

What are techniques I can use for profiling my Rust build and techniques I can use for improving it? Is there anyway I can reuse compilation for dependencies which haven’t changed when rebuilding the binary? In development could I use dynamic linking for my dependencies instead of static linking?



Solution 1:[1]

  1. Use cargo build: it implements an incremental build, so it doesn't build dependencies every time, and only once. The first build is long, and all subsequent builds are fast. You need to use cargo init before that.
  2. Use cargo check to quickly check and fix compilation errors. cargo check runs faster than cargo build because it doesn't do the final compilation step.
  3. Attribute macros (like #[derive(Serialize, Deserialize, Debug)]) consumes a pretty decent amount of time usually, so pay attention.
  4. Seems like there is an only manual way to identify a bottleneck of your build time consumption: remove some dependencies and look how the build time differs.
  5. There is no way to specify dynamic linking just for development.

Solution 2:[2]

Rust 1.60 allows you to run cargo build --timings which helps you identify slow components in the build. As the documentation states:

  • Look for slow dependencies.
    • Check if they have features that you may wish to consider disabling.
    • Consider trying to remove the dependency completely.
  • Look for a crate being built multiple times with different versions.
  • Try to remove the older versions from the dependency graph.
  • Split large crates into smaller pieces.
  • If there are a large number of crates bottlenecked on a single crate, focus your attention on improving that one crate to improve parallelism.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 pythonic833