Skip to content

Commit db5a2b9

Browse files
committed
Auto merge of rust-lang#2315 - saethlin:shrink-item, r=saethlin
Optimizing Stacked Borrows (part 2): Shrink Item This moves protectors out of `Item`, storing them both in a global `HashSet` which contains all currently-protected tags as well as a `Vec<SbTag>` on each `Frame` so that when we return from a function we know which tags to remove from the protected set. This also bit-packs the 64-bit tag and the 2-bit permission together when they are stored in memory. This means we theoretically run out of tags sooner, but I doubt that limit will ever be hit. Together these optimizations reduce the memory footprint of Miri when executing programs which stress Stacked Borrows by ~66%. For example, running a test with isolation off which only panics currently peaks at ~19 GB, with this PR it peaks at ~6.2 GB. To-do - [x] Enforce the 62-bit limit - [x] Decide if there is a better order to pack the tag and permission in - [x] Wait for `UnsafeCell` to become infectious, or express offsets + tags in the global protector set Benchmarks before: ``` Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/backtraces/Cargo.toml Time (mean ± σ): 8.948 s ± 0.253 s [User: 8.752 s, System: 0.158 s] Range (min … max): 8.619 s … 9.279 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/mse/Cargo.toml Time (mean ± σ): 2.129 s ± 0.037 s [User: 1.849 s, System: 0.248 s] Range (min … max): 2.086 s … 2.176 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/serde1/Cargo.toml Time (mean ± σ): 3.334 s ± 0.017 s [User: 3.211 s, System: 0.103 s] Range (min … max): 3.315 s … 3.352 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/serde2/Cargo.toml Time (mean ± σ): 3.316 s ± 0.038 s [User: 3.207 s, System: 0.095 s] Range (min … max): 3.282 s … 3.375 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/unicode/Cargo.toml Time (mean ± σ): 6.391 s ± 0.323 s [User: 5.928 s, System: 0.412 s] Range (min … max): 6.090 s … 6.917 s 5 runs ``` After: ``` Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/backtraces/Cargo.toml Time (mean ± σ): 6.955 s ± 0.051 s [User: 6.807 s, System: 0.132 s] Range (min … max): 6.900 s … 7.038 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/mse/Cargo.toml Time (mean ± σ): 1.784 s ± 0.012 s [User: 1.627 s, System: 0.156 s] Range (min … max): 1.772 s … 1.797 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/serde1/Cargo.toml Time (mean ± σ): 2.505 s ± 0.095 s [User: 2.311 s, System: 0.096 s] Range (min … max): 2.405 s … 2.603 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/serde2/Cargo.toml Time (mean ± σ): 2.449 s ± 0.031 s [User: 2.306 s, System: 0.100 s] Range (min … max): 2.395 s … 2.467 s 5 runs Benchmark 1: cargo +miri miri run --manifest-path bench-cargo-miri/unicode/Cargo.toml Time (mean ± σ): 3.667 s ± 0.110 s [User: 3.498 s, System: 0.140 s] Range (min … max): 3.564 s … 3.814 s 5 runs ``` The decrease in system time is probably due to spending less time in the page fault handler.
2 parents f223a5f + 4eff60a commit db5a2b9

20 files changed

+317
-153
lines changed

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap;
9090
pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
9191
pub use crate::range_map::RangeMap;
9292
pub use crate::stacked_borrows::{
93-
stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag,
94-
SbTagExtra, Stacks,
93+
CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack,
94+
Stacks,
9595
};
9696
pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId};
9797
pub use crate::thread::{

src/machine.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::borrow::Cow;
55
use std::cell::RefCell;
66
use std::collections::HashSet;
77
use std::fmt;
8-
use std::num::NonZeroU64;
98
use std::time::Instant;
109

1110
use rand::rngs::StdRng;
@@ -43,7 +42,7 @@ pub const NUM_CPUS: u64 = 1;
4342
/// Extra data stored with each stack frame
4443
pub struct FrameData<'tcx> {
4544
/// Extra data for Stacked Borrows.
46-
pub call_id: stacked_borrows::CallId,
45+
pub stacked_borrows: Option<stacked_borrows::FrameExtra>,
4746

4847
/// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn`
4948
/// called by `try`). When this frame is popped during unwinding a panic,
@@ -59,9 +58,9 @@ pub struct FrameData<'tcx> {
5958
impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
6059
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6160
// Omitting `timing`, it does not support `Debug`.
62-
let FrameData { call_id, catch_unwind, timing: _ } = self;
61+
let FrameData { stacked_borrows, catch_unwind, timing: _ } = self;
6362
f.debug_struct("FrameData")
64-
.field("call_id", call_id)
63+
.field("stacked_borrows", stacked_borrows)
6564
.field("catch_unwind", catch_unwind)
6665
.finish()
6766
}
@@ -788,6 +787,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
788787
range,
789788
machine.stacked_borrows.as_ref().unwrap(),
790789
machine.current_span(),
790+
&machine.threads,
791791
)?;
792792
}
793793
if let Some(weak_memory) = &alloc_extra.weak_memory {
@@ -819,6 +819,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
819819
range,
820820
machine.stacked_borrows.as_ref().unwrap(),
821821
machine.current_span(),
822+
&machine.threads,
822823
)?;
823824
}
824825
if let Some(weak_memory) = &alloc_extra.weak_memory {
@@ -852,6 +853,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
852853
tag,
853854
range,
854855
machine.stacked_borrows.as_ref().unwrap(),
856+
&machine.threads,
855857
)
856858
} else {
857859
Ok(())
@@ -888,11 +890,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
888890
};
889891

890892
let stacked_borrows = ecx.machine.stacked_borrows.as_ref();
891-
let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| {
892-
stacked_borrows.borrow_mut().new_call()
893-
});
894893

895-
let extra = FrameData { call_id, catch_unwind: None, timing };
894+
let extra = FrameData {
895+
stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame()),
896+
catch_unwind: None,
897+
timing,
898+
};
896899
Ok(frame.with_extra(extra))
897900
}
898901

@@ -936,7 +939,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
936939
) -> InterpResult<'tcx, StackPopJump> {
937940
let timing = frame.extra.timing.take();
938941
if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
939-
stacked_borrows.borrow_mut().end_call(frame.extra.call_id);
942+
stacked_borrows.borrow_mut().end_call(&frame.extra);
940943
}
941944
let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
942945
if let Some(profiler) = ecx.machine.profiler.as_ref() {

0 commit comments

Comments
 (0)