-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Mmap the incremental data instead of reading it. #83214
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
@bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
⌛ Trying commit b199292a80eee54cbdfe86579363fc8dd159abf0 with merge ae8e99fab35dd8ad92e5e9fcf0f0a16437ce106a... |
This comment has been minimized.
This comment has been minimized.
@bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
⌛ Trying commit 7996f05282fa03d5a1c055c0a0314cf82d7cb0a7 with merge 50118f3b1ac7884989bbef838e63e6f348478a59... |
☀️ Try build successful - checks-actions |
Queued 50118f3b1ac7884989bbef838e63e6f348478a59 with parent 1d6754d, future comparison URL. |
Finished benchmarking try commit (50118f3b1ac7884989bbef838e63e6f348478a59): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
Instruction count regressions up to 0.4%. max-rss wins up to 40% on ctfe-stress and up to 15% excluding ctfe-stress. task-clock improvements up to 35% on ctfe-stress and up to 3.6% excluding ctfe-stress with a few regressions up to 2.8%, which is within noise for task-clock. |
This looks good to me! We are already using memory mapped files for crate metadata. One question: why use |
The file should not be written to, but |
Good to know! I think in that case we should switch the entire codebase.
I wonder how to interpret this. I suspect that neither I think the current implementation of incr. comp. makes sure that no |
This comment has been minimized.
This comment has been minimized.
Filed #83236
rustc is not supposed to modify the incremental cache for another instance. This can only happen if the uses starts several rustc/cargo instances at the same moment on the same crate. During one given session, the dep-graph and work product index are deserialized and the memory map is dropped. The only tricky case is the query result cache, which is kept as-is for the entire compilation. As the memory map needs to be dropped before removing the backing file, the cache promotions are moved to rustc_incremental::persist::save::save_dep_graph before dropping the memmap. The current state passes tests in Linux. I don't have a Windows box to test on. |
rustc actually should be handle to synchronize even these cases via file locks: rust/compiler/rustc_incremental/src/persist/fs.rs Lines 496 to 518 in 2aafe45
I wonder if we can encode a proper protocol at the type level here: The memmap gets wrapped in a type with a Drop implementation. By default the drop implementation does nothing, but if the compiler decides that there's a proper replacement file, it will (1) drop the memmap and (2) replace the existing file with the replacement. This way we can write all new versions of a given file to a temporary file and then let the Drop impl take care of swapping things out. That would make it less likely that someone write to the old file while the memmap is still live. I'm not sure how compatible that would be the current setup. In general I think it would be great if we made sure that it's OK to keep an open memmap to the previous versions of all cache files. That would open up the possibility to encode the dep-graph in a way that does not need any up-front decoding at all and still be lazy about actually loading data from the disk. |
OK, let's give it a try. @bors r+ rollup=never |
📌 Commit bcefd48 has been approved by |
⌛ Testing commit bcefd48 with merge 544326c21b625fcf159686fe790f1672fba194e9... |
Note that we're at the very end of a cycle right now. The beta cutoff is in just a few days. So this change is going almost directly into beta. |
@bors r- |
☀️ Try build successful - checks-actions |
Beta has branched. |
📌 Commit bcefd48 has been approved by |
☀️ Test successful - checks-actions |
Finished benchmarking commit (11bbb52): comparison url. Summary: This benchmark run did not return any relevant changes. If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. @rustbot label: -perf-regression |
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), | ||
Err(err) => return Err(err), | ||
}; | ||
// SAFETY: This process must not modify nor remove the backing file while the memory map lives. |
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.
This makes it sound like it is okay when other processes modify or remove the file. Shouldn't the comment be more like
// SAFETY: No process must modify or remove the backing file while the memory map lives.
// We ensure this to be the case for rustc itself. There is no way to prevent another
// process from modifying this file, so UB can arise if they do.
Instead of reading the full incremental state using
fs::read_file
, we memmap it using a private read-only file-backed map.This allows the system to reclaim any memory we are not using, while ensuring we are not polluted by
outside modifications to the file.
Suggested in #83036 (comment) by @bjorn3