Skip to content

Commit 38eecca

Browse files
committedNov 23, 2023
Auto merge of #118073 - saethlin:gc-dead-allocs, r=RalfJung
Miri: GC the dead_alloc_map too dead_alloc_map is the last piece of state in the interpreter I can find that leaks. With this PR, all of the long-term memory growth I can find in Miri with programs that do things like run a big `loop {` or run property tests is attributable to some data structure properties in borrow tracking, and is _extremely_ slow. My only gripe with the commit in this PR is that I don't have a new test for it. I'd like to have a regression test for this, but it would have to be statistical I think because the peak memory of a process that Linux reports is not exactly the same run-to-run. Which means it would have to not be very sensitive to slow leaks (some guesswork suggests for acceptable CI time we would be checking for like 10% memory growth over a minute or two, which is still pretty fast IMO). Unless someone has a better idea for how to detect a regression, I think on balance I'm fine with manually keeping an eye on the memory use situation. r? RalfJung
2 parents fc13ca6 + f5dae8e commit 38eecca

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed
 

‎compiler/rustc_const_eval/src/interpret/memory.rs

+11
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
501501
}
502502
}
503503

504+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
505+
/// This function is used by Miri's provenance GC to remove unreachable entries from the dead_alloc_map.
506+
pub fn remove_unreachable_allocs(&mut self, reachable_allocs: &FxHashSet<AllocId>) {
507+
// Unlike all the other GC helpers where we check if an `AllocId` is found in the interpreter or
508+
// is live, here all the IDs in the map are for dead allocations so we don't
509+
// need to check for liveness.
510+
#[allow(rustc::potential_query_instability)] // Only used from Miri, not queries.
511+
self.memory.dead_alloc_map.retain(|id, _| reachable_allocs.contains(id));
512+
}
513+
}
514+
504515
/// Allocation accessors
505516
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
506517
/// Helper function to obtain a global (tcx) allocation.

‎src/tools/miri/src/provenance_gc.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
195195
}
196196

197197
fn remove_unreachable_allocs(&mut self, allocs: FxHashSet<AllocId>) {
198-
let this = self.eval_context_ref();
198+
let this = self.eval_context_mut();
199199
let allocs = LiveAllocs {
200200
ecx: this,
201201
collected: allocs,
@@ -205,5 +205,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
205205
if let Some(borrow_tracker) = &this.machine.borrow_tracker {
206206
borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs);
207207
}
208+
this.remove_unreachable_allocs(&allocs.collected);
208209
}
209210
}

0 commit comments

Comments
 (0)
Please sign in to comment.