Conversation
This is a preparation for propagating rmeta artifact notification in the middle of a rustc invocation.
`run_input_output` reads the child's stderr to EOF, so nothing can react to a line before the process exits. This add `run_input_output_observing`, which takes an optional stderr observer, which can support streaming and propogations.
tests are running in parallel so need a separate daemon
THis is needed so that tests can observe rmeta artifact notifications
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2875 +/- ##
==========================================
+ Coverage 76.35% 77.49% +1.14%
==========================================
Files 72 72
Lines 40219 41265 +1046
==========================================
+ Hits 30709 31980 +1271
+ Misses 9510 9285 -225 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| // Daemon already emitted `.rmeta` notification and we forwarded it, | ||
| // so the copy from this local compile must not reach the caller again. | ||
| // | ||
| // XXX: This local compile rewrites artifacts the caller may already be |
There was a problem hiding this comment.
does it really need a 6 lines comment? please make it shorter :)
There was a problem hiding this comment.
No. I just wanted to call out that non-deterministic rustc output may hurt this assumption (but anyway sccache currently doesn't yet prepared for the new parallel frontend/--job-frontend flag)
| /// The client that has forwarded the notification must drop that copy. | ||
| /// | ||
| /// Currently only `.rmeta` notifications are sent (for Cargo pipelining). | ||
| ArtifactNotification(Vec<u8>), |
There was a problem hiding this comment.
could you add it at the end of the enum?
inserting here shifts the bincode tags of all the Storage* variants
There was a problem hiding this comment.
Nice catch. Hmm… I should have listened to LLM. I ignored it because I felt like it was being too paranoid.
| .and_then(|res| async { Ok(Response::CompileFinished(res)) }) | ||
| .boxed(); | ||
| let body = if c.kind() == CompilerKind::Rust { | ||
| // Only rustc emits artifact notifications, |
There was a problem hiding this comment.
start_compile_task already spawns internally, do we need the extra spawn_on here?
There was a problem hiding this comment.
I tried without it and it hung. I guess that was because start_compile_task is itself an async fn, so its internal spawn only runs if itself future is polled. However, the later chain won't poll it until rx closes, which needs the tx end be dropped first.
It is kinda a cycle: tx drop -> rx closes -> chain -> start_compile_task -> tx drop
Hence an extra spawn breaking the cycle.
There might be a way we can use select! or something to avoid this extra task, though for readability I feel like the current one is good enough.
| let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); | ||
| let addr = crate::net::SocketAddr::Net(listener.local_addr().unwrap()); | ||
| let server = thread::spawn(move || { | ||
| let (mut sock, _) = listener.accept().unwrap(); |
There was a problem hiding this comment.
the fake server setup is almost the same as in the previous test, could be dedup, no?
There was a problem hiding this comment.
Dedup'd. (I don't particularly like how it works half the way though)
| "second run was not a hit" | ||
| ); | ||
|
|
||
| for (name, stderr, rmeta_lines) in [("miss", &miss.stderr, 1), ("hit", &hit.stderr, 1)] { |
There was a problem hiding this comment.
rmeta_lines is always 1, do we still need it?
There was a problem hiding this comment.
Nice catch. It was vestige. Removed.
This is currently unused though.
Only local rustc compilations that miss the cache stream: * cache hits have no running compiler * distributed compiles never stream because `.rmeta` is not on local disk yet * other compilers are unchanged
`SCCACHE_CLIENT_SIDE` mode already produces the streamed body, so `compile_direct` now takes the CLI's stderr and writes each `CompileStderr` chunk as well.
ea00651 to
33304cf
Compare
weihanglo
left a comment
There was a problem hiding this comment.
Thanks for the review!
| // Daemon already emitted `.rmeta` notification and we forwarded it, | ||
| // so the copy from this local compile must not reach the caller again. | ||
| // | ||
| // XXX: This local compile rewrites artifacts the caller may already be |
There was a problem hiding this comment.
No. I just wanted to call out that non-deterministic rustc output may hurt this assumption (but anyway sccache currently doesn't yet prepared for the new parallel frontend/--job-frontend flag)
| "second run was not a hit" | ||
| ); | ||
|
|
||
| for (name, stderr, rmeta_lines) in [("miss", &miss.stderr, 1), ("hit", &hit.stderr, 1)] { |
There was a problem hiding this comment.
Nice catch. It was vestige. Removed.
| let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); | ||
| let addr = crate::net::SocketAddr::Net(listener.local_addr().unwrap()); | ||
| let server = thread::spawn(move || { | ||
| let (mut sock, _) = listener.accept().unwrap(); |
There was a problem hiding this comment.
Dedup'd. (I don't particularly like how it works half the way though)
| .and_then(|res| async { Ok(Response::CompileFinished(res)) }) | ||
| .boxed(); | ||
| let body = if c.kind() == CompilerKind::Rust { | ||
| // Only rustc emits artifact notifications, |
There was a problem hiding this comment.
I tried without it and it hung. I guess that was because start_compile_task is itself an async fn, so its internal spawn only runs if itself future is polled. However, the later chain won't poll it until rx closes, which needs the tx end be dropped first.
It is kinda a cycle: tx drop -> rx closes -> chain -> start_compile_task -> tx drop
Hence an extra spawn breaking the cycle.
There might be a way we can use select! or something to avoid this extra task, though for readability I feel like the current one is good enough.
| /// The client that has forwarded the notification must drop that copy. | ||
| /// | ||
| /// Currently only `.rmeta` notifications are sent (for Cargo pipelining). | ||
| ArtifactNotification(Vec<u8>), |
There was a problem hiding this comment.
Nice catch. Hmm… I should have listened to LLM. I ignored it because I felt like it was being too paranoid.
What is this
Fixes #2873
This basically adds a side channel to stream artifact notifications for rmeta, so that caller (cargo) can see
.rmetanotification as early as possible.This is only added to local daemon and client-side mode. Distributed mode is not touched.
This should help quite a bit when there are some cache misses, especially for large Cargo workspaces.
How to review
Reviewing this commit by commit is highly recommended.
I personally don't like the post-filter of rmeta notifcation in
CompilerFinished, though it seems unavoidable.Cargo timing HTML
Here we build rust-lang/cargo@07b8049 on master and this PR.
Before, you see almost no codegen (purple) section:
After, pipelining works and overlaps shows:
🤖 LLM disclosure: This was initially generated by LLM after a series of design discussions, and handcrafted afterwards. I've reviewed every single line of this and is responsible for the code change.