Skip to content

feat(racer): GPUDirect reads into client host and GPU memory - #989

Open
Jordan Olshevski (jveski) wants to merge 86 commits into
mainfrom
racer-gpudirect-reads
Open

Jordan Olshevski (jveski) wants to merge 86 commits into
mainfrom
racer-gpudirect-reads

Conversation

@jveski

@jveski Jordan Olshevski (jveski) commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Adds host-read and gpu-read RPCs to the Racer client socket. The client passes a memfd or an exported CUDA allocation with SCM_RIGHTS, and the dataplane writes the object straight into it instead of streaming bytes over the socket. For gpu-read, the dataplane checks CRC64 and the AES-GCM tag and decrypts on the GPU, reads aligned disk pages with cuFile when it can, and lands peer pages in GPU memory over RDMA using dma-buf registered device pools. The on-disk record format moves to v2 so that ciphertext starts 4 KiB aligned; v1 records still read. Also adds a Python client, a racer-vllm loader plugin, NVIDIA library injection for the dataplane, and an opt-in label that mounts the client socket into app pods. When GPUDirect Storage is not available, Racer turns off cuFile's compatibility mode and reads disk pages through its own host path, which is faster. New metrics count the disk pages that cuFile reads straight into GPU memory. cuFile reads run on four reader threads and the cuFile driver opens at startup, and the vLLM loader ends its reads on page boundaries with four in flight, so a 7B model loads from one NVMe drive at close to the drive's speed.

Comment thread clients/python/racer-vllm/tests/test_loader.py Fixed
Comment thread clients/python/racer-vllm/src/racer_vllm/loader.py
Comment thread clients/python/racer/tests/conftest.py Fixed
Comment thread clients/python/racer/tests/fakeserver.py Fixed
Comment thread clients/python/racer/tests/test_client.py Fixed
Comment thread clients/python/racer/tests/test_wire_golden.py Fixed
Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py Fixed
Comment thread clients/python/racer/tests/fakeserver.py Fixed
Comment thread clients/python/racer-vllm/src/racer_vllm/loader.py Fixed
Comment thread clients/python/racer-vllm/src/racer_vllm/loader.py Fixed
Comment thread clients/python/racer/src/racer/cuda.py Fixed
Comment thread clients/python/racer/tests/fakeserver.py Fixed
Comment thread cmd/racer-dataplane/crypto/src/lib.rs Fixed
Comment thread cmd/racer-dataplane/crypto/tests/primitives.rs Dismissed
Comment thread cmd/racer-dataplane/crypto/tests/primitives.rs Dismissed
Comment thread cmd/racer-dataplane/gpu/src/gcm.rs Dismissed
Comment thread cmd/racer-dataplane/gpu/src/gcm.rs Dismissed
Comment thread cmd/racer-dataplane/gpu/tests/gcm_core.rs Dismissed
Comment thread cmd/racer-dataplane/gpu/tests/simulation.rs Dismissed
Comment thread cmd/racer-dataplane/gpu/tests/simulation.rs Dismissed
Comment thread cmd/racer-dataplane/src/gpu.rs Dismissed
Comment thread cmd/racer-dataplane/src/read/sealed.rs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Descriptor accumulation and CUDA context, synchronization, and allocation-lifetime defects can disrupt the dataplane or cause invalid GPU accesses during model loading.

4 open issues
What changed in this PR

Adds direct reads into client-owned host and GPU memory to Racer’s object-cache path, with Python and vLLM integration and deployment support.

Changes:

  • Adds descriptor-based delivery, GPU page authentication and decryption, and aligned disk-read support.
  • Introduces a Python client and vLLM loader with GPU, host-memory, and streaming delivery modes.
  • Adds NVIDIA library injection, opt-in client socket mounts, documentation, and automated coverage.
File Description
Makefile Adds Python client and plugin test target.
internal/​racer/​workload/​workload.go Configures NVIDIA environment and CDI injection.
internal/​racer/​workload/​workload_test.go Tests NVIDIA injection modes and validation.
internal/​racer/​members/​members_test.go Updates expected workload configuration.
internal/​racer/​injector/​injector.go Adds opt-in application socket mounts.
internal/​racer/​injector/​client_socket_test.go Tests socket injection and conflict handling.
internal/​operator/​components/​racer/​webhook_test.go Verifies the additional admission webhook.
internal/​operator/​components/​racer/​dataplane_test.go Tests operator-managed NVIDIA settings.
images/​racer-dataplane/​Containerfile Adds optional CUDA-enabled image builds.
images/​racer-dataplane/​build-native-cuda.sh Builds the CUDA shim and optional kernels.
docs/​content/​reference/​racer.md Documents direct reads and deployment settings.
docs/​content/​guides/​racer-vllm.md Adds the vLLM deployment guide.
deploy/​racer/​mutating-webhook.yaml.tmpl Registers the client socket webhook.
deploy/​racer/​embed_test.go Tests the expanded webhook manifest.
deploy/​racer/​dataplane-config.yaml.tmpl Documents GPU runtime configuration options.
deploy/​racer/​config.yaml.tmpl Documents NVIDIA injection configuration.
cmd/​racer-dataplane/​src/​test_support.rs Extends cache, disk, and decryption fixtures.
cmd/​racer-dataplane/​src/​store/​tests.rs Tests aligned records and direct-read eligibility.
cmd/​racer-dataplane/​src/​security.rs Derives page keys for GPU decryption.
cmd/​racer-dataplane/​src/​read/​sealed.rs Defines sealed pages and verification reports.
cmd/​racer-dataplane/​src/​read/​dispatch.rs Dispatches sealed reads and GPU verdicts.
cmd/​racer-dataplane/​src/​read.rs Integrates direct reads with bounded acquisition.
cmd/​racer-dataplane/​src/​lib.rs Exposes the GPU module.
cmd/​racer-dataplane/​src/​http.rs Adds positioned writes from verified pages.
cmd/​racer-dataplane/​src/​error.rs Adds an unsupported-operation error.
cmd/​racer-dataplane/​src/​config.rs Parses GPU mode and staging limits.
cmd/​racer-dataplane/​src/​client/​tests.rs Integrates direct-delivery tests.
cmd/​racer-dataplane/​src/​client/​listener.rs Receives descriptors and initializes destinations.
cmd/​racer-dataplane/​src/​client/​direct.rs Defines direct sinks and host-file delivery.
cmd/​racer-dataplane/​src/​app.rs Starts and connects the GPU helper.
cmd/​racer-dataplane/​runtime/​src/​reactor/​tests.rs Tests descriptor receipt and positioned writes.
cmd/​racer-dataplane/​http/​tests/​exchanges.rs Tests descriptor-bearing HTTP requests.
cmd/​racer-dataplane/​http/​src/​connection.rs Collects descriptors while reading request headers.
cmd/​racer-dataplane/​gpu/​tests/​gcm_core.rs Checks decryption and tamper rejection.
cmd/​racer-dataplane/​gpu/​src/​gcm.rs Wraps host-emulated cryptographic operations.
cmd/​racer-dataplane/​gpu/​native/​run-kernel-emulation.sh Builds and runs CPU kernel emulation.
cmd/​racer-dataplane/​gpu/​native/​kernel_emulation.cc Emulates CUDA launch and synchronization behavior.
cmd/​racer-dataplane/​gpu/​native/​gpu_cuda.h Defines the native GPU interface.
cmd/​racer-dataplane/​gpu/​native/​gcm_kernel.cu Adds verification and decryption kernels.
cmd/​racer-dataplane/​gpu/​native/​gcm_host.c Implements serial kernel emulation.
cmd/​racer-dataplane/​gpu/​Cargo.toml Declares the GPU crate and features.
cmd/​racer-dataplane/​gpu/​build.rs Compiles the host cryptographic implementation.
cmd/​racer-dataplane/​crypto/​tests/​primitives.rs Tests offloaded key derivation and bindings.
cmd/​racer-dataplane/​crypto/​src/​lib.rs Exposes zeroized derived page keys.
cmd/​racer-dataplane/​Cargo.toml Integrates the GPU crate and CUDA feature.
cmd/​racer-dataplane/​Cargo.lock Records GPU crate dependencies.
cmd/​racer-dataplane/​alloc/​src/​slab.rs Exposes leased physical disk ranges.
clients/​python/​racer/​tests/​test_wire_golden.py Verifies direct-read protocol bytes.
clients/​python/​racer/​tests/​test_keys.py Tests canonical object-key generation.
clients/​python/​racer/​tests/​test_cuda.py Tests CUDA bindings and optional hardware operations.
clients/​python/​racer/​tests/​conftest.py Provides fake server and GPU fixtures.
clients/​python/​racer/​src/​racer/​tensors.py Adds PyTorch allocation views and copy targets.
clients/​python/​racer/​src/​racer/​keys.py Generates Racer-compatible object identities.
clients/​python/​racer/​src/​racer/​host.py Implements mapped host buffers and pinning.
clients/​python/​racer/​src/​racer/​errors.py Defines client errors and status mappings.
clients/​python/​racer/​src/​racer/​_wire.py Implements protocol encoding and validation.
clients/​python/​racer/​src/​racer/​__init__.py Exports the Python client API.
clients/​python/​racer/​README.md Documents client usage and delivery modes.
clients/​python/​racer/​pyproject.toml Defines Python client packaging.
clients/​python/​racer-vllm/​tests/​test_safetensors.py Tests tensor parsing and chunk planning.
clients/​python/​racer-vllm/​tests/​test_loader.py Tests fetching, loading, and registration.
clients/​python/​racer-vllm/​tests/​conftest.py Shares fixtures and builds sample tensor files.
clients/​python/​racer-vllm/​src/​racer_vllm/​weights.py Pipelines weight reads through GPU staging.
clients/​python/​racer-vllm/​src/​racer_vllm/​safetensors.py Parses tensor metadata and plans reads.
clients/​python/​racer-vllm/​src/​racer_vllm/​model.py Resolves model locations and fetches configuration.
clients/​python/​racer-vllm/​src/​racer_vllm/​loader.py Registers and implements the vLLM loader.
clients/​python/​racer-vllm/​src/​racer_vllm/​__init__.py Exports plugin entry points.
clients/​python/​racer-vllm/​README.md Documents plugin setup and options.
clients/​python/​racer-vllm/​pyproject.toml Declares plugin packaging and command entry points.
clients/​python/​.gitignore Excludes generated Python artifacts.
.github/​workflows/​ci.yaml Adds GPU simulation and Python checks.

Review effort: Balanced

Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py
Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py Outdated
Comment thread cmd/racer-dataplane/http/src/connection.rs Outdated
Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

GPU memory retention, loader cleanup, corruption-report delivery, and cuFile packaging remain unresolved.

3 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Close weights iterator before client shutdown

clients/​python/​racer-vllm/​src/​racer_vllm/​loader.py:73

Close weights in a finally block before leaving with client. If model.load_weights() raises after receiving a tensor, the exception traceback can retain the suspended generator, delaying the executor shutdown and GPU fences in weights.py:116-126 until the traceback is released. Background reads can then continue after the client closes. A consumer that returns without exhausting the iterator also leaves cleanup pending. Explicitly closing the iterator makes its cleanup run before client shutdown in both cases.

Medium severity Include cuFile and dependencies in the CUDA runtime image

images/​racer-dataplane/​Containerfile:95

Include the cuFile user-space library and its dependencies in the CUDA-enabled runtime image. The default ubuntu:noble final stage installs only libgcc-s1 and optional RDMA packages (lines 104-114), while this step adds only the CUDA shim. NVIDIA compute/utility injection supplies driver libraries, not the toolkit's libcufile.so.0. Consequently, the shim's dlopen (gpu/native/gpu_cuda.c:640-643) fails and the helper disables cuFile (src/gpu.rs:895-898), so even a GPUDirect Storage-capable host falls back to host-memory disk reads. Package cuFile in the final image or provide an explicit supported injection path.

3 resolved since last review

Review effort: Balanced

Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py Outdated
Comment thread cmd/racer-dataplane/src/read/dispatch.rs
Comment thread clients/python/racer-vllm/src/racer_vllm/weights.py Fixed
Comment thread cmd/racer-dataplane/src/gpu.rs Dismissed
Comment thread cmd/racer-dataplane/src/gpu.rs Dismissed
Comment thread cmd/racer-dataplane/src/gpu.rs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Cross-language GPU cryptography, native resource lifetimes, and RDMA completion guarantees require final human review and hardware-backed validation.

2 open issues
1 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

GPU fallback device selection and CDI request wiring have unresolved correctness issues.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Preserve destination CUDA device for staging registration

clients/​python/​racer/​src/​racer/​tensors.py:44

Preserve the wrapped tensor's CUDA device on this target. Both host and stream fallback call _dest_device(dest), which reads dest.device; without it, a target on cuda:3 requests new staging registration on GPU 0 (clients/python/racer/src/racer/client.py:44-50,211-219,639,680). Registration retains that GPU's primary context (cuda.py:206), so the read can fail if GPU 0 is unavailable or held by another process in exclusive-process mode, even when the destination GPU is usable. This also affects the vLLM torch-memory fallback. Expose tensor.device so staging uses the destination GPU.

2 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Native GPU cryptography and memory lifetimes require hardware-backed validation and human review, alongside resolution of the retained correctness issues.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Reject non-integer and boolean tensor metadata values

clients/​python/​racer-vllm/​src/​racer_vllm/​safetensors.py:92

The int() conversions silently truncate malformed dimensions and byte offsets. For example, a U8 entry with shape: [1.9] and data_offsets: [0.9, 1.9] is accepted as shape (1,) and offsets [0, 1]; a negative dimension of -0.5 becomes zero. These altered ranges determine reads and tensor construction in clients/python/racer-vllm/src/racer_vllm/weights.py:86,109. Require integer arrays, excluding booleans, rather than coercing the values. Add rejection tests for fractional values, numeric strings, and booleans so malformed headers raise SafetensorsError instead of loading an altered tensor layout.

Review effort: Balanced

Comment thread cmd/racer-dataplane/gpu/native/gpu_cuda.h Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Native GPU cryptography and cross-device memory lifetimes need hardware-backed validation and human review, alongside resolution of the verified cleanup failure.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread clients/python/racer/src/racer/host.py Outdated
Comment thread clients/python/racer/src/racer/cuda.py Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Descriptor association remains unresolved, and native CUDA/RDMA lifetimes and cryptographic paths need hardware-backed validation and final human review.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread cmd/racer-dataplane/http/src/connection.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The changes require final human review because they are too complex or risky for automated approval.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

…over RDMA

Requester::request_landing threads a gpu-read's GPU ordinal down to the
peer transport. When the hop is RDMA and the rail's landing buffer is
on that GPU, accept_native grants a landing slot (else host memory as
usual). A completed landing write comes back as RelayResponse::Landed,
whose signed head is checked for exactly this page (landed_response_head)
and verified against the request binding (Forwarding::verify_landed).
…path

Fill::acquire_sealed now tries land_from_peer after local disk staging:
one CopyOnly request to the first provider with the request's GPU
ordinal. A landed page becomes SealedSource::Landed and is decrypted on
the GPU; it never joins single flight, memory, or disk. A host answer
to the landing request is used once instead of fetching again. Any
other outcome takes the usual path. Adds GPU helper tests for landing
buffers and decrypting landed ciphertext.
A page landed by RDMA has no host copy or disk mapping for its owner to
drop, so routing its failed verdict to the owner only consumed a retained
verdict slot. Record the corrupt miss locally instead.
…ved with

A descriptor-aware head read could return a plain HEAD and the start of a
following descriptor-bearing request from one recvmsg. Every descriptor was
attached to the first decoded head, so the HEAD was rejected for carrying an
unexpected descriptor and neither request was served.

Linux unix_stream_read_generic merges skbs into one stream read but stops
after an skb carrying SCM_RIGHTS. A client sends a head's descriptors with
the start of that head, so descriptors from one receive belong to the last
head that starts in its bytes. The receive loop now keeps the newest chunk's
descriptors apart: earlier chunks belong to the current head, and the last
chunk does too unless bytes remain after the head ends. Otherwise they are
carried on the lease with the read-ahead and the same rule is applied when
the next head is decoded from it. Carried descriptors still count toward
MAX_HEAD_DESCRIPTORS, close with the lease or a rejected head, and a
non-descriptor head read that finds them closes them and rejects.

The http layer still rejects pipelining at exchange completion, so a
pipelined host-read after a HEAD now gets the HEAD served and the connection
closed with the carried descriptor released.

Also make the client disconnect cancellation test pump until the hangup is
observed instead of a fixed pump count; it failed under parallel load.
cuFile rejects descriptors with O_NOFOLLOW (error 5019), and Racer opens
every slab file and block device with it, so cuFile was turned off on the
first direct read. Reopen the open file through /proc/self/fd before
registering it.
Without nvidia-fs or P2PDMA, cuFile's compatibility mode reads through a
bounce buffer on the GPU helper thread. Racer's host path does the same
work on I/O threads, so prefer it unless CUFILE_ALLOW_COMPAT_MODE is set.
cuFile classifies each file's block device through udev and fails to
register files it cannot classify (error 5030). Mount the host /run/udev
read-only when NVIDIA injection is on, and install libnuma1, which cuFile
loads at runtime.
The memory cache now keeps only ciphertext, and the range probe decrypts
cached or disk ciphertext on the CPU. Sealed reads probe live plaintext
only, and acquire_sealed stages cached ciphertext from memory before
trying cuFile or a peer, so the GPU decrypts it.
Make the simulation thread safe and add GpuFile::detach and FileReader so
a prepared cuFile read can run on another thread while the helper keeps
decrypting.
The GPU helper thread ran each cuFile read synchronously, so reads and
decryption took turns and one read at a time left the drive mostly idle.
Reads now run on four reader threads. The helper keeps file
registration and frees a handle only after its last read finishes.
Opening the driver probes every GPU and took about 0.8s on an eight-GPU
B200 node. It ran on the first sealed page, so every first model load paid
for it. Open it on a separate thread at startup instead. A failed open
turns cuFile off, as a failed stage does.
Neighboring chunks used to read the page they share twice. Chunks now end
on page boundaries where they can, and a tensor that crosses one is copied
out of each chunk into its own memory.
With page-aligned chunks and parallel cuFile reads, four staging buffers load a 7B model about 7% faster than two on one NVMe drive, close to the drive's GPUDirect limit.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants