Skip to content

Commit f3b479d

Browse files
committed
Explain cache behavior a bit better, clean up diff
1 parent 7cdbf98 commit f3b479d

File tree

4 files changed

+21
-16
lines changed

4 files changed

+21
-16
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ harness = false
5353

5454
[features]
5555
default = ["stack-cache"]
56+
# Will be enabled on CI via `--all-features`.
5657
expensive-debug-assertions = []
5758
stack-cache = []

src/lib.rs

Lines changed: 2 additions & 2 deletions
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, PtrId,
94-
SbTag, SbTagExtra, Stacks,
93+
stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag,
94+
SbTagExtra, Stacks,
9595
};
9696
pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId};
9797
pub use crate::thread::{

src/stacked_borrows.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use diagnostics::{AllocHistory, TagHistory};
2626
pub mod stack;
2727
use stack::Stack;
2828

29-
pub type PtrId = NonZeroU64;
3029
pub type CallId = NonZeroU64;
3130

3231
// Even reading memory can have effects on the stack, so we need a `RefCell` here.
@@ -479,7 +478,7 @@ impl<'tcx> Stack {
479478
)
480479
})?;
481480

482-
// Step 2: Remove all items. Also checks for protectors.
481+
// Step 2: Consider all items removed. This checks for protectors.
483482
for idx in (0..self.len()).rev() {
484483
let item = self.get(idx).unwrap();
485484
Stack::item_popped(&item, None, global, alloc_history)?;
@@ -579,8 +578,8 @@ impl<'tcx> Stacks {
579578
/// Creates new stack with initial tag.
580579
fn new(size: Size, perm: Permission, tag: SbTag) -> Self {
581580
let item = Item { perm, tag, protector: None };
582-
583581
let stack = Stack::new(item);
582+
584583
Stacks {
585584
stacks: RangeMap::new(size, stack),
586585
history: AllocHistory::new(),
@@ -826,14 +825,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
826825
// We have to use shared references to alloc/memory_extra here since
827826
// `visit_freeze_sensitive` needs to access the global state.
828827
let extra = this.get_alloc_extra(alloc_id)?;
829-
830828
let mut stacked_borrows = extra
831829
.stacked_borrows
832830
.as_ref()
833831
.expect("we should have Stacked Borrows data")
834832
.borrow_mut();
835-
let mut current_span = this.machine.current_span();
836-
837833
this.visit_freeze_sensitive(place, size, |mut range, frozen| {
838834
// Adjust range.
839835
range.start += base_offset;
@@ -858,7 +854,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
858854
item,
859855
(alloc_id, range, offset),
860856
&mut global,
861-
&mut current_span,
857+
current_span,
862858
history,
863859
exposed_tags,
864860
)

src/stacked_borrows/stack.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ pub struct Stack {
2727
/// we never have the unknown-to-known boundary in an SRW group.
2828
unknown_bottom: Option<SbTag>,
2929

30-
/// A small LRU cache of searches of the borrow stack. This only caches accesses of `Tagged`,
31-
/// because those are unique in the stack.
30+
/// A small LRU cache of searches of the borrow stack.
3231
#[cfg(feature = "stack-cache")]
3332
cache: StackCache,
3433
/// On a read, we need to disable all `Unique` above the granting item. We can avoid most of
@@ -42,6 +41,11 @@ pub struct Stack {
4241
/// probably-cold random access into the borrow stack to figure out what `Permission` an
4342
/// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but
4443
/// most lookups into the cache are immediately followed by access of the full borrow stack anyway.
44+
///
45+
/// It may seem like maintaining this cache is a waste for small stacks, but
46+
/// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*,
47+
/// probably because runtime is dominated by large stacks.
48+
/// arrays is super fast
4549
#[cfg(feature = "stack-cache")]
4650
#[derive(Clone, Debug)]
4751
struct StackCache {
@@ -81,7 +85,9 @@ impl<'tcx> Stack {
8185
/// - There are no Unique tags outside of first_unique..last_unique
8286
#[cfg(feature = "expensive-debug-assertions")]
8387
fn verify_cache_consistency(&self) {
84-
if self.borrows.len() > CACHE_LEN {
88+
// Only a full cache needs to be valid. Also see the comments in find_granting_cache
89+
// and set_unknown_bottom.
90+
if self.borrows.len() >= CACHE_LEN {
8591
for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) {
8692
assert_eq!(self.borrows[*stack_idx].tag, *tag);
8793
}
@@ -154,7 +160,7 @@ impl<'tcx> Stack {
154160
}
155161

156162
// If we didn't find the tag in the cache, fall back to a linear search of the
157-
// whole stack, and add the tag to the stack.
163+
// whole stack, and add the tag to the cache.
158164
for (stack_idx, item) in self.borrows.iter().enumerate().rev() {
159165
if tag == item.tag && item.perm.grants(access) {
160166
#[cfg(feature = "stack-cache")]
@@ -185,8 +191,11 @@ impl<'tcx> Stack {
185191
// If we found the tag, look up its position in the stack to see if it grants
186192
// the required permission
187193
if self.borrows[stack_idx].perm.grants(access) {
188-
// If it does, and it's not already in the most-recently-used position, move it there.
189-
// Except if the tag is in position 1, this is equivalent to just a swap, so do that.
194+
// If it does, and it's not already in the most-recently-used position, re-insert it at
195+
// the most-recently-used position. This technically reduces the efficiency of the
196+
// cache by duplicating elements, but current benchmarks do not seem to benefit from
197+
// avoiding this duplication.
198+
// But if the tag is in position 1, avoiding the duplicating add is trivial.
190199
if cache_idx == 1 {
191200
self.cache.tags.swap(0, 1);
192201
self.cache.idx.swap(0, 1);
@@ -287,7 +296,6 @@ impl<'tcx> Stack {
287296
let unique_range = 0..self.len();
288297

289298
if disable_start <= unique_range.end {
290-
// add 1 so we don't disable the granting item
291299
let lower = unique_range.start.max(disable_start);
292300
let upper = (unique_range.end + 1).min(self.borrows.len());
293301
for item in &mut self.borrows[lower..upper] {

0 commit comments

Comments
 (0)