Skip to content

feat(cudf): Serve KvikIO reads through AsyncDataCache - #18941

Open
kingcrimsontianyu wants to merge 29 commits into
facebookincubator:mainfrom
kingcrimsontianyu:kvikio_async_v2
Open

kingcrimsontianyu wants to merge 29 commits into
facebookincubator:mainfrom
kingcrimsontianyu:kvikio_async_v2

Conversation

@kingcrimsontianyu

@kingcrimsontianyu kingcrimsontianyu commented Sep 10, 2026 •

Copy link
Copy Markdown

PR description

The native KvikIO datasource bypasses Velox's I/O stack and has no cache. Every query therefore re-reads the same bytes from remote storage.

This PR wraps it in a CachingDataSource backed by AsyncDataCache. Reads are served from cache entries (with (file, offset) as the key). On a miss, the bytes are read from remote storage into a new entry. A shorter entry at the same offset is reused as a prefix, and only the rest is read from remote storage (#19126). Device reads copy through a per-thread pinned buffer to the GPU. device_read_async() fills the cache on one thread pool and copies to the GPU on a second, smaller one (cudf.kvikio_cache_copy_threads, default 16).

The wrapper is used only when the async data cache is enabled and the split is cacheable. Otherwise the native KvikIO source is returned unchanged. Also this PR forwards the split's cacheable flag and the file size Presto sends, which avoids a HEAD request per file open.

This PR also bumps KvikIO version, so that we can use per-NIC binding and non-temporal copy introduced in rapidsai/kvikio#1052.

Depends on #19126

This PR is extracted from the WXD-launch integration branch (https://github.com/rapidsai/velox/tree/WXD-launch) made by @kjmph.

Performance result

TPC-H SF1K (tpch_sf1k_v2_float_s3), g7e.48xlarge, 8x RTX PRO 6000, one worker per GPU,
fresh cluster, 3 iterations, no warmup. Seconds.
  it1 = sum over Q1-Q22 of iteration 1
  hot = sum over Q1-Q22 of min(iterations 2..3)
  Kyle ref, Kyle ref 2 : Kyle Hubert's WXD-launch matrix runs (KvikIO cases)
  WXD-launch   : Kyle's images (worker 6c657690bd6b, coordinator 6917e7f28626) and harness
                 (velox-testing d8f6a61); KvikIO direct receive REQUIRE, PER_CHUNK dispatch
  wxd-upstream : images tialiu-wxdup-1016 built from the wxd-upstream branches
                 (Velox 4b2b5e092, Presto 563e7787ee, velox-testing 99a1e35), run right after
                 WXD-launch; UCX 1.22.0, UCX exchange, SHARED_QUEUE dispatch,
                 run_tpch_g7e_48xlarge.sh
  Date = start of the run, UTC

                                 Kyle ref    Kyle ref 2  WXD-launch  wxd-upstream
Date (UTC)                       2026-09-22  2026-10-05  2026-10-16  2026-10-16
                                 01:30       23:41       15:08       15:20
Cache ON, cold       it1           56.580      67.007      63.722        69.628
                     hot           21.371      21.246      21.230        21.667
Cache ON, lukewarm   it1           36.062      41.494      39.462        40.145
                     hot           21.352      21.431      21.408        21.622
Cache OFF            it1           60.208      64.722      64.689        59.156
                     hot           55.596      56.399      57.538        52.196

@netlify

netlify Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for meta-velox canceled.

Name Link
🔨 Latest commit fb14bc5
🔍 Latest deploy log https://app.netlify.com/projects/meta-velox/deploys/6ad191b003675cb5c20c8fb6

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 10, 2026
@github-actions github-actions Bot added the cudf cudf related - GPU acceleration label Sep 10, 2026
kjmph added a commit to rapidsai/velox that referenced this pull request Sep 11, 2026
Adapt Tianyu Liu's KvikIO/AsyncDataCache implementation from Velox
PR facebookincubator#18941 to the split-reader and asynchronous lifetime interfaces.

Reuse AsyncDataCache for KvikIO-backed Hive reads so repeated object
ranges can be served from host memory. Route asynchronous device reads
with absent cache keys to a dedicated executor, and reuse pinned staging
buffers for cache-to-device copies.

Keep BufferedInput on its existing reader path. When caching is disabled
or a split is not cacheable, return the original KvikIO datasource so
its native asynchronous and batched reads remain available.

Retain read ownership through asynchronous completion, fence pending
device copies before releasing their destinations, and reject short
cache fills. Handle page-backed hits and cache-capacity fallback, and
add cache traffic counters and focused host/device tests.

Cache entries use the requested file offset rather than aligned cache
pages. Pinned staging retains its per-thread, per-device high-water
capacity until process exit; this does not add a bounded staging pool
or host-cache-only preloading.

Upstream-PR: facebookincubator#18941
Upstream-commit: a0347ef
Co-authored-by: Tianyu Liu <tialiu@nvidia.com>
kjmph added a commit to kjmph/velox-testing that referenced this pull request Sep 11, 2026
Support the cache reader adapted from Tianyu Liu's Velox PR #18941.
This change provides launcher integration for that reader.

Add an explicit kvikio-cache reader mode for workers that support the
KvikIO cache datasource. Enable AsyncDataCache while retaining KvikIO
reads, using the same host-memory budget and soft-affinity placement
as buffered-cache. Keep kvikio as the cache-disabled mode.

Apply the direct KvikIO defaults to both modes, reject AWS-only receive
and TCP MSS options, and reconcile coordinator affinity when switching
between cached and uncached readers.

Test reader selection, generated catalog properties, worker memory
budgets, affinity transitions, and incompatible launch options.

Related-PR: facebookincubator/velox#18941
kjmph added a commit to rapidsai/velox that referenced this pull request Sep 11, 2026
Our adaptation of PR facebookincubator#18941 routes synchronous device reads through
the asynchronous executor and waits for completion. A cache-hit caller
already occupying the connector executor can exhaust its threads and
deadlock waiting for its own queued work.

Perform synchronous reads inline while preserving destination-device
selection and the CUDA completion fence. Leave asynchronous scheduling
and cache selection unchanged.

Cover both synchronous overloads on a one-thread executor, verify that
synchronous reads do not enqueue work, and retain H2D completion checks.
Test empty, EOF, overflowing and null-buffer requests.

Fixes: 7c2cea7
Upstream-PR: facebookincubator#18941
kjmph added a commit to rapidsai/velox that referenced this pull request Sep 14, 2026
Cache-backed GPU reads copy received bytes from pageable cache storage
into pinned staging before transferring them to the device. Separate
registration lifetime from cache-entry lifetime so cache fills and H2D
can use the same backing storage.

Add an optional allocator-owned backing interface to AsyncDataCache and
a registered slab pool shared by the BufferedInput and KvikIO GPU
readers. Suballocate stable, page-aligned slices without moving live
entries. Grow regular slabs from 64 MiB through 128 MiB to 256 MiB, and
use dedicated page-rounded blocks for larger contiguous requests.
Inherit the allocating worker's memory policy and restrict slab reuse
to its CPU NUMA node.

Charge complete slabs to the existing root allocator and a process-wide
registration budget, including unused space and pending registrations.
Keep the feature disabled by default with a 32-GiB budget when enabled.
Tiny or pre-existing pageable entries, budget pressure, and recoverable
allocation or registration failures retain ordinary cache backing and
the staging fallback without refetching received bytes. Other CUDA and
UCX registrations are outside this budget.

Return slices on eviction, invalidation, and failed fills without
retaining idle cache pins. Cache clear preserves reusable prepared
slabs; allocator pressure and shrink reclaim empty slabs and report
only backing capacity actually freed. Keep CUDA calls and backing frees
outside cache shard and pool locks. Retain cache pins and DMA leases
through copy completion, and unregister before freeing slab storage.
Tear down backing during quiescent cache shutdown while the allocator
and CUDA remain available.

Prepare new slabs synchronously before publishing their slices. Leave
ordinary CPU caches, cache-off reads, and storage scheduling unchanged;
this does not pre-register the entire cache or move live data between
pinned and pageable tiers.

Add counters for registration, fallback, pool capacity, and H2D. Cover
shared slabs, geometric growth, fragmented reuse, clear/refill, memory
pressure accounting, invalidation, registration failures, shutdown,
concurrent leases, and outstanding DMA in both GPU readers.

Related-PR: facebookincubator#18941
kjmph added a commit to rapidsai/velox that referenced this pull request Sep 14, 2026
The KvikIO cache reader adapted from Velox PR facebookincubator#18941, with the shared
executor introduced by #116, still performs synchronous
host reads for device-read cache misses. Pending remote reads occupy
executor threads, limiting fill concurrency even when the transport can
service more requests.

Submit misses through the delegate's caller-buffer host_read_async API.
Keep pending host futures and exclusive-cache-entry waits off the
executor, and dispatch ready reads independently for cache publication
and H2D submission. Bridge the std::future interface with one readiness
thread that sleeps when idle and polls pending work at 100-microsecond
intervals. Deferred-only delegates remain supported on the executor.

Bound admitted logical reads before allocating cache entries. Reuse a
positive KVIKIO_REMOTE_IO_MAX_CONCURRENT_REQUESTS, with a limit of 64
when unset or zero. This window is separate from the transport's HTTP
request slots and does not add a byte budget or increase GPU driver
count, preload depth, or destination allocations.

Publish exclusive entries only after complete, successful fills. Drain
outstanding writes before releasing failed allocations, preserve the
destination completion fence when a future is consumed or discarded,
and retain registered sources through H2D. Keep synchronous calls inline
and preserve capacity fallback, BufferedInput dispatch, and the original
cache-off KvikIO datasource.

Add counters for admission delay, active fills, exclusive waits,
deferred delegates, and fallback. Cover concurrency beyond executor
size, bounded admission, shared fills, out-of-order completion, short
and failed reads, capacity fallback, and datasource/destination lifetime
on future discard.

Upstream-PR: facebookincubator#18941
Related-PR: #116
kjmph added a commit to rapidsai/velox that referenced this pull request Sep 14, 2026
The KvikIO read-through cache requires an entry at the requested offset
to cover the entire read. A larger request can invalidate a useful
smaller entry and fetch its bytes again, even though BufferedInput
already supports consuming smaller cached prefixes.

Use AsyncDataCache's kAllowSmaller policy for host and device reads.
Consume each cached prefix, continue lookup at the next offset, and fill
only the remaining suffix on a miss. Support contiguous and page-run
backing, and count the actual bytes served by each fragment rather than
charging the full request repeatedly.

Preserve inline synchronous reads and asynchronous device-read fills.
Retain every registered fragment through the logical read's final H2D
fence, including while a later suffix is pending. Drain submitted copies
before releasing sources after a suffix failure or discarded future.
If the remainder cannot be cached, bypass only that remainder without
refetching an already consumed prefix.

This is exact-offset fragment reuse, not general interval lookup or
compaction of cached storage. Reads beginning inside an existing entry,
or encountering a cached island beyond an uncached gap, can still fetch
overlapping bytes. Keep oversized-request bypass, pool budgets,
BufferedInput, and cache-off KvikIO behavior unchanged.

Add reused-prefix counters and tests for exact delegate offsets and
lengths, long fragment chains, mixed backing, concurrent unequal-size
readers, suffix-only fallback, failed fills, and H2D source lifetime.

Related-PR: facebookincubator#18941
kingcrimsontianyu and others added 4 commits September 22, 2026 01:49
Co-authored-by: Kyle Hubert <kjmph@users.noreply.github.com>
Co-authored-by: Kyle Hubert <kjmph@users.noreply.github.com>
@devavret

devavret commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

@kingcrimsontianyu is this ready for review?

# Conflicts:
#	CMake/resolve_dependency_modules/cudf.cmake
#	velox/experimental/cudf/connectors/hive/CudfSplitReader.cpp
kingcrimsontianyu added a commit to kingcrimsontianyu/velox that referenced this pull request Oct 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. cudf cudf related - GPU acceleration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants