Skip to content

Commit 8da5869

Browse files
committed
Auto merge of #69464 - Marwes:detach_undo_log, r=nikomatsakis
perf: Unify the undo log of all snapshot types Extracted from #69218 and extended to all the current snapshot types. Since snapshotting is such a frequent action in the compiler and many of the scopes execute so little work, the act of creating the snapshot and rolling back empty/small snapshots end up showing in perf. By unifying all the logs into one the creation of snapshots becomes significantly cheaper at the cost of some complexity when combining the log with the specific data structures that are being mutated. Depends on rust-lang/ena#29
2 parents 43271a3 + 3f85338 commit 8da5869

File tree

26 files changed

+893
-535
lines changed

26 files changed

+893
-535
lines changed

Cargo.lock

+11-2
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,15 @@ dependencies = [
993993
"log",
994994
]
995995

996+
[[package]]
997+
name = "ena"
998+
version = "0.14.0"
999+
source = "registry+https://github.com/rust-lang/crates.io-index"
1000+
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
1001+
dependencies = [
1002+
"log",
1003+
]
1004+
9961005
[[package]]
9971006
name = "encoding_rs"
9981007
version = "0.8.17"
@@ -3234,7 +3243,7 @@ dependencies = [
32343243
"bitflags",
32353244
"cfg-if",
32363245
"crossbeam-utils 0.7.2",
3237-
"ena",
3246+
"ena 0.13.1",
32383247
"indexmap",
32393248
"jobserver",
32403249
"lazy_static 1.4.0",
@@ -3683,7 +3692,7 @@ dependencies = [
36833692
"bitflags",
36843693
"cfg-if",
36853694
"crossbeam-utils 0.7.2",
3686-
"ena",
3695+
"ena 0.14.0",
36873696
"graphviz",
36883697
"indexmap",
36893698
"jobserver",

src/librustc_data_structures/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ path = "lib.rs"
1010
doctest = false
1111

1212
[dependencies]
13-
ena = "0.13.1"
13+
ena = "0.14"
1414
indexmap = "1"
1515
log = "0.4"
1616
jobserver_crate = { version = "0.1.13", package = "jobserver" }

src/librustc_data_structures/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub mod sync;
8484
pub mod thin_vec;
8585
pub mod tiny_list;
8686
pub mod transitive_relation;
87+
pub use ena::undo_log;
8788
pub use ena::unify;
8889
mod atomic_ref;
8990
pub mod fingerprint;
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,140 @@
11
use crate::fx::FxHashMap;
2+
use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog};
3+
use std::borrow::{Borrow, BorrowMut};
24
use std::hash::Hash;
3-
use std::mem;
5+
use std::marker::PhantomData;
46
use std::ops;
57

8+
pub use crate::undo_log::Snapshot;
9+
610
#[cfg(test)]
711
mod tests;
812

9-
pub struct SnapshotMap<K, V>
10-
where
11-
K: Clone + Eq,
12-
{
13-
map: FxHashMap<K, V>,
14-
undo_log: Vec<UndoLog<K, V>>,
15-
num_open_snapshots: usize,
13+
pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>;
14+
pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>;
15+
16+
pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> {
17+
map: M,
18+
undo_log: L,
19+
_marker: PhantomData<(K, V)>,
1620
}
1721

1822
// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
19-
impl<K, V> Default for SnapshotMap<K, V>
23+
impl<K, V, M, L> Default for SnapshotMap<K, V, M, L>
2024
where
21-
K: Hash + Clone + Eq,
25+
M: Default,
26+
L: Default,
2227
{
2328
fn default() -> Self {
24-
SnapshotMap { map: Default::default(), undo_log: Default::default(), num_open_snapshots: 0 }
29+
SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData }
2530
}
2631
}
2732

28-
pub struct Snapshot {
29-
len: usize,
30-
}
31-
32-
enum UndoLog<K, V> {
33+
pub enum UndoLog<K, V> {
3334
Inserted(K),
3435
Overwrite(K, V),
3536
Purged,
3637
}
3738

38-
impl<K, V> SnapshotMap<K, V>
39+
impl<K, V, M, L> SnapshotMap<K, V, M, L> {
40+
pub fn with_log<L2>(&mut self, undo_log: L2) -> SnapshotMap<K, V, &mut M, L2> {
41+
SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData }
42+
}
43+
}
44+
45+
impl<K, V, M, L> SnapshotMap<K, V, M, L>
3946
where
4047
K: Hash + Clone + Eq,
48+
M: BorrowMut<FxHashMap<K, V>> + Borrow<FxHashMap<K, V>>,
49+
L: UndoLogs<UndoLog<K, V>>,
4150
{
4251
pub fn clear(&mut self) {
43-
self.map.clear();
52+
self.map.borrow_mut().clear();
4453
self.undo_log.clear();
45-
self.num_open_snapshots = 0;
46-
}
47-
48-
fn in_snapshot(&self) -> bool {
49-
self.num_open_snapshots > 0
5054
}
5155

5256
pub fn insert(&mut self, key: K, value: V) -> bool {
53-
match self.map.insert(key.clone(), value) {
57+
match self.map.borrow_mut().insert(key.clone(), value) {
5458
None => {
55-
if self.in_snapshot() {
56-
self.undo_log.push(UndoLog::Inserted(key));
57-
}
59+
self.undo_log.push(UndoLog::Inserted(key));
5860
true
5961
}
6062
Some(old_value) => {
61-
if self.in_snapshot() {
62-
self.undo_log.push(UndoLog::Overwrite(key, old_value));
63-
}
63+
self.undo_log.push(UndoLog::Overwrite(key, old_value));
6464
false
6565
}
6666
}
6767
}
6868

6969
pub fn remove(&mut self, key: K) -> bool {
70-
match self.map.remove(&key) {
70+
match self.map.borrow_mut().remove(&key) {
7171
Some(old_value) => {
72-
if self.in_snapshot() {
73-
self.undo_log.push(UndoLog::Overwrite(key, old_value));
74-
}
72+
self.undo_log.push(UndoLog::Overwrite(key, old_value));
7573
true
7674
}
7775
None => false,
7876
}
7977
}
8078

8179
pub fn get(&self, key: &K) -> Option<&V> {
82-
self.map.get(key)
80+
self.map.borrow().get(key)
8381
}
82+
}
8483

84+
impl<K, V> SnapshotMap<K, V>
85+
where
86+
K: Hash + Clone + Eq,
87+
{
8588
pub fn snapshot(&mut self) -> Snapshot {
86-
let len = self.undo_log.len();
87-
self.num_open_snapshots += 1;
88-
Snapshot { len }
89-
}
90-
91-
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
92-
assert!(self.undo_log.len() >= snapshot.len);
93-
assert!(self.num_open_snapshots > 0);
89+
self.undo_log.start_snapshot()
9490
}
9591

9692
pub fn commit(&mut self, snapshot: Snapshot) {
97-
self.assert_open_snapshot(&snapshot);
98-
if self.num_open_snapshots == 1 {
99-
// The root snapshot. It's safe to clear the undo log because
100-
// there's no snapshot further out that we might need to roll back
101-
// to.
102-
assert!(snapshot.len == 0);
103-
self.undo_log.clear();
104-
}
105-
106-
self.num_open_snapshots -= 1;
93+
self.undo_log.commit(snapshot)
10794
}
10895

109-
pub fn partial_rollback<F>(&mut self, snapshot: &Snapshot, should_revert_key: &F)
110-
where
111-
F: Fn(&K) -> bool,
112-
{
113-
self.assert_open_snapshot(snapshot);
114-
for i in (snapshot.len..self.undo_log.len()).rev() {
115-
let reverse = match self.undo_log[i] {
116-
UndoLog::Purged => false,
117-
UndoLog::Inserted(ref k) => should_revert_key(k),
118-
UndoLog::Overwrite(ref k, _) => should_revert_key(k),
119-
};
120-
121-
if reverse {
122-
let entry = mem::replace(&mut self.undo_log[i], UndoLog::Purged);
123-
self.reverse(entry);
124-
}
125-
}
96+
pub fn rollback_to(&mut self, snapshot: Snapshot) {
97+
let map = &mut self.map;
98+
self.undo_log.rollback_to(|| map, snapshot)
12699
}
100+
}
127101

128-
pub fn rollback_to(&mut self, snapshot: Snapshot) {
129-
self.assert_open_snapshot(&snapshot);
130-
while self.undo_log.len() > snapshot.len {
131-
let entry = self.undo_log.pop().unwrap();
132-
self.reverse(entry);
133-
}
102+
impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap<K, V, M, L>
103+
where
104+
K: Hash + Clone + Eq,
105+
M: Borrow<FxHashMap<K, V>>,
106+
{
107+
type Output = V;
108+
fn index(&self, key: &'k K) -> &V {
109+
&self.map.borrow()[key]
110+
}
111+
}
134112

135-
self.num_open_snapshots -= 1;
113+
impl<K, V, M, L> Rollback<UndoLog<K, V>> for SnapshotMap<K, V, M, L>
114+
where
115+
K: Eq + Hash,
116+
M: Rollback<UndoLog<K, V>>,
117+
{
118+
fn reverse(&mut self, undo: UndoLog<K, V>) {
119+
self.map.reverse(undo)
136120
}
121+
}
137122

138-
fn reverse(&mut self, entry: UndoLog<K, V>) {
139-
match entry {
123+
impl<K, V> Rollback<UndoLog<K, V>> for FxHashMap<K, V>
124+
where
125+
K: Eq + Hash,
126+
{
127+
fn reverse(&mut self, undo: UndoLog<K, V>) {
128+
match undo {
140129
UndoLog::Inserted(key) => {
141-
self.map.remove(&key);
130+
self.remove(&key);
142131
}
143132

144133
UndoLog::Overwrite(key, old_value) => {
145-
self.map.insert(key, old_value);
134+
self.insert(key, old_value);
146135
}
147136

148137
UndoLog::Purged => {}
149138
}
150139
}
151140
}
152-
153-
impl<'k, K, V> ops::Index<&'k K> for SnapshotMap<K, V>
154-
where
155-
K: Hash + Clone + Eq,
156-
{
157-
type Output = V;
158-
fn index(&self, key: &'k K) -> &V {
159-
&self.map[key]
160-
}
161-
}

0 commit comments

Comments
 (0)