Skip to content

perf(scan): intra-file decode parallelism + per-execution kernel cache + FlatReader decode memo#60

Closed
lukekim wants to merge 3 commits into
spiceai-53from
lukim/scan-improvements
Closed

perf(scan): intra-file decode parallelism + per-execution kernel cache + FlatReader decode memo#60
lukekim wants to merge 3 commits into
spiceai-53from
lukim/scan-improvements

Conversation

@lukekim

@lukekim lukekim commented Jun 12, 2026

Copy link
Copy Markdown

Three scan-path performance changes (correctness-proven + unit-tested), off the a677d11 pin (an ancestor of spiceai-53), applying cleanly onto spiceai-53.

1. Intra-file decode parallelism (vortex-layout/src/scan/split_by.rs)

SplitBy::Layout produced one split per chunk → a well-compacted file decoded a full-column scan on a single core. subdivide_large_spans divides any inter-boundary span over IDEAL_SPLIT_SIZE (100K rows) into evenly-spaced row-range sub-splits. Exact-coverage (only inserts interior points; half-open ranges stay contiguous, non-overlapping, every row once); property test + layout tests pass.

2. Per-execution ArrayKernels cache (vortex-array/src/executor.rs, optimizer/kernels.rs)

The decode/compute loop did a session clone + sharded DashMap ArrayKernels probe per array node per iteration, for an execution-invariant value. Resolved once via ArrayKernels::snapshot() (ArcSwap::load_full) on ExecutionCtx; removes the per-node lock. Kernel-path tests pass.

3. FlatReader decode memoization (vortex-layout/src/layouts/flat/reader.rs)

A column referenced by BOTH the WHERE filter and the SELECT projection went through array_future() twice → decoded the chunk twice. Memoize the shared decode in a OnceLock<SharedArrayFuture> (mirroring DictReader::values_array); the segment is still re-requested per call for prioritization, only the decode is cached. Bounded by reader lifetime (readers held via Weak in the opener), so it does not reintroduce the unbounded retention that prompted the prior cache removal. Flat-reader tests pass.

cargo check/clippy -p vortex-array -p vortex-layout clean. Validated end-to-end in spiceai 3-node CH-benCH.

Change 1: resolve ArrayKernels once at ExecutionCtx construction (a cheap
KernelSnapshot holding the two registry maps via ArcSwap::load_full) instead
of cloning the session and probing the sharded DashMap on every array node in
the execute_until / single-step paths. ArrayKernels is a global TypeId-keyed
registry populated at session construction and never mutated mid-scan, so the
cached value is invariant for one execution.

Change 2: SplitBy::Layout now sub-divides any chunk-boundary span wider than
IDEAL_SPLIT_SIZE into evenly sized row-range splits, so files with few large
chunks decode across multiple cores. Subdivision only inserts points strictly
between existing adjacent boundaries, so the half-open ranges consumers derive
remain a contiguous, non-overlapping, exact partition of the same rows.
Copilot AI review requested due to automatic review settings June 12, 2026 17:22
@lukekim lukekim self-assigned this Jun 12, 2026
@lukekim lukekim added the enhancement New feature or request label Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets scan/execution hot paths by increasing parallelism when splitting scans by layout chunk boundaries and by removing per-node session/kernel lookups inside the executor loop via a per-execution kernel snapshot.

Changes:

  • Subdivide large chunk-boundary spans into multiple row-range splits to improve intra-file decode parallelism (SplitBy::Layout).
  • Add ArrayKernels::snapshot() and a KernelSnapshot view to avoid repeated session probes.
  • Cache the KernelSnapshot in ExecutionCtx and use it in execute_parent resolution.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
vortex-layout/src/scan/split_by.rs Adds subdivide_large_spans and applies it to SplitBy::Layout to improve parallel decoding of large spans.
vortex-array/src/optimizer/kernels.rs Introduces KernelSnapshot and ArrayKernels::snapshot() to cheaply capture registry state.
vortex-array/src/executor.rs Caches the kernel snapshot in ExecutionCtx and uses it to avoid repeated session/kernel lookups in hot loops.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread vortex-array/src/executor.rs Outdated
Comment thread vortex-array/src/optimizer/kernels.rs Outdated
lukekim added 2 commits June 12, 2026 13:15
…subdivision

- Correct ArrayKernels/ExecutionCtx docs flagged by review: the registry is
  session-scoped and mutable via public register_* methods; an ExecutionCtx
  sees a point-in-time snapshot taken at construction, and later
  registrations are picked up by the next context.
- Narrow KernelSnapshot and ArrayKernels::snapshot() to pub(crate) and drop
  the unused reduce_parent half of the snapshot (the optimizer still probes
  the live registry).
- Document the SplitBy::Layout sub-division behavior on the enum variant.
- Use saturating_add in subdivide_large_spans against the u64::MAX edge and
  add a boundary regression test; add an end-to-end vortex-file test that a
  250k-row single flat chunk scans correctly across sub-divided splits.

Signed-off-by: Luke Kim <80174+lukekim@users.noreply.github.com>
@lukekim

lukekim commented Jun 12, 2026

Copy link
Copy Markdown
Author

Splitting this into two independent PRs: #61 (per-ExecutionCtx ArrayKernels snapshot) and #62 (sub-split large chunk spans, plus fixed-size RowCount and string-chunk e2e tests). Both incorporate the review feedback addressed here (point-in-time snapshot doc semantics, pub(crate) narrowing, saturating arithmetic, added tests).

@lukekim lukekim closed this Jun 12, 2026
@lukekim lukekim changed the title perf(scan): intra-file decode parallelism + per-execution ArrayKernels cache perf(scan): intra-file decode parallelism + per-execution kernel cache + FlatReader decode memo Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/performance A performance improvement enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants