forked from libre-chip/fayalite
speed up LazyInterned by redoing caching using RwLock and add a thread-local cache
This commit is contained in:
parent
9db3240644
commit
1bc835803b
4 changed files with 189 additions and 107 deletions
|
|
@ -109,14 +109,42 @@ impl<T: StaticType, Len: KnownSize> Default for ArrayType<T, Len> {
|
|||
}
|
||||
}
|
||||
|
||||
struct MakeType<T: StaticType>(Interned<T>);
|
||||
|
||||
impl<T: StaticType> From<MakeType<T>> for Interned<T> {
|
||||
fn from(value: MakeType<T>) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StaticType> Default for MakeType<T> {
|
||||
fn default() -> Self {
|
||||
Self(T::TYPE.intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
struct MakeMaskType<T: StaticType>(Interned<T::MaskType>);
|
||||
|
||||
impl<T: StaticType> From<MakeMaskType<T>> for Interned<T::MaskType> {
|
||||
fn from(value: MakeMaskType<T>) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StaticType> Default for MakeMaskType<T> {
|
||||
fn default() -> Self {
|
||||
Self(T::MASK_TYPE.intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StaticType, Len: KnownSize> StaticType for ArrayType<T, Len> {
|
||||
const TYPE: Self = Self {
|
||||
element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()),
|
||||
element: LazyInterned::new_const::<MakeType<T>>(),
|
||||
len: Len::SIZE,
|
||||
type_properties: Self::TYPE_PROPERTIES,
|
||||
};
|
||||
const MASK_TYPE: Self::MaskType = ArrayType::<T::MaskType, Len> {
|
||||
element: LazyInterned::new_lazy(&|| T::MASK_TYPE.intern_sized()),
|
||||
element: LazyInterned::new_const::<MakeMaskType<T>>(),
|
||||
len: Len::SIZE,
|
||||
type_properties: Self::MASK_TYPE_PROPERTIES,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use serde::{Deserialize, Serialize};
|
|||
use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::{Borrow, Cow},
|
||||
cell::RefCell,
|
||||
cmp::Ordering,
|
||||
ffi::{OsStr, OsString},
|
||||
fmt,
|
||||
hash::{BuildHasher, Hash, Hasher},
|
||||
iter::FusedIterator,
|
||||
marker::PhantomData,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::RwLock,
|
||||
|
|
@ -23,51 +23,172 @@ use std::{
|
|||
mod interner;
|
||||
mod type_map;
|
||||
|
||||
pub trait LazyInternedTrait<T: ?Sized + Send + Sync + 'static>: Send + Sync + Any {
|
||||
fn get(&self) -> Interned<T>;
|
||||
/// invariant: T must be zero-sized, `type_id` is unique for every possible T value.
|
||||
struct LazyInternedLazyInner<T: ?Sized + 'static> {
|
||||
type_id: TypeId,
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static, F: ?Sized + Fn() -> Interned<T> + Send + Sync + Any>
|
||||
LazyInternedTrait<T> for F
|
||||
{
|
||||
fn get(&self) -> Interned<T> {
|
||||
self()
|
||||
impl<T: ?Sized + 'static> Hash for LazyInternedLazyInner<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Self { type_id, value: _ } = self;
|
||||
type_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct LazyInternedFn<T: ?Sized + Send + Sync + 'static>(pub &'static dyn LazyInternedTrait<T>);
|
||||
impl<T: ?Sized + 'static> PartialEq for LazyInternedLazyInner<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self { type_id, value: _ } = self;
|
||||
*type_id == other.type_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Copy for LazyInternedFn<T> {}
|
||||
impl<T: ?Sized + 'static> Eq for LazyInternedLazyInner<T> {}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Clone for LazyInternedFn<T> {
|
||||
impl<T: ?Sized + 'static> fmt::Debug for LazyInternedLazyInner<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LazyInternedLazyInner")
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + 'static> LazyInternedLazyInner<T> {
|
||||
const fn new(value: T) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
const { assert!(size_of::<T>() == 0) };
|
||||
Self {
|
||||
type_id: TypeId::of::<T>(),
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LazyInternedLazy<T: ?Sized + Send + Sync + 'static>(
|
||||
&'static LazyInternedLazyInner<dyn Fn() -> Interned<T> + Send + Sync>,
|
||||
);
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> LazyInternedLazy<T> {
|
||||
pub const fn new_const<V: Default + Into<Interned<T>>>() -> Self {
|
||||
Self(&const { LazyInternedLazyInner::new(|| V::default().into()) })
|
||||
}
|
||||
pub const fn new_const_default() -> Self
|
||||
where
|
||||
Interned<T>: Default,
|
||||
{
|
||||
Self::new_const::<Interned<T>>()
|
||||
}
|
||||
pub fn interned(self) -> Interned<T> {
|
||||
struct Map(hashbrown::HashTable<(TypeId, &'static (dyn Any + Send + Sync))>);
|
||||
impl Map {
|
||||
const EMPTY: Self = Self(hashbrown::HashTable::new());
|
||||
fn get<T: ?Sized + Send + Sync + 'static>(
|
||||
&self,
|
||||
lazy_interned_lazy: LazyInternedLazy<T>,
|
||||
hash: u64,
|
||||
) -> Option<&'static Interned<T>> {
|
||||
let &(_, v) = self.0.find(hash, |v| v.0 == lazy_interned_lazy.0.type_id)?;
|
||||
let Some(retval) = v.downcast_ref::<Interned<T>>() else {
|
||||
unreachable!();
|
||||
};
|
||||
Some(retval)
|
||||
}
|
||||
fn get_or_insert<T: ?Sized + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
lazy_interned_lazy: LazyInternedLazy<T>,
|
||||
hash: u64,
|
||||
v: &'static Interned<T>,
|
||||
) -> &'static Interned<T> {
|
||||
let entry = self
|
||||
.0
|
||||
.entry(
|
||||
hash,
|
||||
|&(k, _)| k == lazy_interned_lazy.0.type_id,
|
||||
|&(k, _)| type_map::TypeIdBuildHasher.hash_one(k),
|
||||
)
|
||||
.or_insert_with(|| (lazy_interned_lazy.0.type_id, v));
|
||||
let &(_, v) = entry.get();
|
||||
let Some(retval) = v.downcast_ref::<Interned<T>>() else {
|
||||
unreachable!();
|
||||
};
|
||||
retval
|
||||
}
|
||||
}
|
||||
static GLOBAL_CACHE: RwLock<Map> = RwLock::new(Map::EMPTY);
|
||||
#[cold]
|
||||
fn insert_in_thread_local_cache<T: ?Sized + Send + Sync + 'static>(
|
||||
cache: &RefCell<Map>,
|
||||
this: LazyInternedLazy<T>,
|
||||
hash: u64,
|
||||
) -> Interned<T> {
|
||||
let read_lock = GLOBAL_CACHE.read().unwrap();
|
||||
let v = read_lock.get(this, hash);
|
||||
drop(read_lock);
|
||||
let v = v.unwrap_or_else(|| {
|
||||
let v = Box::leak(Box::new((this.0.value)()));
|
||||
GLOBAL_CACHE.write().unwrap().get_or_insert(this, hash, v)
|
||||
});
|
||||
*cache.borrow_mut().get_or_insert(this, hash, v)
|
||||
}
|
||||
thread_local! {
|
||||
static THREAD_LOCAL_CACHE: RefCell<Map> = const { RefCell::new(Map::EMPTY) };
|
||||
}
|
||||
let hash = type_map::TypeIdBuildHasher.hash_one(self.0.type_id);
|
||||
THREAD_LOCAL_CACHE.with(|cache| {
|
||||
let borrow = cache.borrow();
|
||||
if let Some(v) = borrow.get(self, hash) {
|
||||
*v
|
||||
} else {
|
||||
drop(borrow);
|
||||
insert_in_thread_local_cache(cache, self, hash)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Copy for LazyInternedLazy<T> {}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Clone for LazyInternedLazy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Hash for LazyInternedFn<T> {
|
||||
impl<T: ?Sized + Send + Sync + 'static> Hash for LazyInternedLazy<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.get_ptr_eq_with_type_id().hash(state);
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> Eq for LazyInternedFn<T> {}
|
||||
impl<T: ?Sized + Send + Sync + 'static> Eq for LazyInternedLazy<T> {}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> PartialEq for LazyInternedFn<T> {
|
||||
impl<T: ?Sized + Send + Sync + 'static> PartialEq for LazyInternedLazy<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.get_ptr_eq_with_type_id() == other.0.get_ptr_eq_with_type_id()
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LazyInterned<T: ?Sized + Send + Sync + 'static> {
|
||||
Interned(Interned<T>),
|
||||
Lazy(LazyInternedFn<T>),
|
||||
Lazy(LazyInternedLazy<T>),
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> LazyInterned<T> {
|
||||
pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
|
||||
Self::Lazy(LazyInternedFn(v))
|
||||
pub const fn new_const<V: Default + Into<Interned<T>>>() -> Self {
|
||||
Self::Lazy(LazyInternedLazy::new_const::<V>())
|
||||
}
|
||||
pub const fn new_const_default() -> Self
|
||||
where
|
||||
Interned<T>: Default,
|
||||
{
|
||||
Self::new_const::<Interned<T>>()
|
||||
}
|
||||
pub fn interned(self) -> Interned<T> {
|
||||
match self {
|
||||
Self::Interned(retval) => retval,
|
||||
Self::Lazy(retval) => retval.interned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +200,7 @@ impl<T: ?Sized + Sync + Send + 'static> Clone for LazyInterned<T> {
|
|||
|
||||
impl<T: ?Sized + Sync + Send + 'static> Copy for LazyInterned<T> {}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> Deref for LazyInterned<T> {
|
||||
impl<T: ?Sized + Sync + Send + 'static> Deref for LazyInterned<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
@ -87,9 +208,9 @@ impl<T: ?Sized + Sync + Send + 'static + Intern> Deref for LazyInterned<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> Eq for LazyInterned<T> where Interned<T>: Eq {}
|
||||
impl<T: ?Sized + Sync + Send + 'static> Eq for LazyInterned<T> where Interned<T>: Eq {}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> PartialEq for LazyInterned<T>
|
||||
impl<T: ?Sized + Sync + Send + 'static> PartialEq for LazyInterned<T>
|
||||
where
|
||||
Interned<T>: PartialEq,
|
||||
{
|
||||
|
|
@ -98,7 +219,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> Ord for LazyInterned<T>
|
||||
impl<T: ?Sized + Sync + Send + 'static> Ord for LazyInterned<T>
|
||||
where
|
||||
Interned<T>: Ord,
|
||||
{
|
||||
|
|
@ -107,7 +228,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> PartialOrd for LazyInterned<T>
|
||||
impl<T: ?Sized + Sync + Send + 'static> PartialOrd for LazyInterned<T>
|
||||
where
|
||||
Interned<T>: PartialOrd,
|
||||
{
|
||||
|
|
@ -116,7 +237,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static + Intern> Hash for LazyInterned<T>
|
||||
impl<T: ?Sized + Sync + Send + 'static> Hash for LazyInterned<T>
|
||||
where
|
||||
Interned<T>: Hash,
|
||||
{
|
||||
|
|
@ -125,77 +246,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Sync + Send + 'static> LazyInterned<T> {
|
||||
pub fn interned(self) -> Interned<T>
|
||||
where
|
||||
T: Intern,
|
||||
{
|
||||
struct MemoizeInterned<T: ?Sized + Intern>(PhantomData<T>);
|
||||
|
||||
impl<T: ?Sized + Intern> Hash for MemoizeInterned<T> {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Intern> PartialEq for MemoizeInterned<T> {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Intern> Eq for MemoizeInterned<T> {}
|
||||
|
||||
impl<T: ?Sized + Intern> Clone for MemoizeInterned<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Intern> Copy for MemoizeInterned<T> {}
|
||||
|
||||
impl<T: ?Sized + Intern> MemoizeGeneric for MemoizeInterned<T> {
|
||||
type InputRef<'a> = LazyInternedFn<T>;
|
||||
|
||||
type InputOwned = LazyInternedFn<T>;
|
||||
|
||||
type InputCow<'a> = LazyInternedFn<T>;
|
||||
|
||||
type Output = Interned<T>;
|
||||
|
||||
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
|
||||
a == b
|
||||
}
|
||||
|
||||
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
||||
*input
|
||||
}
|
||||
|
||||
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
|
||||
input
|
||||
}
|
||||
|
||||
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
|
||||
*input
|
||||
}
|
||||
|
||||
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
|
||||
input
|
||||
}
|
||||
|
||||
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
|
||||
input
|
||||
}
|
||||
|
||||
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
|
||||
input.0.get()
|
||||
}
|
||||
}
|
||||
match self {
|
||||
Self::Interned(retval) => retval,
|
||||
Self::Lazy(retval) => MemoizeInterned(PhantomData).get(retval),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InternedCompare {
|
||||
type InternedCompareKey: Ord + Hash;
|
||||
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
sync::RwLock,
|
||||
};
|
||||
|
||||
struct TypeIdHasher(u64);
|
||||
pub(crate) struct TypeIdHasher(u64);
|
||||
|
||||
// assumes TypeId has at least 64 bits that is a good hash
|
||||
impl Hasher for TypeIdHasher {
|
||||
|
|
@ -63,7 +63,7 @@ impl Hasher for TypeIdHasher {
|
|||
}
|
||||
}
|
||||
|
||||
struct TypeIdBuildHasher;
|
||||
pub(crate) struct TypeIdBuildHasher;
|
||||
|
||||
impl BuildHasher for TypeIdBuildHasher {
|
||||
type Hasher = TypeIdHasher;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
use crate::{
|
||||
expr::{Expr, HdlPartialEqImpl, HdlPartialOrdImpl, ToExpr, ValueType},
|
||||
int::Bool,
|
||||
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
||||
intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize},
|
||||
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
|
|
@ -240,11 +240,17 @@ impl<T: ?Sized + PhantomConstValue> PhantomConst<T> {
|
|||
{
|
||||
Self::new_interned(value.intern_deref())
|
||||
}
|
||||
pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
|
||||
pub const fn new_const<V: Default + Into<Interned<T>>>() -> Self {
|
||||
Self {
|
||||
value: LazyInterned::new_lazy(v),
|
||||
value: LazyInterned::new_const::<V>(),
|
||||
}
|
||||
}
|
||||
pub const fn new_const_default() -> Self
|
||||
where
|
||||
Interned<T>: Default,
|
||||
{
|
||||
Self::new_const::<Interned<T>>()
|
||||
}
|
||||
pub fn get(self) -> Interned<T> {
|
||||
self.value.interned()
|
||||
}
|
||||
|
|
@ -334,9 +340,7 @@ impl<T: ?Sized + PhantomConstValue> StaticType for PhantomConst<T>
|
|||
where
|
||||
Interned<T>: Default,
|
||||
{
|
||||
const TYPE: Self = PhantomConst {
|
||||
value: LazyInterned::new_lazy(&Interned::<T>::default),
|
||||
};
|
||||
const TYPE: Self = Self::new_const_default();
|
||||
const MASK_TYPE: Self::MaskType = ();
|
||||
const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
|
||||
const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue