Skip to content

perf(data): node cache for component readers - #196

Merged
janickm merged 1 commit into
stack/zarr3/02-nodesfrom
stack/zarr3/03-node-cache
Oct 23, 2026
Merged

janickm merged 1 commit into
stack/zarr3/02-nodesfrom
stack/zarr3/03-node-cache

Conversation

@janickm

@janickm janickm commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Opening a group / array constructs its zarr-python object, which decodes the node's metadata on every access (~0.5 ms per frame lookup with zarr-python 2, dominating reads of small frame arrays).

Component readers now cache the nodes they open (with their decoded metadata, but not their data) in a thread-safe nodes.NodeCache shared by all member groups of the component. The cache size is configurable via SequenceComponentGroupsReader(node_cache_size=...): None (default) caches all accessed nodes, N the N most recently used nodes, and 0 disables caching.

With the cache, repeated frame lookups take ~2 us instead of ~470 us.

Component stores are opened concurrently (hiding the latency of remote archive index reads), their hierarchies are now opened from their consolidated metadata sequentially on the calling thread, each as soon as its store is opened (while the remaining stores are still being opened): opening hierarchies is pure-Python CPU work, which concurrent threads only slow down.

Measurements

Full test sequence (35 stores, 447 MB; reading 320 camera / lidar frames: encoded images, lidar directions, distances and valid masks), local SSD, 64 cores, median of 5. "First pass" reads each frame once after opening (node cache cold), "later passes" read them again (node cache warm). Metadata reads count node metadata records read from the archives.

open_consolidated and store-opening threads (max_threads)

zarr-python 2 (2.18.7), this PR (7091fb18):

open_consolidated max_threads open metadata reads at open first pass metadata reads first pass open + first pass later passes
True 1 59 ms 0 654 us/frame 0 269 ms 185 us/frame
True 4 52 ms 0 658 us/frame 0 263 ms 189 us/frame
True default 65 ms 0 644 us/frame 0 271 ms 181 us/frame
False 1 43 ms 70 666 us/frame 779 256 ms 182 us/frame
False 4 39 ms 70 664 us/frame 779 252 ms 178 us/frame
False default 43 ms 70 663 us/frame 779 255 ms 179 us/frame

zarr-python 3 (3.4.1), with this PR's node cache (measured on #197 9aee757d, which adds zarr-python 3 support):

open_consolidated max_threads open metadata reads at open first pass metadata reads first pass open + first pass later passes
True 1 378 ms 0 311 us/frame 0 478 ms 206 us/frame
True 4 381 ms 0 313 us/frame 0 482 ms 210 us/frame
True default 389 ms 0 311 us/frame 0 488 ms 206 us/frame
False 1 51 ms 70 509 us/frame 1671 213 ms 205 us/frame
False 4 45 ms 70 510 us/frame 1671 209 ms 205 us/frame
False default 47 ms 70 512 us/frame 1671 211 ms 208 us/frame

For comparison, main (1de0192e, zarr-python 2, no node cache): open 65 ms / 42 ms (consolidated / unconsolidated), 819 / 869 us/frame on the first pass, 791 / 864 us/frame on later passes.

  • Node cache: later passes take ~180 us/frame with zarr-python 2 (main: ~790 to 860 us/frame, re-opening each node on every access).
  • Local data: store-opening threads barely matter (opening a local archive's index takes ~1 ms). zarr-python 3 constructs the objects of all nodes of consolidated hierarchies when opening them (~40 us per node, pure-Python CPU work on the calling thread), so open_consolidated=False opens ~8x faster and is faster overall (open + first pass 211 vs 488 ms). zarr-python 2 constructs nodes on access, so the two modes are close.
  • Remote data: open_consolidated=True (the default) reads 0 node metadata records, False reads one per accessed node (70 at open, 779 / 1671 during the first pass, each a request on remote storage).

Store-opening threads with remote latency

50 ms simulated latency per store opening (the remote index read), open only:

zarr-python open_consolidated max_threads collect stores first (before: 62f9767d / #197 f15e3ff7) pipelined (this PR: 7091fb18 / #197 9aee757d)
2 True 1 1866 ms 1803 ms
2 True 8 334 ms 275 ms
2 True default 176 ms 140 ms
2 False default 138 ms 130 ms
3 True 1 2161 ms 1828 ms
3 True 8 639 ms 454 ms
3 True default 465 ms 440 ms
3 False default 148 ms 123 ms

Concurrent store opening hides the latency (35 x 50 ms = 1.75 s sequentially). Opening each hierarchy as soon as its store is opened overlaps the CPU work of opening hierarchies with the remaining store openings, most visible with zarr-python 3's consolidated hierarchies and limited threads (639 -> 454 ms with 8 threads).

@copy-pr-bot

copy-pr-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@janickm
janickm added this pull request to stack #201 October 14, 2026 07:28
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test dcfb70a

@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test d435c3b

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from d435c3b to d3b4b36 Compare October 14, 2026 10:02
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test d3b4b36

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from d3b4b36 to ac24f4b Compare October 14, 2026 10:09
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test ac24f4b

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from ac24f4b to 064254f Compare October 14, 2026 11:58
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 064254f

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 064254f to f5c3f7a Compare October 14, 2026 14:16
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test f5c3f7a

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from f5c3f7a to 4a20fac Compare October 14, 2026 14:43
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 4a20fac

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 4a20fac to 375b6de Compare October 14, 2026 15:32
@janickm

janickm commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 375b6de

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 375b6de to a47b3d7 Compare October 15, 2026 07:55
@janickm

janickm commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test a47b3d7

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from a47b3d7 to e7d77cc Compare October 15, 2026 10:20
@janickm

janickm commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test e7d77cc

@janickm

janickm commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test bdb9a8e

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from bdb9a8e to 0e68e7e Compare October 16, 2026 13:37
@janickm

janickm commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 0e68e7e

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 0e68e7e to fe94b83 Compare October 19, 2026 08:56
@janickm

janickm commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test fe94b83

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from fe94b83 to f82f7ee Compare October 19, 2026 11:52
@janickm

janickm commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test f82f7ee

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from f82f7ee to 79dd9ef Compare October 19, 2026 11:58
@janickm

janickm commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 79dd9ef

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 79dd9ef to 0f552ff Compare October 21, 2026 08:37
@janickm

janickm commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 0f552ff

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 0f552ff to 517461d Compare October 21, 2026 08:53
@janickm

janickm commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 517461d

@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 517461d to a65383a Compare October 21, 2026 09:11
@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from a65383a to 8a2cea3 Compare October 21, 2026 14:15
@janickm

janickm commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 8a2cea3

Opening a group / array constructs its zarr-python object, which
decodes the node's metadata on every access (~0.5 ms per frame lookup
with zarr-python 2, dominating reads of small frame arrays).

Component readers now cache the nodes they open (with their decoded
metadata, but not their data) in a thread-safe nodes.NodeCache shared
by all member groups of the component. The cache size is configurable
via SequenceComponentGroupsReader(node_cache_size=...): None (default)
caches all accessed nodes, N the N most recently used nodes, and 0
disables caching.

With the cache, repeated frame lookups take ~2 us instead of ~470 us.

Component stores are opened concurrently (hiding the latency of
remote archive index reads), their hierarchies are now opened from
their consolidated metadata sequentially on the calling thread, each as
soon as its store is opened (while the remaining stores are still being
opened): opening hierarchies is pure-Python CPU work, which concurrent
threads only slow down.
@janickm
janickm force-pushed the stack/zarr3/03-node-cache branch from 8a2cea3 to 4044682 Compare October 21, 2026 18:01
@janickm

janickm commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

/ok to test 4044682

@janickm
janickm merged commit 0d6c43d into main Oct 23, 2026
5 checks passed
@janickm
janickm deleted the stack/zarr3/03-node-cache branch October 23, 2026 13:09
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.

1 participant