Auto merge of #114894 - Zoxc:sharded-cfg-cleanup2, r=cjgillot

Remove conditional use of `Sharded` from query state

`Sharded` is already a zero cost abstraction, so it shouldn't affect the performance of the single thread compiler if LLVM does its job.

r? `@cjgillot`
This commit is contained in:
bors 2023-08-29 12:04:37 +00:00
commit 6d32b298ed
4 changed files with 47 additions and 72 deletions

View File

@ -2,9 +2,12 @@ use crate::fx::{FxHashMap, FxHasher};
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
use crate::sync::{is_dyn_thread_safe, CacheAligned}; use crate::sync::{is_dyn_thread_safe, CacheAligned};
use crate::sync::{Lock, LockGuard}; use crate::sync::{Lock, LockGuard};
#[cfg(parallel_compiler)]
use itertools::Either;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::hash_map::RawEntryMut; use std::collections::hash_map::RawEntryMut;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter;
use std::mem; use std::mem;
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
@ -70,19 +73,27 @@ impl<T> Sharded<T> {
} }
} }
pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> { #[inline]
pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> {
match self { match self {
Self::Single(single) => vec![single.lock()], #[cfg(not(parallel_compiler))]
Self::Single(single) => iter::once(single.lock()),
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
Self::Shards(shards) => shards.iter().map(|shard| shard.0.lock()).collect(), Self::Single(single) => Either::Left(iter::once(single.lock())),
#[cfg(parallel_compiler)]
Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.lock())),
} }
} }
pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> { #[inline]
pub fn try_lock_shards(&self) -> impl Iterator<Item = Option<LockGuard<'_, T>>> {
match self { match self {
Self::Single(single) => Some(vec![single.try_lock()?]), #[cfg(not(parallel_compiler))]
Self::Single(single) => iter::once(single.try_lock()),
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
Self::Shards(shards) => shards.iter().map(|shard| shard.0.try_lock()).collect(), Self::Single(single) => Either::Left(iter::once(single.try_lock())),
#[cfg(parallel_compiler)]
Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.try_lock())),
} }
} }
} }
@ -101,7 +112,7 @@ pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
impl<K: Eq, V> ShardedHashMap<K, V> { impl<K: Eq, V> ShardedHashMap<K, V> {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.lock_shards().iter().map(|shard| shard.len()).sum() self.lock_shards().map(|shard| shard.len()).sum()
} }
} }

View File

@ -1296,8 +1296,8 @@ macro_rules! sty_debug_print {
}; };
$(let mut $variant = total;)* $(let mut $variant = total;)*
let shards = tcx.interners.type_.lock_shards(); for shard in tcx.interners.type_.lock_shards() {
let types = shards.iter().flat_map(|shard| shard.keys()); let types = shard.keys();
for &InternedInSet(t) in types { for &InternedInSet(t) in types {
let variant = match t.internee { let variant = match t.internee {
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
@ -1316,6 +1316,7 @@ macro_rules! sty_debug_print {
if ct { total.ct_infer += 1; variant.ct_infer += 1 } if ct { total.ct_infer += 1; variant.ct_infer += 1 }
if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 } if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
} }
}
writeln!(fmt, "Ty interner total ty lt ct all")?; writeln!(fmt, "Ty interner total ty lt ct all")?;
$(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \ $(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \
{ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%", {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",

View File

@ -70,8 +70,7 @@ where
} }
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
let shards = self.cache.lock_shards(); for shard in self.cache.lock_shards() {
for shard in shards.iter() {
for (k, v) in shard.iter() { for (k, v) in shard.iter() {
f(k, &v.0, v.1); f(k, &v.0, v.1);
} }
@ -160,8 +159,7 @@ where
} }
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
let shards = self.cache.lock_shards(); for shard in self.cache.lock_shards() {
for shard in shards.iter() {
for (k, v) in shard.iter_enumerated() { for (k, v) in shard.iter_enumerated() {
if let Some(v) = v { if let Some(v) = v {
f(&k, &v.0, v.1); f(&k, &v.0, v.1);

View File

@ -12,12 +12,13 @@ use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobI
use crate::query::SerializedDepNodeIndex; use crate::query::SerializedDepNodeIndex;
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
use crate::HandleCycleError; use crate::HandleCycleError;
#[cfg(parallel_compiler)]
use rustc_data_structures::cold_path;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sharded::Sharded;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lock; use rustc_data_structures::sync::Lock;
#[cfg(parallel_compiler)]
use rustc_data_structures::{cold_path, sharded::Sharded};
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError}; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use std::cell::Cell; use std::cell::Cell;
@ -30,10 +31,7 @@ use thin_vec::ThinVec;
use super::QueryConfig; use super::QueryConfig;
pub struct QueryState<K, D: DepKind> { pub struct QueryState<K, D: DepKind> {
#[cfg(parallel_compiler)]
active: Sharded<FxHashMap<K, QueryResult<D>>>, active: Sharded<FxHashMap<K, QueryResult<D>>>,
#[cfg(not(parallel_compiler))]
active: Lock<FxHashMap<K, QueryResult<D>>>,
} }
/// Indicates the state of a query for a given key in a query map. /// Indicates the state of a query for a given key in a query map.
@ -52,15 +50,7 @@ where
D: DepKind, D: DepKind,
{ {
pub fn all_inactive(&self) -> bool { pub fn all_inactive(&self) -> bool {
#[cfg(parallel_compiler)] self.active.lock_shards().all(|shard| shard.is_empty())
{
let shards = self.active.lock_shards();
shards.iter().all(|shard| shard.is_empty())
}
#[cfg(not(parallel_compiler))]
{
self.active.lock().is_empty()
}
} }
pub fn try_collect_active_jobs<Qcx: Copy>( pub fn try_collect_active_jobs<Qcx: Copy>(
@ -71,26 +61,10 @@ where
) -> Option<()> { ) -> Option<()> {
let mut active = Vec::new(); let mut active = Vec::new();
#[cfg(parallel_compiler)]
{
// We use try_lock_shards here since we are called from the // We use try_lock_shards here since we are called from the
// deadlock handler, and this shouldn't be locked. // deadlock handler, and this shouldn't be locked.
let shards = self.active.try_lock_shards()?; for shard in self.active.try_lock_shards() {
for shard in shards.iter() { for (k, v) in shard?.iter() {
for (k, v) in shard.iter() {
if let QueryResult::Started(ref job) = *v {
active.push((*k, job.clone()));
}
}
}
}
#[cfg(not(parallel_compiler))]
{
// We use try_lock here since we are called from the
// deadlock handler, and this shouldn't be locked.
// (FIXME: Is this relevant for non-parallel compilers? It doesn't
// really hurt much.)
for (k, v) in self.active.try_lock()?.iter() {
if let QueryResult::Started(ref job) = *v { if let QueryResult::Started(ref job) = *v {
active.push((*k, job.clone())); active.push((*k, job.clone()));
} }
@ -184,10 +158,7 @@ where
cache.complete(key, result, dep_node_index); cache.complete(key, result, dep_node_index);
let job = { let job = {
#[cfg(parallel_compiler)]
let mut lock = state.active.get_shard_by_value(&key).lock(); let mut lock = state.active.get_shard_by_value(&key).lock();
#[cfg(not(parallel_compiler))]
let mut lock = state.active.lock();
match lock.remove(&key).unwrap() { match lock.remove(&key).unwrap() {
QueryResult::Started(job) => job, QueryResult::Started(job) => job,
QueryResult::Poisoned => panic!(), QueryResult::Poisoned => panic!(),
@ -209,10 +180,7 @@ where
// Poison the query so jobs waiting on it panic. // Poison the query so jobs waiting on it panic.
let state = self.state; let state = self.state;
let job = { let job = {
#[cfg(parallel_compiler)]
let mut shard = state.active.get_shard_by_value(&self.key).lock(); let mut shard = state.active.get_shard_by_value(&self.key).lock();
#[cfg(not(parallel_compiler))]
let mut shard = state.active.lock();
let job = match shard.remove(&self.key).unwrap() { let job = match shard.remove(&self.key).unwrap() {
QueryResult::Started(job) => job, QueryResult::Started(job) => job,
QueryResult::Poisoned => panic!(), QueryResult::Poisoned => panic!(),
@ -336,10 +304,7 @@ where
Qcx: QueryContext, Qcx: QueryContext,
{ {
let state = query.query_state(qcx); let state = query.query_state(qcx);
#[cfg(parallel_compiler)]
let mut state_lock = state.active.get_shard_by_value(&key).lock(); let mut state_lock = state.active.get_shard_by_value(&key).lock();
#[cfg(not(parallel_compiler))]
let mut state_lock = state.active.lock();
// For the parallel compiler we need to check both the query cache and query state structures // For the parallel compiler we need to check both the query cache and query state structures
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the // while holding the state lock to ensure that 1) the query has not yet completed and 2) the