mirror of
https://github.com/lexmount/moli.git
synced 2026-10-30 08:07:38 +00:00
perf(layout): bound initial numeric cache reservation
Reserve at most four existing boxes on the first store and grow with actual cache demand. Avoid the full-tree candidate scan and cover sparse stores in both flattened and ordinary block trees.
This commit is contained in:
@@ -101,37 +101,42 @@ fn numeric_cache_growth_keeps_box_viewport_and_invalidation_owners_distinct() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numeric_cache_allocation_follows_actual_stores_in_a_large_flattened_tree() {
|
||||
let mut world = LayoutWorld::new(block(0), false);
|
||||
for source in 1..=4096 {
|
||||
let mut text = block(source);
|
||||
text.inline_flattened = true;
|
||||
text.inline_context_owner = Some(world.root());
|
||||
world.boxes.push(text);
|
||||
fn numeric_cache_allocation_follows_stores_in_large_flattened_and_block_trees() {
|
||||
for flattened in [false, true] {
|
||||
let mut world = LayoutWorld::new(block(0), false);
|
||||
for source in 1..=4096 {
|
||||
let mut child = block(source);
|
||||
if flattened {
|
||||
child.inline_flattened = true;
|
||||
child.inline_context_owner = Some(world.root());
|
||||
}
|
||||
world.boxes.push(child);
|
||||
}
|
||||
let sibling = LayoutBoxId::from_index(world.len());
|
||||
world.boxes.push(block(4097));
|
||||
let input = input();
|
||||
let root = world.root().to_taffy();
|
||||
world.cache_store(root, &input, output(60.0));
|
||||
world.cache_store(sibling.to_taffy(), &input, output(80.0));
|
||||
assert_eq!(world.cache_get(root, &input), Some(output(60.0)));
|
||||
assert_eq!(
|
||||
world.cache_get(sibling.to_taffy(), &input),
|
||||
Some(output(80.0))
|
||||
);
|
||||
let allocated_bytes = world.box_caches.capacity() * std::mem::size_of::<taffy::Cache>();
|
||||
assert!(
|
||||
allocated_bytes < 64 * 1024,
|
||||
"4098 construction boxes with two stores should not allocate dense caches: {allocated_bytes} bytes"
|
||||
);
|
||||
assert_eq!(world.box_caches.len(), 2);
|
||||
// Unvisited boxes, including flattened boxes, can still store later.
|
||||
let previously_unvisited = LayoutBoxId::from_index(4096).to_taffy();
|
||||
world.cache_store(previously_unvisited, &input, output(90.0));
|
||||
assert_eq!(
|
||||
world.cache_get(previously_unvisited, &input),
|
||||
Some(output(90.0))
|
||||
);
|
||||
}
|
||||
let sibling = LayoutBoxId::from_index(world.len());
|
||||
world.boxes.push(block(4097));
|
||||
let input = input();
|
||||
let root = world.root().to_taffy();
|
||||
world.cache_store(root, &input, output(60.0));
|
||||
world.cache_store(sibling.to_taffy(), &input, output(80.0));
|
||||
assert_eq!(world.cache_get(root, &input), Some(output(60.0)));
|
||||
assert_eq!(
|
||||
world.cache_get(sibling.to_taffy(), &input),
|
||||
Some(output(80.0))
|
||||
);
|
||||
let allocated_bytes = world.box_caches.capacity() * std::mem::size_of::<taffy::Cache>();
|
||||
assert!(
|
||||
allocated_bytes < 64 * 1024,
|
||||
"4098 construction boxes with two stores should not allocate dense caches: {allocated_bytes} bytes"
|
||||
);
|
||||
// Admission hints must not prevent a later valid store on a flattened box.
|
||||
let previously_unvisited = LayoutBoxId::from_index(4096).to_taffy();
|
||||
world.cache_store(previously_unvisited, &input, output(90.0));
|
||||
assert_eq!(
|
||||
world.cache_get(previously_unvisited, &input),
|
||||
Some(output(90.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -706,15 +706,9 @@ where
|
||||
slot
|
||||
} else {
|
||||
if self.box_caches.is_empty() {
|
||||
// Reserve without initializing caches for unvisited boxes.
|
||||
// This is a hint, not an eligibility restriction: a caller
|
||||
// may subsequently store any valid construction/numeric box.
|
||||
let candidates = self
|
||||
.boxes
|
||||
.iter()
|
||||
.filter(|layout_box| !layout_box.inline_flattened)
|
||||
.count();
|
||||
self.box_caches.reserve_exact(candidates);
|
||||
// Bound the first allocation without scanning construction
|
||||
// boxes or reserving caches for boxes that may never store.
|
||||
self.box_caches.reserve_exact(self.boxes.len().min(4));
|
||||
}
|
||||
let slot = u32::try_from(self.box_caches.len())
|
||||
.ok()
|
||||
|
||||
Reference in New Issue
Block a user