Skip to content

perf(streaming): Speed up PyTreeLoader reads with mmap and compiled unflatten#849

Merged
tchaton merged 4 commits into
mainfrom
perf/mmap-nonshared
Jul 24, 2026
Merged

perf(streaming): Speed up PyTreeLoader reads with mmap and compiled unflatten#849
tchaton merged 4 commits into
mainfrom
perf/mmap-nonshared

Conversation

@tchaton

@tchaton tchaton commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator
Before submitting
  • Was this discussed/agreed via a Github issue? (no need for typos and docs improvements)
  • Did you read the contributor guideline, Pull Request section?
  • Did you make sure to update the docs?
  • Did you write any new necessary tests?

What does this PR do?

Speeds up the StreamingDataset / PyTreeLoader read hot path for local cached chunks.

  • Memory-maps chunks that a worker owns exclusively (skips shared chunks to avoid deletion races / SIGSEGV).
  • Compiles a specialized treespec unflatten once per dataset instead of recursively rebuilding every sample.
  • Uses cheaper struct unpacking for size headers and int/float leaves.
  • Adds targeted tests for mmap parity, close/pickle safety, encryption, shared-chunk exclusion, and header mismatch.

Local microbench on 80k dict-of-leaves items (warm sequential reads): about 2.9× vs the previous stock file path (~224k → ~644k items/s).

PR review

Anyone in the community is free to review the PR once the tests have passed.
If we didn't discuss your PR in GitHub issues there's a high chance it will not be merged.

Did you have fun?

Make sure you had fun coding 🙃

@tchaton
tchaton requested a review from justusschock as a code owner July 24, 2026 12:37
The PyTreeLoader opened each chunk unbuffered and did two `seek`+`read` syscalls
per item (offset pair, then the item). Memory-mapping the chunk and caching its
offset table turns per-item reads into memory slices (~+8% single-process read
throughput on a local dataset).

mmap is applied ONLY to chunks that are safe to map: not encrypted, and NOT shared
with another worker. A shared chunk can be deleted/replaced by a co-worker while it
is still mapped, which crashes with SIGSEGV rather than a recoverable error (see
issues #459 and #756). The set of non-shared chunks is exactly the per-worker
shared-chunk analysis already computed for the deletion-race fix; shared and
encrypted chunks keep the previous unbuffered read path. The mmap allow-set
defaults to empty, so any path that does not opt in (e.g. random __getitem__
access) uses normal reads.

The map is opened/closed per chunk transition and released on teardown and when
pickled (spawn workers), so no map outlives the chunk file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tchaton
tchaton force-pushed the perf/mmap-nonshared branch from 3e188dc to e74cc74 Compare July 24, 2026 12:41
@codecov-commenter

codecov-commenter commented Jul 24, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 99.10714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81%. Comparing base (ecbb64d) to head (54d2484).
⚠️ Report is 1 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@         Coverage Diff          @@
##           main   #849    +/-   ##
====================================
  Coverage    81%    81%            
====================================
  Files        54     54            
  Lines      7736   7842   +106     
====================================
+ Hits       6268   6372   +104     
- Misses     1468   1470     +2     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Cut PyTreeLoader hot-path overhead by compiling a specialized unflatten
once per dataset, tightening non-shared mmap item reads, and covering
the new paths with targeted tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tchaton tchaton changed the title perf(streaming): memory-map non-shared chunks in PyTreeLoader perf(streaming): Speed up PyTreeLoader reads with mmap and compiled unflatten Jul 24, 2026
tchaton and others added 2 commits July 24, 2026 14:53
Replace nested closures with module-level callables so item loaders
pickle cleanly under DataLoader spawn workers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@tchaton
tchaton merged commit cd343d0 into main Jul 24, 2026
34 checks passed
@tchaton
tchaton deleted the perf/mmap-nonshared branch July 24, 2026 14:28
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.

3 participants