Skip to content

Commit 383c1d7

Browse files
committed
Auto merge of #109117 - oli-obk:locks, r=michaelwoerister
Avoid a few locks We can use atomics or datastructures tuned for specific access patterns instead of locks. This may be an improvement for parallel rustc, but it's mostly a cleanup making various datastructures only usable in the way they are used right now (append data, never mutate), instead of having a general purpose lock.
2 parents 90a9f69 + 457a162 commit 383c1d7

File tree

17 files changed

+137
-47
lines changed

17 files changed

+137
-47
lines changed

Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -1418,9 +1418,9 @@ dependencies = [
14181418

14191419
[[package]]
14201420
name = "elsa"
1421-
version = "1.8.0"
1421+
version = "1.7.1"
14221422
source = "registry+https://github.com/rust-lang/crates.io-index"
1423-
checksum = "f74077c3c3aedb99a2683919698285596662518ea13e5eedcf8bdd43b0d0453b"
1423+
checksum = "848fe615fbb0a74d9ae68dcaa510106d32e37d9416207bbea4bd008bd89c47ed"
14241424
dependencies = [
14251425
"stable_deref_trait",
14261426
]

compiler/rustc_data_structures/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ stacker = "0.1.15"
3232
tempfile = "3.2"
3333
thin-vec = "0.2.12"
3434
tracing = "0.1"
35-
elsa = "1.8"
35+
elsa = "=1.7.1"
3636

3737
[dependencies.parking_lot]
3838
version = "0.11"

compiler/rustc_data_structures/src/sync.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5151
pub use std::sync::atomic::Ordering;
5252
pub use std::sync::atomic::Ordering::SeqCst;
5353

54-
pub use vec::AppendOnlyVec;
54+
pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
5555

5656
mod vec;
5757

@@ -107,6 +107,14 @@ cfg_if! {
107107
}
108108
}
109109

110+
impl Atomic<bool> {
111+
pub fn fetch_or(&self, val: bool, _: Ordering) -> bool {
112+
let result = self.0.get() | val;
113+
self.0.set(val);
114+
result
115+
}
116+
}
117+
110118
impl<T: Copy + PartialEq> Atomic<T> {
111119
#[inline]
112120
pub fn compare_exchange(&self,
@@ -481,14 +489,6 @@ impl<T: Default> Default for Lock<T> {
481489
}
482490
}
483491

484-
// FIXME: Probably a bad idea
485-
impl<T: Clone> Clone for Lock<T> {
486-
#[inline]
487-
fn clone(&self) -> Self {
488-
Lock::new(self.borrow().clone())
489-
}
490-
}
491-
492492
#[derive(Debug, Default)]
493493
pub struct RwLock<T>(InnerRwLock<T>);
494494

compiler/rustc_data_structures/src/sync/vec.rs

+66-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ use std::marker::PhantomData;
22

33
use rustc_index::vec::Idx;
44

5-
pub struct AppendOnlyVec<I: Idx, T: Copy> {
5+
#[derive(Default)]
6+
pub struct AppendOnlyIndexVec<I: Idx, T: Copy> {
67
#[cfg(not(parallel_compiler))]
78
vec: elsa::vec::FrozenVec<T>,
89
#[cfg(parallel_compiler)]
910
vec: elsa::sync::LockFreeFrozenVec<T>,
1011
_marker: PhantomData<fn(&I)>,
1112
}
1213

13-
impl<I: Idx, T: Copy> AppendOnlyVec<I, T> {
14+
impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {
1415
pub fn new() -> Self {
1516
Self {
1617
#[cfg(not(parallel_compiler))]
@@ -39,3 +40,66 @@ impl<I: Idx, T: Copy> AppendOnlyVec<I, T> {
3940
return self.vec.get(i);
4041
}
4142
}
43+
44+
#[derive(Default)]
45+
pub struct AppendOnlyVec<T: Copy> {
46+
#[cfg(not(parallel_compiler))]
47+
vec: elsa::vec::FrozenVec<T>,
48+
#[cfg(parallel_compiler)]
49+
vec: elsa::sync::LockFreeFrozenVec<T>,
50+
}
51+
52+
impl<T: Copy> AppendOnlyVec<T> {
53+
pub fn new() -> Self {
54+
Self {
55+
#[cfg(not(parallel_compiler))]
56+
vec: elsa::vec::FrozenVec::new(),
57+
#[cfg(parallel_compiler)]
58+
vec: elsa::sync::LockFreeFrozenVec::new(),
59+
}
60+
}
61+
62+
pub fn push(&self, val: T) -> usize {
63+
#[cfg(not(parallel_compiler))]
64+
let i = self.vec.len();
65+
#[cfg(not(parallel_compiler))]
66+
self.vec.push(val);
67+
#[cfg(parallel_compiler)]
68+
let i = self.vec.push(val);
69+
i
70+
}
71+
72+
pub fn get(&self, i: usize) -> Option<T> {
73+
#[cfg(not(parallel_compiler))]
74+
return self.vec.get_copy(i);
75+
#[cfg(parallel_compiler)]
76+
return self.vec.get(i);
77+
}
78+
79+
pub fn iter_enumerated(&self) -> impl Iterator<Item = (usize, T)> + '_ {
80+
(0..)
81+
.map(|i| (i, self.get(i)))
82+
.take_while(|(_, o)| o.is_some())
83+
.filter_map(|(i, o)| Some((i, o?)))
84+
}
85+
86+
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
87+
(0..).map(|i| self.get(i)).take_while(|o| o.is_some()).filter_map(|o| o)
88+
}
89+
}
90+
91+
impl<T: Copy + PartialEq> AppendOnlyVec<T> {
92+
pub fn contains(&self, val: T) -> bool {
93+
self.iter_enumerated().any(|(_, v)| v == val)
94+
}
95+
}
96+
97+
impl<A: Copy> FromIterator<A> for AppendOnlyVec<A> {
98+
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
99+
let this = Self::new();
100+
for val in iter {
101+
this.push(val);
102+
}
103+
this
104+
}
105+
}

compiler/rustc_interface/src/queries.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
77
use rustc_codegen_ssa::CodegenResults;
88
use rustc_data_structures::steal::Steal;
99
use rustc_data_structures::svh::Svh;
10-
use rustc_data_structures::sync::{AppendOnlyVec, Lrc, OnceCell, RwLock, WorkerLocal};
10+
use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal};
1111
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
1212
use rustc_hir::definitions::Definitions;
1313
use rustc_incremental::DepGraphFuture;
@@ -215,7 +215,7 @@ impl<'tcx> Queries<'tcx> {
215215

216216
let cstore = RwLock::new(Box::new(CStore::new(sess)) as _);
217217
let definitions = RwLock::new(Definitions::new(sess.local_stable_crate_id()));
218-
let source_span = AppendOnlyVec::new();
218+
let source_span = AppendOnlyIndexVec::new();
219219
let _id = source_span.push(krate.spans.inner_span);
220220
debug_assert_eq!(_id, CRATE_DEF_ID);
221221
let untracked = Untracked { cstore, source_span, definitions };

compiler/rustc_lint/src/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1947,7 +1947,7 @@ impl KeywordIdents {
19471947
};
19481948

19491949
// Don't lint `r#foo`.
1950-
if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
1950+
if cx.sess().parse_sess.raw_identifier_spans.contains(ident.span) {
19511951
return;
19521952
}
19531953

compiler/rustc_metadata/src/creader.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl CStore {
185185
fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
186186
if !deps.contains(&cnum) {
187187
let data = self.get_crate_data(cnum);
188-
for &dep in data.dependencies().iter() {
188+
for dep in data.dependencies() {
189189
if dep != cnum {
190190
self.push_dependencies_in_postorder(deps, dep);
191191
}
@@ -605,7 +605,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
605605
if cmeta.update_extern_crate(extern_crate) {
606606
// Propagate the extern crate info to dependencies if it was updated.
607607
let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
608-
for &dep_cnum in cmeta.dependencies().iter() {
608+
for dep_cnum in cmeta.dependencies() {
609609
self.update_extern_crate(dep_cnum, extern_crate);
610610
}
611611
}

compiler/rustc_metadata/src/rmeta/decoder.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_ast as ast;
77
use rustc_data_structures::captures::Captures;
88
use rustc_data_structures::fx::FxHashMap;
99
use rustc_data_structures::svh::Svh;
10-
use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell};
10+
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell};
1111
use rustc_data_structures::unhash::UnhashMap;
1212
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
1313
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
@@ -109,7 +109,7 @@ pub(crate) struct CrateMetadata {
109109
/// IDs as they are seen from the current compilation session.
110110
cnum_map: CrateNumMap,
111111
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
112-
dependencies: Lock<Vec<CrateNum>>,
112+
dependencies: AppendOnlyVec<CrateNum>,
113113
/// How to link (or not link) this crate to the currently compiled crate.
114114
dep_kind: Lock<CrateDepKind>,
115115
/// Filesystem location of this crate.
@@ -1594,7 +1594,7 @@ impl CrateMetadata {
15941594
.collect();
15951595
let alloc_decoding_state =
15961596
AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
1597-
let dependencies = Lock::new(cnum_map.iter().cloned().collect());
1597+
let dependencies = cnum_map.iter().copied().collect();
15981598

15991599
// Pre-decode the DefPathHash->DefIndex table. This is a cheap operation
16001600
// that does not copy any data. It just does some data verification.
@@ -1634,12 +1634,12 @@ impl CrateMetadata {
16341634
cdata
16351635
}
16361636

1637-
pub(crate) fn dependencies(&self) -> LockGuard<'_, Vec<CrateNum>> {
1638-
self.dependencies.borrow()
1637+
pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> + '_ {
1638+
self.dependencies.iter()
16391639
}
16401640

16411641
pub(crate) fn add_dependency(&self, cnum: CrateNum) {
1642-
self.dependencies.borrow_mut().push(cnum);
1642+
self.dependencies.push(cnum);
16431643
}
16441644

16451645
pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool {

compiler/rustc_metadata/src/rmeta/encoder.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1712,8 +1712,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
17121712
let stability = tcx.lookup_stability(CRATE_DEF_ID);
17131713
let macros =
17141714
self.lazy_array(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
1715-
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
1716-
for (i, span) in spans.into_iter().enumerate() {
1715+
for (i, span) in self.tcx.sess.parse_sess.proc_macro_quoted_spans() {
17171716
let span = self.lazy(span);
17181717
self.tables.proc_macro_quoted_spans.set_some(i, span);
17191718
}

compiler/rustc_middle/src/mir/interpret/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ impl AllocDecodingState {
263263
}
264264

265265
pub fn new(data_offsets: Vec<u32>) -> Self {
266-
let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()];
266+
let decoding_state =
267+
std::iter::repeat_with(|| Lock::new(State::Empty)).take(data_offsets.len()).collect();
267268

268269
Self { decoding_state, data_offsets }
269270
}

compiler/rustc_parse/src/lexer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl<'a> StringReader<'a> {
175175
if !sym.can_be_raw() {
176176
self.sess.emit_err(errors::CannotBeRawIdent { span, ident: sym });
177177
}
178-
self.sess.raw_identifier_spans.borrow_mut().push(span);
178+
self.sess.raw_identifier_spans.push(span);
179179
token::Ident(sym, true)
180180
}
181181
rustc_lexer::TokenKind::UnknownPrefix => {

compiler/rustc_parse/src/parser/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutab
2929
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
3030
use rustc_ast_pretty::pprust;
3131
use rustc_data_structures::fx::FxHashMap;
32+
use rustc_data_structures::sync::Ordering;
3233
use rustc_errors::PResult;
3334
use rustc_errors::{
3435
Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan,
@@ -1540,8 +1541,10 @@ pub(crate) fn make_unclosed_delims_error(
15401541
}
15411542

15421543
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedDelim>, sess: &ParseSess) {
1543-
*sess.reached_eof.borrow_mut() |=
1544-
unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none());
1544+
let _ = sess.reached_eof.fetch_or(
1545+
unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()),
1546+
Ordering::Relaxed,
1547+
);
15451548
for unmatched in unclosed_delims.drain(..) {
15461549
if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) {
15471550
e.emit();

compiler/rustc_passes/src/entry.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
187187

188188
fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
189189
let sp = tcx.def_span(CRATE_DEF_ID);
190-
if *tcx.sess.parse_sess.reached_eof.borrow() {
190+
if tcx.sess.parse_sess.reached_eof.load(rustc_data_structures::sync::Ordering::Relaxed) {
191191
// There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
192192
// the missing `fn main()` then as it might have been hidden inside an unclosed block.
193193
tcx.sess.delay_span_bug(sp, "`main` not found, but expected unclosed brace error");

compiler/rustc_query_system/src/cache.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ use rustc_data_structures::sync::Lock;
77

88
use std::hash::Hash;
99

10-
#[derive(Clone)]
1110
pub struct Cache<Key, Value> {
1211
hashmap: Lock<FxHashMap<Key, WithDepNode<Value>>>,
1312
}
1413

14+
impl<Key: Clone, Value: Clone> Clone for Cache<Key, Value> {
15+
fn clone(&self) -> Self {
16+
Self { hashmap: Lock::new(self.hashmap.borrow().clone()) }
17+
}
18+
}
19+
1520
impl<Key, Value> Default for Cache<Key, Value> {
1621
fn default() -> Self {
1722
Self { hashmap: Default::default() }

compiler/rustc_session/src/cstore.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::search_paths::PathKind;
66
use crate::utils::NativeLibKind;
77
use crate::Session;
88
use rustc_ast as ast;
9-
use rustc_data_structures::sync::{self, AppendOnlyVec, MetadataRef, RwLock};
9+
use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock};
1010
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
1111
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
1212
use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -257,6 +257,6 @@ pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send;
257257
pub struct Untracked {
258258
pub cstore: RwLock<Box<CrateStoreDyn>>,
259259
/// Reference span for definitions.
260-
pub source_span: AppendOnlyVec<LocalDefId, Span>,
260+
pub source_span: AppendOnlyIndexVec<LocalDefId, Span>,
261261
pub definitions: RwLock<Definitions>,
262262
}

compiler/rustc_session/src/parse.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::lint::{
88
};
99
use rustc_ast::node_id::NodeId;
1010
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
11-
use rustc_data_structures::sync::{Lock, Lrc};
11+
use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc};
1212
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
1313
use rustc_errors::{
1414
fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
@@ -194,7 +194,7 @@ pub struct ParseSess {
194194
pub edition: Edition,
195195
/// Places where raw identifiers were used. This is used to avoid complaining about idents
196196
/// clashing with keywords in new editions.
197-
pub raw_identifier_spans: Lock<Vec<Span>>,
197+
pub raw_identifier_spans: AppendOnlyVec<Span>,
198198
/// Places where identifiers that contain invalid Unicode codepoints but that look like they
199199
/// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
200200
/// provide a single error per unique incorrect identifier.
@@ -208,7 +208,7 @@ pub struct ParseSess {
208208
pub gated_spans: GatedSpans,
209209
pub symbol_gallery: SymbolGallery,
210210
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
211-
pub reached_eof: Lock<bool>,
211+
pub reached_eof: AtomicBool,
212212
/// Environment variables accessed during the build and their values when they exist.
213213
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
214214
/// File paths accessed during the build.
@@ -219,7 +219,7 @@ pub struct ParseSess {
219219
pub assume_incomplete_release: bool,
220220
/// Spans passed to `proc_macro::quote_span`. Each span has a numerical
221221
/// identifier represented by its position in the vector.
222-
pub proc_macro_quoted_spans: Lock<Vec<Span>>,
222+
pub proc_macro_quoted_spans: AppendOnlyVec<Span>,
223223
/// Used to generate new `AttrId`s. Every `AttrId` is unique.
224224
pub attr_id_generator: AttrIdGenerator,
225225
}
@@ -247,14 +247,14 @@ impl ParseSess {
247247
config: FxIndexSet::default(),
248248
check_config: CrateCheckConfig::default(),
249249
edition: ExpnId::root().expn_data().edition,
250-
raw_identifier_spans: Lock::new(Vec::new()),
250+
raw_identifier_spans: Default::default(),
251251
bad_unicode_identifiers: Lock::new(Default::default()),
252252
source_map,
253253
buffered_lints: Lock::new(vec![]),
254254
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
255255
gated_spans: GatedSpans::default(),
256256
symbol_gallery: SymbolGallery::default(),
257-
reached_eof: Lock::new(false),
257+
reached_eof: AtomicBool::new(false),
258258
env_depinfo: Default::default(),
259259
file_depinfo: Default::default(),
260260
type_ascription_path_suggestions: Default::default(),
@@ -324,13 +324,13 @@ impl ParseSess {
324324
}
325325

326326
pub fn save_proc_macro_span(&self, span: Span) -> usize {
327-
let mut spans = self.proc_macro_quoted_spans.lock();
328-
spans.push(span);
329-
return spans.len() - 1;
327+
self.proc_macro_quoted_spans.push(span)
330328
}
331329

332-
pub fn proc_macro_quoted_spans(&self) -> Vec<Span> {
333-
self.proc_macro_quoted_spans.lock().clone()
330+
pub fn proc_macro_quoted_spans(&self) -> impl Iterator<Item = (usize, Span)> + '_ {
331+
// This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for
332+
// AppendOnlyVec, so we resort to this scheme.
333+
self.proc_macro_quoted_spans.iter_enumerated()
334334
}
335335

336336
#[track_caller]

0 commit comments

Comments
 (0)