perf: Reduce memory usage by deduplicating type information (#803)

* Reduce memory usage by deduplicating type information

We were storing the type information, 3 words wide, for each memo in each slot, while it is always constant wrt. the ingredient (different slots of the same ingredients will always have the same memos in the same order). This introduces some more unsafety, and the result wasn't as fast so I also had to use some lock-free structures, but the result is worth it: this shaves off 230mb from rust-analyzer with new Salsa.

* Simplify

* Replace `RwLock` with boxcar + `AtomicPtr`

* Use TypeId and allocate instead

* Use `OnceLock` instead of atomic-ptr

---------

Co-authored-by: Chayim Refael Friedman <chayimfr@gmail.com>
This commit is contained in:
Lukas Wirth 2025-04-22 13:24:23 +02:00 committed by GitHub
parent cf9efae0da
commit f981e7d0fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 475 additions and 210 deletions

View file

@ -256,21 +256,45 @@ macro_rules! setup_tracked_fn {
struct_index
}
};
let memo_ingredient_indices = From::from((zalsa, struct_index, first_index));
let fn_ingredient = <$zalsa::function::IngredientImpl<$Configuration>>::new(
first_index,
memo_ingredient_indices,
$lru,
zalsa.views().downcaster_for::<dyn $Db>()
);
$zalsa::macro_if! { $needs_interner =>
let intern_ingredient = <$zalsa::interned::IngredientImpl<$Configuration>>::new(
first_index.successor(0)
);
}
let intern_ingredient_memo_types = $zalsa::macro_if! {
if $needs_interner {
Some($zalsa::Ingredient::memo_table_types(&intern_ingredient))
} else {
None
}
};
// SAFETY: We call with the correct memo types.
let memo_ingredient_indices = unsafe {
$zalsa::NewMemoIngredientIndices::create(
zalsa,
struct_index,
first_index,
$zalsa::function::MemoEntryType::of::<$zalsa::function::Memo<$Configuration>>(),
intern_ingredient_memo_types,
)
};
// SAFETY: We pass the MemoEntryType for this Configuration, and we lookup the memo types table correctly.
let fn_ingredient = unsafe {
<$zalsa::function::IngredientImpl<$Configuration>>::new(
first_index,
memo_ingredient_indices,
$lru,
zalsa.views().downcaster_for::<dyn $Db>(),
)
};
$zalsa::macro_if! {
if $needs_interner {
vec![
Box::new(fn_ingredient),
Box::new(<$zalsa::interned::IngredientImpl<$Configuration>>::new(
first_index.successor(0)
)),
Box::new(intern_ingredient),
]
} else {
vec![