Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [Continuous Integration](guide/continuous-integration.md)
* [Publishing on crates.io](reference/publishing.md)
* [Cargo Home](guide/cargo-home.md)
* [Optimizing Build Performance](guide/build-performance.md)

* [Cargo Reference](reference/index.md)
* [The Manifest Format](reference/manifest.md)
Expand Down
70 changes: 70 additions & 0 deletions src/doc/src/guide/build-performance.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have some "tips" at https://doc.rust-lang.org/nightly/cargo/reference/timings.html, should we switch that to a link to this page?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe fold that page into this one and setup a redirect

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to include a "how to profile my builds" in this page, which could link to the timings page as one of the points. And the timings page could then cross-link here for "how to optimize build perf.".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was considering bringing up dividing this into two sections

  • Root causing build times (--timings, compiler passes, macro lines, cargo llvm-lines)
  • Optimizing builds

I was just split on that vs framing those in terms of the current organization. For example, we could have a section on reducing the impact of generics and talk through using cargo llvm-lines to find large, repeated generic functions and discuss how to improve that.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Optimizing Build Performance

Cargo configuration options and source code organization patterns can help improve build performance, by prioritizing it over other aspects which may not be as important for your circumstances.

Same as when optimizing runtime performance, be sure to measure these changes against the workflows you actually care about, as we provide general guidelines and your circumstances may be different, it is possible that some of these approaches might actually make build performance worse for your use-case.

Example workflows to consider include:
- Compiler feedback as you develop (`cargo check` after making a code change)
- Test feedback as you develop (`cargo test` after making a code change)
- CI builds

## Cargo and Compiler Configuration

Cargo uses configuration defaults that try to balance several aspects, including debuggability, runtime performance, build performance, binary size and others. This section describes several approaches for changing these defaults that should be designed to maximize build performance.

You can set the described options either in the [`Cargo.toml` manifest](../reference/profiles.md), which will make them available for all developers who work on the given crate/project, or in the [`config.toml` configuration file](../reference/config.md), where you can apply them only for you or even globally for all your local projects.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading:

  • ./.cargo/config.toml can be included in a projects version control, and therefore used to set configs for all contributors. Its not inherently only for local/personal changes.
  • Not all config options are allowed in both Cargo.toml and .cargo/config.toml. This is quite an important distinction: As someone active in the Bevy community, where compile time optimizations have been recommended for a long time, I've repeatedly had to explain to people that these are different files. People often skipped reading the part of Bevys setup guide which explains the distinction and went straight to copying things, which made their builds fail. Even if every option mentioned on this page can be applied to both, I still consider it important to ensure a section like this doesn't lead to confusion down the line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your second point is also raised at #15924 (comment). I figured we could wait and evolve as this continues.

As for the first, that is true, but since all we are talking about is profile so far, there is no point in putting that in a committed .cargo/config.toml

See also #15924 (comment)


### Reduce amount of generated debug information

Recommendation: Add to your `Cargo.toml` or `.cargo/config.toml`:

```toml
[profile.dev]
debug = "line-tables-only"

[profile.dev.package."*"]
debug = false

[profile.debugging]
inherits = "dev"
debug = true
```

This will:
- Change the [`dev` profile](../reference/profiles.md#dev) (default for development commands) to:
- Limit [debug information](../reference/profiles.md#debug) for workspace members to what is needed for useful panic backtraces
- Avoid generating any debug information for dependencies
- Provide an opt-in for when debugging via [`--profile debugging`](../reference/profiles.md#custom-profiles)

Trade-offs:
- ✅ Faster build times
- ✅ Faster link times
- ✅ Smaller disk usage of the `target` directory
- ❌ Requires a full rebuild to have a high-quality debugger experience

### Use an alternative codegen backend

Recommendation:

- Install the Cranelift codegen backend rustup component
```console
$ rustup component add rustc-codegen-cranelift-preview --toolchain nightly
```
- Add to your `Cargo.toml` or `.cargo/config.toml`:
```toml
[profile.dev]
codegen-backend = "cranelift"
```
- Run Cargo with `-Z codegen-backend` or enable the [`codegen-backend`](../reference/unstable.md#codegen-backend) feature in `.cargo/config.toml`.
- This is required because this is currently an unstable feature.

This will change the [`dev` profile](../reference/profiles.md#dev) to use the [Cranelift codegen backend](https://github.com/rust-lang/rustc_codegen_cranelift) for generating machine code, instead of the default LLVM backend. The Cranelift backend should generate code faster than LLVM, which should result in improved build performance.

Trade-offs:
- ✅ Faster code generation (`cargo build`)
- ❌ **Requires using nightly Rust and an unstable Cargo feature**
- ❌ Worse runtime performance of the generated code
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth mentioning in some way that you can mix codegen backends, by using llvm for dependencies which are often more performance critical and cranelift only for your own crate.

Example from bevy subsecond plugin recommendations

[profile.dev]
codegen-backend = "cranelift"
debug = false

# Consider compiling deps with cranelift if you want cold-compilation to be faster
[profile.dev.package."*"]
codegen-backend = "llvm"

Another facet of runtime performance: In my experience, cranelift is only slower by a very negligible amount with opt-level=3 vs opt-level=1, which also helps alleviate runtime performance issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like we do for debug, should we just switch the example to get good performance with fast incremental builds, at the cost of full builds?

- Speeds up build part of `cargo test`, but might increase its test execution part
- ❌ Only available for [certain targets](https://github.com/rust-lang/rustc_codegen_cranelift?tab=readme-ov-file#platform-support)
- ❌ Might not support all Rust features (e.g. unwinding)
1 change: 1 addition & 0 deletions src/doc/src/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ develop Rust packages.
* [Continuous Integration](continuous-integration.md)
* [Publishing on crates.io](../reference/publishing.md)
* [Cargo Home](cargo-home.md)
* [Optimizing Build Performance](build-performance.md)
Loading