Skip to content

Commit

Permalink
enable on-demand rustc incremental compilation
Browse files Browse the repository at this point in the history
Summary:
Users can now enable incremental compilation by running:
```
buck2 build -c rust.incremental=relative/path/to/target <TARGET>
```
This will generate an `incremental/<BUILD_MODE>/` directory which can be reused between builds. Since `rustc` is quite opinionated about incremental artifact hashing, file naming and placement, we enforce incremental compilation to run locally by skipping RE.

## Benchmarking (quick)

From a few local experiments run builds with and without incremental compilation turned on after making minor code changes, I see *> 80%* reduction in build times when using incremental compilation:

**example #1**: `//common/rust/tools/rust-expand:rust-expand`
```
|---------------------+-------------------+-------------------------|
| Build type          | 1st Build (clean) | 2nd Build (with change) |
|---------------------+-------------------+-------------------------|
| Without incremental | 9.2sec            | 14.2sec                 |
| With incremental    | 15.2sec           | 2.1sec                  |
|---------------------+-------------------+-------------------------|
```

**example #2**: `//common/rust/tools/rustfix2:buck`
```
|---------------------+-------------------+-------------------------|
| Build type          | 1st Build (clean) | 2nd Build (with change) |
|---------------------+-------------------+-------------------------|
| Without incremental | 7.6sec            | 3.4sec                  |
| With incremental    | 9sec              | 0.72sec                 |
|---------------------+-------------------+-------------------------|
```

For both examples above, 1st build gets run & timed like so:
```
for i in {1..5}; do buck2 clean && time buck2 build --show-full-output //common/rust/tools/rustfix2:buck; done
```
and 2nd build gets run & timed like so:
```
cd ~/fbcode
for i in {1..5}; do sed -i 's/println!("some some something 1");/&\n    println!("some some something 2");/' common/rust/tools/rustfix2/src/buck.rs && time buck2 build --show-full-output //common/rust/tools/rustfix2:buck; done
```
adding and removing `-c rust.incremental` to generate results with and without incremental compilation.

Reviewed By: krallin

Differential Revision: D38374692

fbshipit-source-id: 0f7412249da6e3dad2a381f0945e8cc8f9412065
  • Loading branch information
Dimitris Iliopoulos authored and facebook-github-bot committed Aug 16, 2022
1 parent 3b5eb89 commit 41f300d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
6 changes: 6 additions & 0 deletions prelude/rules_impl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ extra_attributes = struct(
},
#rust
rust_binary = {
"incremental_build_mode": attrs.option(attrs.string()),
"incremental_enabled": attrs.bool(default = False),
"resources": attrs.named_set(attrs.one_of(attrs.dep(), attrs.source()), sorted = True, default = []),
"_cxx_toolchain": _cxx_toolchain(),
"_rust_toolchain": _rust_toolchain(),
Expand All @@ -457,6 +459,8 @@ extra_attributes = struct(
# them and it simplifies the implementation of Rust rules since they
# don't have to know whether we're building a rust_binary or a
# rust_library.
"incremental_build_mode": attrs.option(attrs.string()),
"incremental_enabled": attrs.bool(default = False),
"linker_flags": attrs.list(attrs.arg(), default = []),
"preferred_linkage": attrs.enum(Linkage, default = "any"),
"resources": attrs.named_set(attrs.one_of(attrs.dep(), attrs.source()), sorted = True, default = []),
Expand All @@ -465,6 +469,8 @@ extra_attributes = struct(
},
rust_test = {
"framework": attrs.bool(default = True),
"incremental_build_mode": attrs.option(attrs.string()),
"incremental_enabled": attrs.bool(default = False),
"resources": attrs.named_set(attrs.one_of(attrs.dep(), attrs.source()), sorted = True, default = []),
"_cxx_toolchain": _cxx_toolchain(),
"_rust_toolchain": _rust_toolchain(),
Expand Down
22 changes: 18 additions & 4 deletions prelude/rust/build.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -659,8 +659,14 @@ def _rustc_emits(

if emit not in (Emit("expand"), Emit("save-analysis")):
extra_dir = subdir + "/extras/" + output_filename(crate, emit, params)
extra_dir = ctx.actions.declare_output(extra_dir)
emit_args.add("--out-dir", extra_dir.as_output())
extra_out = ctx.actions.declare_output(extra_dir)
emit_args.add("--out-dir", extra_out.as_output())

if ctx.attrs.incremental_enabled:
build_mode = ctx.attrs.incremental_build_mode
incremental_out = ctx.actions.declare_output("{}/extras/incremental/{}".format(subdir, build_mode))
incremental_cmd = cmd_args(incremental_out.as_output(), format = "-Cincremental={}")
emit_args.add(incremental_cmd)

return (outputs, emit_args)

Expand Down Expand Up @@ -712,9 +718,17 @@ def _rustc_invoke(
compile_cmd.add(rustc_cmd)
compile_cmd.hidden(toolchain_info.compiler, compile_ctx.symlinked_srcs)

local_only = is_binary and link_cxx_binary_locally(ctx)
incremental_enabled = ctx.attrs.incremental_enabled
local_only = (is_binary and link_cxx_binary_locally(ctx)) or incremental_enabled
identifier = "{} {} [{}]".format(prefix, short_cmd, diag)
ctx.actions.run(compile_cmd, env = plain_env, local_only = local_only, category = "rustc", identifier = identifier)
ctx.actions.run(
compile_cmd,
env = plain_env,
local_only = local_only,
category = "rustc",
identifier = identifier,
no_outputs_cleanup = incremental_enabled,
)

return ({diag + ".json": json_diag, diag + ".txt": txt_diag}, build_status)

Expand Down

0 comments on commit 41f300d

Please sign in to comment.