Skip to content

Add PathMap benchmark coverage#44

Open
MesTTo wants to merge 2 commits into
Adam-Vandervorst:masterfrom
MesTTo:pr/pathmap-benchmarks-only
Open

Add PathMap benchmark coverage#44
MesTTo wants to merge 2 commits into
Adam-Vandervorst:masterfrom
MesTTo:pr/pathmap-benchmarks-only

Conversation

@MesTTo

@MesTTo MesTTo commented Jun 23, 2026

Copy link
Copy Markdown

Adds benchmark coverage for graft behavior, node layout, prefix and product cases, streaming cases, write zipper cases, and owned zipper head cases.

The grouped graft benchmark exposed an existing graft_child_maps panic at zipper node boundaries. The branch now also fixes with_node_at_path so it does not ask a trie node for a child using an empty node key when the zipper is already at a node boundary.

Validation:

  • cargo check --benches
  • cargo test write_zipper_graft_child_maps_zero_child_with_root_value --lib
  • cargo test --lib --tests
  • cargo bench --bench graft_child_maps_criterion -- graft_child_maps/grouped_keep_unset/contiguous/1 --warm-up-time 0.05 --measurement-time 0.1 --sample-size 10
  • jscpd --reporters ai --format rust src/write_zipper.rs

@MesTTo MesTTo marked this pull request as ready for review June 23, 2026 10:23
@adamv-symbolica

Copy link
Copy Markdown

Fails to run for me with

Benchmarking graft_child_maps/grouped_keep_unset/contiguous/1: Warming up for 150.00 ms
thread 'main' (9746966) panicked at src/dense_byte_node.rs:637:28:
index out of bounds: the len is 0 but the index is 0
stack backtrace:
   0: __rustc::rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic_bounds_check
   3: <pathmap::trie_node::tagged_node_ref::TaggedNodeRefMut<u32, ()>>::node_get_child_mut
   4: <pathmap::write_zipper::WriteZipperCore<u32, ()>>::graft_child_maps::<alloc::vec::Vec<pathmap::trie_map::PathMap<u32>>>
   5: graft_child_maps_criterion::grouped_graft
   6: <criterion::bencher::Bencher>::iter_batched::<(pathmap::trie_map::PathMap<u32>, alloc::vec::Vec<pathmap::trie_map::PathMap<u32>>, pathmap::utils::ByteMask), usize, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}::{closure#0}, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}::{closure#1}>
   7: <criterion::routine::Function<criterion::measurement::WallTime, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture> as criterion::routine::Routine<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>>::warm_up
   8: <criterion::routine::Function<criterion::measurement::WallTime, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture> as criterion::routine::Routine<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>>::sample
   9: criterion::analysis::common::<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>
  10: <criterion::benchmark_group::BenchmarkGroup<criterion::measurement::WallTime>>::bench_with_input::<criterion::benchmark_group::BenchmarkId, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture>
  11: graft_child_maps_criterion::main

@MesTTo

MesTTo commented Jun 23, 2026

Copy link
Copy Markdown
Author

I pushed ad91856 for this.

The benchmark exposed a real bug in with_node_at_path. When the zipper is already at a node boundary, self.key.node_key() is empty, but the helper still called node_get_child_mut(key). DenseByteNode::node_get_child_mut expects a non-empty key. In debug builds that trips the assertion; in the bench profile it reaches the key[0] bounds check and panics with the out-of-bounds error you saw.

The fix skips the child lookup when the current node key is empty and uses the existing direct mutation path instead. I added write_zipper_graft_child_maps_zero_child_with_root_value to cover the zero child case with a root value and nested child data.

Checked locally:

  • cargo test write_zipper_graft_child_maps_zero_child_with_root_value --lib
  • cargo test --lib --tests
  • cargo bench --bench graft_child_maps_criterion -- graft_child_maps/grouped_keep_unset/contiguous/1 --warm-up-time 0.05 --measurement-time 0.1 --sample-size 10

@MesTTo

MesTTo commented Jun 24, 2026

Copy link
Copy Markdown
Author

confirmed gone. ran the exact bench on the parent commit and it still panics at dense_byte_node.rs:637, then on ad91856 it runs clean (grouped_keep_unset/contiguous/1 ~5.6µs).

the panic is just an empty key reaching node_get_child_mut. in release it's the key[0] index that blows up (what you saw), in debug the debug_assert!(key.len() > 0) in that same fn fires instead. nothing exercised a grouped graft sitting exactly on a node boundary before, so it slipped past the existing tests... write_zipper_graft_child_maps_zero_child_with_root_value locks that shape now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants