Skip to content

feat: cross language LTO #3162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

ParkMyCar
Copy link
Contributor

If you're using Clang for your C toolchain, it's possible to do cross language optimizations between Rust and C, see Rust's Linker-plugin-based LTO docs for more info.

This PR adds a new @rules_rust//rust/settings:experimental_cross_language_lto (off by default) which when building a Rust binary will set -Clinker-plugin-lto. If LTO is enabled for both Rust and C will then delay optimizations to the linker, resulting in cross language optimizations.

This feature is highly experimental. To have it work correctly you need to be using a Clang toolchain with lld as the linker that is recent enough to understand the bitcode emitted by rustc. There is much more we can do here to make the feature more stable, but this seemed like a good starting point?

@ParkMyCar
Copy link
Contributor Author

Will take a look at the CI failures. FWIW I tested this locally with clang-18 and Rust 1.83 and it indeed works. When LTO is enabled for both Rust and C I see in-lining occurring across the language boundary

args = []

# proc-macros do not benefit from LTO, and cannot be dynamically linked with LTO.
if mode in ["thin", "fat", "off"] and not is_exec_configuration(ctx) and crate_info.type != "proc-macro":
Copy link
Contributor

Choose a reason for hiding this comment

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

did you revert this intentionally?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I was experimenting, but I switched this back to how it was before!

@ParkMyCar ParkMyCar force-pushed the lto/x-lang branch 3 times, most recently from cfdef01 to 307b3c0 Compare January 14, 2025 02:04
ParkMyCar added a commit to MaterializeInc/materialize that referenced this pull request Apr 29, 2025
This PR enables cross language LTO for our release builds, meaning
function calls from external C dependencies like `libdecimal` can
potentially get inlined into Rust code.

The way this works is when building our final binaries, e.g.
`environmentd` and `clusterd`, we specify the `-Clinker-plugin-lto` flag
to `rustc` which has our linker (`lld`) run the LTO passes instead of
`rustc`. At which point all of our Rust and C code has been compiled to
LLVM bitcode so to `lld` is free to optimize across languages.

This only works when building for Linux. Arguments that `rustc` passes
to the linker when targetting macOS don't seem to be supported by
`ld64.lld`? See rust-lang/rust#60059 for some
more investigation.

### Motivation

Faster runtime performance. 

### Tips for reviewer

The commits are broken down as follows:

1. Some Bazel configuration so we can detect when the cross language LTO
is requested _and_ when we're building on a Linux machine.
2. Updates to cargo-gazelle so we specify the right `rustc` flags.
Theoretically something like this could be upstreamed into `rules_rust`
which I started working on in
bazelbuild/rules_rust#3162. But for now updating
cargo-gazelle is a lot easier.
3. Running `bin/bazel gen`

### Checklist

- [ ] This PR has adequate test coverage / QA involvement has been duly
considered. ([trigger-ci for additional test/nightly
runs](https://trigger-ci.dev.materialize.com/))
- [ ] This PR has an associated up-to-date [design
doc](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/README.md),
is a design doc
([template](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/00000000_template.md)),
or is sufficiently small to not require a design.
  <!-- Reference the design in the description. -->
- [ ] If this PR evolves [an existing `$T ⇔ Proto$T`
mapping](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/command-and-response-binary-encoding.md)
(possibly in a backwards-incompatible way), then it is tagged with a
`T-proto` label.
- [ ] If this PR will require changes to cloud orchestration or tests,
there is a companion cloud PR to account for those changes that is
tagged with the release-blocker label
([example](MaterializeInc/cloud#5021)).
<!-- Ask in #team-cloud on Slack if you need help preparing the cloud
PR. -->
- [ ] If this PR includes major [user-facing behavior
changes](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/guide-changes.md#what-changes-require-a-release-note),
I have pinged the relevant PM to schedule a changelog post.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants