Stylistic guide for speeding up compile time

  1. I am reaching a point where rustc auto recompile can take minutes depending on what is modified.

  2. Is there a style guide on what features are fast/slow for compilation, how to organize code into multiple crates for speeding up compile time, … and whatever else other tricks for minimizing compile time?

  3. I am willing to change how the code is organized / rewrite parts of the code to avoid using “expensive” features.

Try to modularize your code and split ypur project into multiple crates. This eay cargo can cache crates that don’t change and improve build times. You can also look into workspaces to make this easier.

  1. I’m currently using a workspace.

  2. It’s currently ~17L LOC spread out over 38 crates, with all crates < 1.5K LOC.

Other suggestions? :slight_smile:

Oh, I’m not sure what to do from there.

One advice which I have seen is to use tools meant to profile executable size (like cargo bloat) to identify suspicious code regions. This is because rustc spends about half of its time generating executable code in a typical project, which means code size is a decent metric for compile-time bloat.

Common culprits of code bloat are constructs that generate code like generics and macros. Common strategies are to extract as much as possible from generic code to common (non-generic) functions and to make broader use of dynamic dispatch (aka dyn Trait) where static dispatch is not truly needed.

1 Like

If your code is modularized and you don’t have a macro-related problem, the recompilation when a file changed shouldn’t take minutes.

How exactly are you doing “auto-recompilation” ? Are you sure there’s no hidden cleaning ?

Okay, minutes is exaggerating a bit. I’m doing continuous rebuilds via:

cargo web start --target=wasm32-unknown-unknown --release --port 8002 --host 0.0.0.0 --auto-reload

What happens is:

  1. I point Chrome at localhost:8002

  2. I modify a file in IntelliJ, hit C-s to save.

  3. The existing cargo web start notices the file change & starts a rebuild.

  4. I stare at the web browser waiting for it to refresh, which seems like an eternity, but is more on the order of tens of seconds.

So I guess complaining about waiting tens of seconds for a rebuild sounds spoiled – but there’s the thing:

  1. when I first started on Rust/wasm32, the cargo rebuilding was nearly instantaneous; and if I create a blank project, it’s also nearly instantaneous

  2. it’s very unfortunate that as the codebase gets larger, the “write code; see change” cycle gets slower and slower

  3. this makes it really annoying to build certain types of GUI applications (imagine using Visual Basic or XCode’s “form builder” – but every op changing the GUI takes 10 seconds)

Release mode takes significantly more time to build than debug, is this necessary for you during development?

Without release, I was running into 7MB wasm files 7MB *.wasm files? , which causes it’s own delay due to wasm parsing – though I haven’t benchmarked the two to see which delay is worse.

Slow disk could be killing compilation time, even incremental which needs to check the cache.

  • Use a fast SSD
  • If you’re on Windows, don’t use C:\ and disable anti-virus for the drive your target/ is on (Windows has synchronous file access hooks that everything hooks up into).
  • Don’t use WSL, network drives, FUSE (including Vagrant, Docker)
3 Likes

I don’t know how cargo web start works – Are the times you’re seeing similar to running cargo build --release? (I’m wondering if it might not be doing incremental rebuilds correctly.) In particular, if you only change your top-level lib.rs the rebuild should be much faster than if you change something in one of your deep, fundamental crates.

Assuming that’s working right, have a look at the shape of your dependency graph (the one between your crates in your workspace). (The cargo graph command can help with this.) Just splitting up your crate may not be enough: your rebuild will be slower if the graph is either too flat, or too tall. By which I mean: if you have factored out a lot of crates, but you have one central crate that depends on all of them directly, that central crate is probably going to be slow to rebuild (because it’s doing a lot). On the other hand, if your graph looks like

your_binary -> crate1 -> crate2 -> crate3 -> crate4

(i.e. a line instead of a tree) it will also tend to be slow to rebuild, because any change to crate3/4 will require rebuilds of everything on top of it.

If you are frequently editing files in a deep leaf crate (like crate4 in the above example), check to see that everything build on top of it actually needs to depend on it. Fixing it so that crate2 no longer depends on crate3, so that the graph is shaped like

your_binary -> crate2
    \--> crate3 -> crate4

will allow more parallel builds and will rebuild less code when you change crate4.

Optimizing the shape of a dependency graph for build performance is more art than science, but I hope that made sense.

5 Likes

I’m on Linux, only using SSD, and everything is local.

Did you try sccache?

If case, just remember to check it out from the master branch, the released 0.28 version still has some rough edges:
cargo install --force --git=https://github.com/mozilla/sccache