Skip to content

Use u64 trie iteration tokens#52

Open
MesTTo wants to merge 1 commit into
Adam-Vandervorst:masterfrom
MesTTo:pr/pathmap-u64-iter-tokens
Open

Use u64 trie iteration tokens#52
MesTTo wants to merge 1 commit into
Adam-Vandervorst:masterfrom
MesTTo:pr/pathmap-u64-iter-tokens

Conversation

@MesTTo

@MesTTo MesTTo commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Answers the question the new_iter_token doc comment already asks: the
token is a node-local cursor, so it never needs to encode a whole path, and
64 bits are enough. The ByteNode stops caching the remaining mask word
inside the token — the source of the 128-bit requirement — and keeps only
one more than the last byte returned, recomputing the next set bit from its
own mask (next_iter_byte_from: a masked trailing_zeros probe across at
most four words, still O(1) per step). Every other node type already used
small counters, so this is purely a type change for them.

iter_token_for_path semantics are unchanged (resume strictly after the
given byte); the word-edge cases (63/64, 127/128, 191/192, 255) are pinned by
a new test. Consumers (the zippers, cursors, merkleization, viz) treat
tokens as opaque, so the swap is type-level there.

Result

ReadZipperCore shrinks from 144 to 128 bytes (measured on both this branch
and master), and each ancestor-stack entry loses 8 bytes of padding.
Interleaved A/B against master (two reps each side): superdense_k_path
-7..-8%, sparse_iter -23..-47%, binary_iter up to -53%, no regressed
cell in either bench. The resume-strictly-after contract is also modeled in
Alloy (fac27_iter_token in a separate verification repo), UNSAT in scope.

Test plan

  • cargo test --release --lib (661/0, matches the master baseline)
  • cargo miri test on the new boundary test and the touched dense-node tests
  • cargo test --release --doc (7/0)
  • cargo bench --bench superdense_keys / sparse_keys / binary_keys -- iter

Implements the answer the iter-token note in the TrieNode trait already
sketched: the token is a node-local cursor, so it never needs to encode a
whole path, and 64 bits are enough. The ByteNode stops caching the remaining
mask word inside the token (the source of the 128-bit requirement); it keeps
only one more than the last byte returned and recomputes the next set bit
from its own mask (next_iter_byte_from, four masked trailing_zeros probes,
still O(1) per step). All other node types already used small counters.

iter_token_for_path semantics are unchanged (resume strictly after the given
byte; the 63/127/191/255 word-edge cases land identically through the word
advance), pinned by a new mask-word-boundary test. Consumers treat tokens as
opaque, so the swap is type-level for them; ReadZipperCore shrinks from 144
to 128 bytes (measured on both trees), and each ancestor stack entry loses 8
bytes of padding.
@Adam-Vandervorst

Adam-Vandervorst commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Local best-of-3 on suggested benchmarks. Do you want more benchmarks @luketpeterson ?

master
superdense_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ superdense_iter                       │               │               │               │         │
│  ├─ 100                  2.483 µs      │ 12.87 µs      │ 2.503 µs      │ 2.551 µs      │ 5000    │ 5000
│  ├─ 200                  4.908 µs      │ 15.94 µs      │ 4.948 µs      │ 5.04 µs       │ 5000    │ 5000
│  ├─ 400                  10.02 µs      │ 75.6 µs       │ 10.31 µs      │ 11.17 µs      │ 5000    │ 5000
│  ├─ 800                  21.1 µs       │ 57.05 µs      │ 21.22 µs      │ 21.73 µs      │ 5000    │ 5000
│  ├─ 1600                 40.62 µs      │ 80.99 µs      │ 41.6 µs       │ 42.12 µs      │ 5000    │ 5000
│  ╰─ 3200                 83.33 µs      │ 176.4 µs      │ 84.02 µs      │ 85.65 µs      │ 5000    │ 5000
╰─ superdense_k_path_iter                │               │               │               │         │
   ├─ 500                  5.489 µs      │ 46.43 µs      │ 5.629 µs      │ 5.962 µs      │ 5000    │ 5000
   ├─ 1000                 10.65 µs      │ 45.31 µs      │ 10.9 µs       │ 11.17 µs      │ 5000    │ 5000
   ├─ 2000                 21.24 µs      │ 51.9 µs       │ 21.82 µs      │ 21.86 µs      │ 5000    │ 5000
   ├─ 4000                 42.51 µs      │ 106.2 µs      │ 43.66 µs      │ 44.32 µs      │ 5000    │ 5000
   ├─ 8000                 85.2 µs       │ 193.6 µs      │ 88.29 µs      │ 91.66 µs      │ 5000    │ 5000
   ╰─ 16000                164 µs        │ 373.3 µs      │ 171.6 µs      │ 174.8 µs      │ 5000    │ 5000
u64-iter-tokens
superdense_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ superdense_iter                       │               │               │               │         │
│  ├─ 100                  2.213 µs      │ 30.42 µs      │ 2.223 µs      │ 2.317 µs      │ 5000    │ 5000
│  ├─ 200                  4.267 µs      │ 79.49 µs      │ 4.307 µs      │ 5.197 µs      │ 5000    │ 5000
│  ├─ 400                  9.075 µs      │ 285.5 µs      │ 9.146 µs      │ 10.39 µs      │ 5000    │ 5000
│  ├─ 800                  18.6 µs       │ 59.52 µs      │ 18.95 µs      │ 19.55 µs      │ 5000    │ 5000
│  ├─ 1600                 36.73 µs      │ 73.79 µs      │ 39.26 µs      │ 38.83 µs      │ 5000    │ 5000
│  ╰─ 3200                 73.25 µs      │ 178 µs        │ 74.58 µs      │ 76.18 µs      │ 5000    │ 5000
╰─ superdense_k_path_iter                │               │               │               │         │
   ├─ 500                  4.757 µs      │ 21.08 µs      │ 5.138 µs      │ 5.232 µs      │ 5000    │ 5000
   ├─ 1000                 10.16 µs      │ 59.32 µs      │ 10.2 µs       │ 10.35 µs      │ 5000    │ 5000
   ├─ 2000                 20.28 µs      │ 66.31 µs      │ 20.38 µs      │ 20.71 µs      │ 5000    │ 5000
   ├─ 4000                 39.96 µs      │ 77.71 µs      │ 40.11 µs      │ 40.73 µs      │ 5000    │ 5000
   ├─ 8000                 78.82 µs      │ 156.4 µs      │ 81.02 µs      │ 81.73 µs      │ 5000    │ 5000
   ╰─ 16000                145.8 µs      │ 263.8 µs      │ 149.1 µs      │ 152.7 µs      │ 5000    │ 5000

master
sparse_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ sparse_iter                       │               │               │               │         │
│  ├─ 10               409.7 ns      │ 5.229 µs      │ 420.7 ns      │ 427.3 ns      │ 4000    │ 4000
│  ├─ 20               740.9 ns      │ 7.298 µs      │ 763.7 ns      │ 827.1 ns      │ 4000    │ 16000
│  ├─ 40               1.471 µs      │ 22.04 µs      │ 1.511 µs      │ 1.703 µs      │ 4000    │ 4000
│  ├─ 80               2.924 µs      │ 8.635 µs      │ 2.974 µs      │ 2.992 µs      │ 4000    │ 4000
│  ├─ 160              5.9 µs        │ 21.29 µs      │ 6.01 µs       │ 6.362 µs      │ 4000    │ 4000
│  ╰─ 320              11.92 µs      │ 37.34 µs      │ 12.23 µs      │ 12.36 µs      │ 4000    │ 4000
╰─ sparse_k_path_iter                │               │               │               │         │
   ├─ 50               1.401 µs      │ 10.81 µs      │ 1.432 µs      │ 1.459 µs      │ 4000    │ 4000
   ├─ 100              2.704 µs      │ 11.26 µs      │ 2.734 µs      │ 2.777 µs      │ 4000    │ 4000
   ├─ 200              5.298 µs      │ 16.37 µs      │ 5.379 µs      │ 5.701 µs      │ 4000    │ 4000
   ├─ 400              10.92 µs      │ 47.5 µs       │ 11.19 µs      │ 11.79 µs      │ 4000    │ 4000
   ├─ 800              24.3 µs       │ 51.96 µs      │ 24.55 µs      │ 25.44 µs      │ 4000    │ 4000
   ╰─ 1600             50.05 µs      │ 92.84 µs      │ 50.39 µs      │ 52.09 µs      │ 4000    │ 4000
u64-iter-tokens
sparse_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ sparse_iter                       │               │               │               │         │
│  ├─ 10               409.7 ns      │ 5.699 µs      │ 410.7 ns      │ 418.6 ns      │ 4000    │ 4000
│  ├─ 20               740.7 ns      │ 11.94 µs      │ 761.2 ns      │ 856.7 ns      │ 4000    │ 8000
│  ├─ 40               1.431 µs      │ 12.06 µs      │ 1.502 µs      │ 2.038 µs      │ 4000    │ 4000
│  ├─ 80               2.815 µs      │ 23.69 µs      │ 2.864 µs      │ 3.069 µs      │ 4000    │ 4000
│  ├─ 160              5.619 µs      │ 40.47 µs      │ 5.76 µs       │ 5.973 µs      │ 4000    │ 4000
│  ╰─ 320              11.4 µs       │ 49.93 µs      │ 11.56 µs      │ 11.95 µs      │ 4000    │ 4000
╰─ sparse_k_path_iter                │               │               │               │         │
   ├─ 50               1.091 µs      │ 8.054 µs      │ 1.121 µs      │ 1.162 µs      │ 4000    │ 4000
   ├─ 100              2.083 µs      │ 11.5 µs       │ 2.143 µs      │ 2.311 µs      │ 4000    │ 4000
   ├─ 200              4.136 µs      │ 46.72 µs      │ 4.207 µs      │ 4.374 µs      │ 4000    │ 4000
   ├─ 400              8.995 µs      │ 46.07 µs      │ 9.717 µs      │ 9.728 µs      │ 4000    │ 4000
   ├─ 800              20.62 µs      │ 84.38 µs      │ 21.09 µs      │ 21.95 µs      │ 4000    │ 4000
   ╰─ 1600             44.32 µs      │ 153.1 µs      │ 45.93 µs      │ 46.72 µs      │ 4000    │ 4000

master
binary_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ binary_k_path_iter                │               │               │               │         │
│  ├─ 50               2.894 µs      │ 12.54 µs      │ 2.924 µs      │ 2.944 µs      │ 4000    │ 4000
│  ├─ 100              5.419 µs      │ 45.49 µs      │ 5.49 µs       │ 5.659 µs      │ 4000    │ 4000
│  ├─ 200              10.52 µs      │ 43.33 µs      │ 10.64 µs      │ 10.91 µs      │ 4000    │ 4000
│  ├─ 400              20.65 µs      │ 43.17 µs      │ 21.08 µs      │ 21.41 µs      │ 4000    │ 4000
│  ├─ 800              40.57 µs      │ 175.7 µs      │ 41 µs         │ 42.58 µs      │ 4000    │ 4000
│  ╰─ 1600             77.79 µs      │ 390.2 µs      │ 79.91 µs      │ 82.46 µs      │ 4000    │ 4000
╰─ binary_zipper_iter                │               │               │               │         │
   ├─ 50               3.535 µs      │ 39.81 µs      │ 3.565 µs      │ 3.797 µs      │ 4000    │ 4000
   ├─ 100              6.741 µs      │ 19.51 µs      │ 6.811 µs      │ 6.978 µs      │ 4000    │ 4000
   ├─ 200              13.1 µs       │ 33.7 µs       │ 13.17 µs      │ 13.63 µs      │ 4000    │ 4000
   ├─ 400              24.79 µs      │ 87.05 µs      │ 25.25 µs      │ 25.93 µs      │ 4000    │ 4000
   ├─ 800              48.29 µs      │ 166.8 µs      │ 49.21 µs      │ 50 µs         │ 4000    │ 4000
   ╰─ 1600             97.47 µs      │ 502.3 µs      │ 99.42 µs      │ 102.9 µs      │ 4000    │ 4000
u64-iter-tokens
binary_keys            fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ binary_k_path_iter                │               │               │               │         │
│  ├─ 50               1.662 µs      │ 10 µs         │ 1.713 µs      │ 1.728 µs      │ 4000    │ 4000
│  ├─ 100              3.045 µs      │ 28.54 µs      │ 3.185 µs      │ 3.265 µs      │ 4000    │ 4000
│  ├─ 200              6.211 µs      │ 53.11 µs      │ 6.421 µs      │ 6.729 µs      │ 4000    │ 4000
│  ├─ 400              12.2 µs       │ 109 µs        │ 12.61 µs      │ 13.24 µs      │ 4000    │ 4000
│  ├─ 800              26.08 µs      │ 103.5 µs      │ 26.5 µs       │ 26.95 µs      │ 4000    │ 4000
│  ╰─ 1600             56.06 µs      │ 171.9 µs      │ 57.77 µs      │ 58.91 µs      │ 4000    │ 4000
╰─ binary_zipper_iter                │               │               │               │         │
   ├─ 50               1.802 µs      │ 9.958 µs      │ 1.832 µs      │ 1.848 µs      │ 4000    │ 4000
   ├─ 100              3.435 µs      │ 39 µs         │ 3.535 µs      │ 4.396 µs      │ 4000    │ 4000
   ├─ 200              6.862 µs      │ 20.75 µs      │ 6.972 µs      │ 7.277 µs      │ 4000    │ 4000
   ├─ 400              13.66 µs      │ 38.64 µs      │ 13.94 µs      │ 15.27 µs      │ 4000    │ 4000
   ├─ 800              26.75 µs      │ 89.45 µs      │ 27.5 µs       │ 28.29 µs      │ 4000    │ 4000
   ╰─ 1600             59.43 µs      │ 187.8 µs      │ 64.35 µs      │ 65.59 µs      │ 4000    │ 4000

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