-
Notifications
You must be signed in to change notification settings - Fork 442
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
process_wrapper: add support for terminating rustc after it emits rmeta. #1207
Conversation
d2423a5
to
f824879
Compare
1d273f2
to
1225f0b
Compare
1ffd558
to
531eeb7
Compare
util/process_wrapper/rustc.rs
Outdated
let parsed: JsonValue = line | ||
.parse() | ||
.expect("process wrapper error: expected json messages in pipeline mode"); | ||
if let Some(emit) = get_key(parsed.clone(), "emit") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have to clone? Seems we can move parsed
.
Nit/discussion - from get_key
I'd expect that we're getting a reference to a key while somebody else keeps ownership of the map. What we are actually doing is consuming the map and returning the value. Sometimes in Rust APIs these "conversion" methods are expressed as to_<foo>()
. So maybe to_key
is more intention revealing? Maybe take_key
/collect_key
are better? WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were two places where parsed might have been moved. Modified get_key so it takes a reference to the json object and instead clones the string value out of it. WDYT?
0343ba7
to
d135600
Compare
@UebelAndre do you also want to take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mostly have nits but could you also explain "pipelining" to me? What's the workflow that this unblocks?
@UebelAndre thanks for review :)
Sure :) Pipelining (in Cargo terms) allows Cargo to unblock a lib -> lib dependency by asking the compiler to emit a metadata file during compilation. When rustc is asked to provide a metadata file, it will produce two files for any given library a .rmeta (the metadata) which is produced quickly and a .rlib (the full object). As soon as Cargo sees the rmeta file, it unblocks all the library targets that depend on that, increasing parallelism. Bazel is (currently) unable to unblock dependencies mid-action so we need two different invocations of the compiler. The first invocation will be killed as soon as the metadata file is produced while the second will continue to completion. The idea is that for rlib -> rlib dependencies we will only run the lightweight metadata invocation, then unblock the dependencies, then compile the full rlib at link time (or whatever other action depends on the full file). You can also read the original rationale for introducing this in Cargo at https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199. I hope this answers your question. |
5ff23fa
to
d30adb5
Compare
Ignorant question: if pipelining requires two runs of cargo, instead of building up a way to terminate rustc, could Related, it seems like having that as always being the first step would cause the build to fail fast, probably solving #428, more-or-less. |
Sadly no. As I have found out while working on the bazel side of this (which is still WIP), the CLI invocations of the two compiler instances need to be basically identical for this to work. Changing any of the flags (including stuff unrelated to codegen, like --error-format) causes rustc to not accept the generated .rmeta file once we get to the linking stage where we need the .rlib.
This is still going to be behind a flag and disabled by default at least for the time being. |
@UebelAndre are you happy with this change now? |
Sad day. Has that been flagged to the rust team? That seems like something rustc should be able to support. |
Well, not really. What rustc does is to emit metadata and object in the same invocation of the compiler. The double invocation is just because of a limitation in bazel (which can't emit output out of a rule that's still executing). |
In addition to command line flags changing the content of the rlib as @gigaroby explained, there's also a second issue/feature :) So regarding #428, we could use the metadata files from pipelining for an equivalent of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay. I have one more question and my final set of nits. Generally looks good though, great work and thanks!
79cd16b
to
3f6669c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting up with all my boring requests! Looks good to me 😄
BTW, I've successfully implemented Rust pipelining in Buck rules. The key is to not use |
This is a key component of supporting pipelining in rules_rust. The bazel rules will (in a follow-up PR) configure rustc to run either to completion for rules whose dependencies require the full rlib files or until they emit the rmeta files if dependencies only require that. This is safe to commit as there are no changes to user-visible behavior until the new flags are used.
This is a key component of supporting pipelining in rules_rust. The
bazel rules will (in a follow-up PR) configure rustc to run either to
completion for rules whose dependencies require the full rlib files or
until they emit the rmeta files if dependencies only require that.
This is safe to commit as there are no changes to user-visible behavior
until the new flags are used.