Repository navigation
Lightsheet and gene-pyramid viewers: one dask layer per level; store fetched tiles without scanning DID's cache index - #341
Merged
Conversation
Each pyramid level was one from_delayed array per chunk joined with da.block, so the graph had one layer per chunk and dask walked all of them on every slice. Showing 16 cached chunks cost ~1.4 s on a 16k-chunk level and ~26 s on a 131k-chunk level, against ~15 ms to read the files. A level is now a single map_blocks layer; the same view takes ~20 ms at any level size. Also print one [lightsheet] tiles: line per burst of reads, splitting tile time into path lookup (memo vs fetcher queue), disk read, decode and the burst span. NDI_LIGHTSHEET_TIMING=0 turns it off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJ9PUeM7x2vLsg8FcZQfXo
levelArrays joined one from_delayed array per tile with da.block, so dask walked one graph layer per tile on every slice and drawing a view cost time in proportion to the whole level. Same fix as the lightsheet loader: one map_blocks layer per level, cropped to the true size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJ9PUeM7x2vLsg8FcZQfXo
Contributor
Author
|
Two checks are red on this PR, and neither comes from this change:
Every other check that has finished is green, including Generated by Claude Code |
…ndex A fetched tile took about a minute to be added to DID's file cache once it held tens of thousands of files and many download threads finished together: _keepFetched asked the index (is_file, a row-by-row scan), and DID-python's lock let threads through unguarded or made them sleep a second per retry. Check the disk instead, and let one fetcher thread at a time add to the cache. The debug fetch line now reports the add time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJ9PUeM7x2vLsg8FcZQfXo
The shared download Session kept requests' default 10 connections per
host while the lightsheet fetcher runs up to 64 downloads at once, so
every download past the tenth opened its own connection and discarded
it afterwards ("Connection pool is full, discarding connection").
Mount an adapter pooling 64.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJ9PUeM7x2vLsg8FcZQfXo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In the lightsheet viewer, tiles drew slowly in two ways:
da.from_delayedarray per chunk or tile, joined withda.block. That gives the graph one layer per chunk, and dask walks every layer each time napari computes a slice. So the cost grew with the size of the whole level, not with the tiles on screen.is_file/add_filescanned the cache index row by row.Benchmark for (1): a view of 16 chunks, all on local disk, chunks 64×256×256 uint16.
Reading the 16 files directly takes about 15 ms. Building a 131k-chunk level at open time also dropped from about 38 s to 2 s.
Changes
ndi.pyramid.multiscale:_build_block_gridis replaced by_build_level_array. Each level is now a singleda.map_blockslayer, and each block works out its chunk fromblock_info. Thestoredshort-circuit for sparse chunks, edge-block shapes and the upsample-fallback reader all work as before.[lightsheet] tiles:line to stderr. It splits tile time into path lookup (memo hit or the fetcher queue, plus how many of those the workers found on disk vs. downloaded), disk read and decode, and gives the burst's wall-clock span.NDI_LIGHTSHEET_TIMING=0turns it off. WithNDI_LIGHTSHEET_DEBUG, the per-fetch line also reportscache add Xs._ChunkFetcher._keepFetched): checks the disk (one stat) instead of the cache index, and lets one fetcher thread at a time add to DID's cache. The underlying cache fixes are in DID itself, FileCache: thread-safe lock, binary-search lookups, cache lock handed on quickly and expiring like MATLAB's VH-Lab/DID-python#89 and fileCache: binary-search the index; the cache lock is handed on quickly VH-Lab/DID-matlab#221, both merged.ndi.cloud.api.files._download_session): pools 64 connections per host, one per possible download thread. requests' default of 10 made every download past the tenth open and discard its own connection ("Connection pool is full, discarding connection").ndi.gui.app.genepyramid.multiscale.levelArrays: the same one-layer-per-level fix. Levels are still cropped to their true size.Testing
ctestpass after mergingmain: 909 passed, 196 skipped. The gene-pyramid tests includetest_a_computed_block_matches_readViewportandtest_only_the_touched_tiles_are_fetched.FileCacheall land without touchingis_file. This passes against DID-python both before and after Navigator: statusIcon, progressPane, sessionInfo #89, and fails without this change.MAX_WORKERSconnections.ruffandblackare clean.mainwith Bulk document upload with ingestion wait (NDI-matlab#1047); ctest failure values (NDI-matlab#1046) #340: everything passes, including bridge completeness and all four cloud jobs (the pyramid integration tests now read Bulk document upload with ingestion wait (NDI-matlab#1047); ctest failure values (NDI-matlab#1046) #340's rebuilt dataset). At the time of writing only the two Windows smoke tests were still running.🤖 Generated with Claude Code
https://claude.ai/code/session_01EJ9PUeM7x2vLsg8FcZQfXo