Skip to content

Commit 65014d8

Browse files
author
Markus Westerlind
committed
Optimize ModifiedSet for faster snapshot/rollback
Snapshot/rollback is done a lot in certain workloads so optimizing for it makes sense as there is very little additional overhead for the set/drain case (which are called relatively rarely)
1 parent bb70251 commit 65014d8

File tree

2 files changed

+45
-42
lines changed

2 files changed

+45
-42
lines changed

compiler/rustc_data_structures/src/logged_unification_table.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,14 @@ where
7474

7575
self.relations.unify_var_var(a, b)?;
7676

77-
if self.needs_log(a.into()) || self.needs_log(b.into()) {
78-
warn!("Log: {:?} {:?} => {:?}", a, b, I::from(self.relations.find(a)));
79-
if a == self.relations.find(a) {
77+
if a == self.relations.find(a) {
78+
if self.needs_log(b.into()) {
79+
warn!("Log: {:?} {:?} => {:?}", a, b, I::from(self.relations.find(a)));
8080
self.unify_log.unify(a.into(), b.into());
81-
} else {
81+
}
82+
} else {
83+
if self.needs_log(a.into()) {
84+
warn!("Log: {:?} {:?} => {:?}", a, b, I::from(self.relations.find(a)));
8285
self.unify_log.unify(b.into(), a.into());
8386
}
8487
}

compiler/rustc_data_structures/src/modified_set.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ use std::{collections::VecDeque, marker::PhantomData};
22

33
use rustc_index::{bit_set::BitSet, vec::Idx};
44

5+
#[derive(Copy, Clone, Debug)]
6+
enum Undo<T> {
7+
Add(T),
8+
Drain { index: usize, offset: usize },
9+
}
10+
511
#[derive(Clone, Debug)]
612
pub struct ModifiedSet<T: Idx> {
7-
modified: VecDeque<T>,
13+
modified: VecDeque<Undo<T>>,
814
snapshots: usize,
915
modified_set: BitSet<T>,
10-
undo_offsets: Vec<usize>,
1116
offsets: Vec<usize>,
1217
}
1318

@@ -18,7 +23,6 @@ impl<T: Idx> Default for ModifiedSet<T> {
1823
snapshots: 0,
1924
modified_set: BitSet::new_empty(0),
2025
offsets: Vec::new(),
21-
undo_offsets: Vec::new(),
2226
}
2327
}
2428
}
@@ -33,62 +37,59 @@ impl<T: Idx> ModifiedSet<T> {
3337
self.modified_set.resize(index.index() + 1);
3438
}
3539
if self.modified_set.insert(index) {
36-
self.modified.push_back(index);
40+
self.modified.push_back(Undo::Add(index));
3741
}
3842
}
3943

40-
pub fn drain(&mut self, offset: &Offset<T>, mut f: impl FnMut(T) -> bool) {
41-
let offset = &mut self.offsets[offset.index];
42-
for &index in self.modified.iter().skip(*offset) {
43-
if f(index) {}
44+
pub fn drain(&mut self, index: &Offset<T>, mut f: impl FnMut(T) -> bool) {
45+
let offset = &mut self.offsets[index.index];
46+
if *offset < self.modified.len() {
47+
for &undo in self.modified.iter().skip(*offset) {
48+
if let Undo::Add(index) = undo {
49+
f(index);
50+
}
51+
}
52+
self.modified.push_back(Undo::Drain { index: index.index, offset: *offset });
53+
*offset = self.modified.len();
4454
}
45-
*offset = self.modified.len();
4655
}
4756

4857
pub fn snapshot(&mut self) -> Snapshot<T> {
4958
self.snapshots += 1;
50-
let offsets_start = self.undo_offsets.len();
51-
self.undo_offsets.extend_from_slice(&self.offsets);
52-
Snapshot {
53-
modified_len: self.modified.len(),
54-
offsets_start,
55-
offsets_len: self.offsets.len(),
56-
_marker: PhantomData,
57-
}
59+
Snapshot { modified_len: self.modified.len(), _marker: PhantomData }
5860
}
5961

6062
pub fn rollback_to(&mut self, snapshot: Snapshot<T>) {
6163
self.snapshots -= 1;
62-
for &index in self.modified.iter().skip(snapshot.modified_len) {
63-
self.modified_set.remove(index);
64-
}
65-
self.modified.truncate(snapshot.modified_len);
66-
let (offsets, offsets_rest) = self.offsets.split_at_mut(snapshot.offsets_len);
67-
offsets.copy_from_slice(
68-
&self.undo_offsets
69-
[snapshot.offsets_start..snapshot.offsets_start + snapshot.offsets_len],
70-
);
71-
for offset in offsets_rest {
72-
*offset = self.modified.len().min(*offset);
64+
if snapshot.modified_len < self.modified.len() {
65+
for &undo in
66+
self.modified.iter().rev().take(self.modified.len() - snapshot.modified_len)
67+
{
68+
match undo {
69+
Undo::Add(index) => {
70+
self.modified_set.remove(index);
71+
}
72+
Undo::Drain { index, offset } => {
73+
if let Some(o) = self.offsets.get_mut(index) {
74+
*o = offset;
75+
}
76+
}
77+
}
78+
}
79+
self.modified.truncate(snapshot.modified_len);
7380
}
74-
self.undo_offsets.truncate(snapshot.offsets_start);
7581

7682
if self.snapshots == 0 {
7783
let min = self.offsets.iter().copied().min().unwrap_or(0);
78-
// Any indices still in `modified` may not have been instantiated, so if we observe them again
79-
// we need to notify any listeners again
80-
for index in self.modified.drain(..min) {
81-
self.modified_set.remove(index);
82-
}
84+
self.modified.drain(..min);
8385
for offset in &mut self.offsets {
8486
*offset -= min;
8587
}
8688
}
8789
}
8890

89-
pub fn commit(&mut self, snapshot: Snapshot<T>) {
91+
pub fn commit(&mut self, _snapshot: Snapshot<T>) {
9092
self.snapshots -= 1;
91-
self.undo_offsets.truncate(snapshot.offsets_start);
9293
if self.snapshots == 0 {
9394
// Everything up until this point is committed, so we can forget anything before the
9495
// current offsets
@@ -102,6 +103,7 @@ impl<T: Idx> ModifiedSet<T> {
102103

103104
pub fn register(&mut self) -> Offset<T> {
104105
let index = self.offsets.len();
106+
self.modified.push_back(Undo::Drain { index, offset: 0 });
105107
self.offsets.push(0);
106108
Offset { index, _marker: PhantomData }
107109
}
@@ -131,7 +133,5 @@ impl<T> Drop for Offset<T> {
131133
#[derive(Debug)]
132134
pub struct Snapshot<T> {
133135
modified_len: usize,
134-
offsets_start: usize,
135-
offsets_len: usize,
136136
_marker: PhantomData<T>,
137137
}

0 commit comments

Comments
 (0)