Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
010a08a
docs(racer): design GPUDirect reads
jveski Oct 22, 2026
e87c899
feat(racer): add pure Python Racer client with host-read and gpu-read
jveski Oct 22, 2026
3ae47c0
feat(racer): add racer-vllm loader plugin, test target and CI job
jveski Oct 22, 2026
ada9fc7
feat(racer): inject NVIDIA driver libraries into the dataplane
jveski Oct 22, 2026
aa185e5
feat(racer): mount the client socket into labeled app containers
jveski Oct 22, 2026
d35c08c
docs(racer): document GPU reads, client socket mount, and vLLM loading
jveski Oct 22, 2026
3d9b68c
docs(racer): match vLLM guide to the racer-vllm fetch flow
jveski Oct 22, 2026
3ec5c32
docs(racer): align GPUDirect design with client fallback and NVIDIA knob
jveski Oct 22, 2026
f2fd0b4
feat(racer): expose physical extent translation on Slab
jveski Oct 22, 2026
de531aa
feat(racer): parse record prefixes and locate aligned ciphertext
jveski Oct 22, 2026
7121212
feat(racer): floor the page record unit at 4 KiB for direct reads
jveski Oct 22, 2026
78b8dfd
feat(racer): expose zeroizing XAES-256-GCM page subkey derivation
jveski Oct 22, 2026
b1c794f
feat(racer): add racer-gpu crate with C AES-GCM and CRC64 decrypt core
jveski Oct 22, 2026
e8f4cbe
feat(racer): add CUDA driver shim and GPU decrypt kernels
jveski Oct 22, 2026
3d7c602
feat(racer): add racer-gpu safe API, shim loader, and simulation backend
jveski Oct 22, 2026
c3f662a
feat(racer): add cuda feature enabling the racer-gpu native shim
jveski Oct 22, 2026
98d55e1
build(racer): add RACER_NATIVE_CUDA image build argument
jveski Oct 22, 2026
bb37e75
ci(racer): build the CUDA shim, emulate GPU kernels, and test racer-gpu
jveski Oct 22, 2026
24e83a3
docs(racer): clarify GPU AES timing note
jveski Oct 22, 2026
64241c6
feat(racer): add io_uring RecvMsg with SCM_RIGHTS and shared position…
jveski Oct 22, 2026
270f015
feat(racer): parse host-read and gpu-read requests and build direct h…
jveski Oct 22, 2026
83dffba
feat(racer): collect SCM_RIGHTS descriptors while reading request heads
jveski Oct 22, 2026
3a232ab
feat(racer): serve host-read and add the gpu-read sink seam
jveski Oct 22, 2026
9c566bc
test(racer): cover host-read and gpu-read over the client socket
jveski Oct 22, 2026
911dade
test(racer): wait for direct-read connections to close on a deadline
jveski Oct 22, 2026
881384a
fix(racer): do not mark host-read unsupported when the destination is…
jveski Oct 22, 2026
1a2be97
test(racer): align fake server with dataplane and add golden wire tests
jveski Oct 22, 2026
6239141
feat(racer): parse RACER_ENABLE_GPU and RACER_GPU_STAGING_BYTES
jveski Oct 22, 2026
ace6881
feat(racer): serve gpu-read through a process-wide GPU helper thread
jveski Oct 22, 2026
44d23d3
feat(racer): test gpu-read end to end on simulated GPUs
jveski Oct 22, 2026
a78ec79
feat(racer): document gpu-read and GPU configuration
jveski Oct 22, 2026
0fce9d9
feat(racer): simulate cuFile reads of O_DIRECT files
jveski Oct 22, 2026
4702141
feat(racer): locate v2 disk ciphertext for direct reads and derive GP…
jveski Oct 22, 2026
9cf7e03
feat(racer): deliver sealed pages to gpu-read and decrypt them on the…
jveski Oct 22, 2026
8ab58e3
test(racer): cover GPU decryption of sealed gpu-read pages
jveski Oct 22, 2026
8d20b24
chore(racer): satisfy clippy for sealed gpu-read pages
jveski Oct 22, 2026
8fc1743
docs(racer): describe GPU decryption of gpu-read pages
jveski Oct 22, 2026
aab1fff
test(racer): close pyproject.toml file handle in entry point test
jveski Oct 23, 2026
d7115b1
test(racer): assert vLLM loader register() registers only once
jveski Oct 23, 2026
54e97e1
test(racer): use a single import style for the racer module
jveski Oct 23, 2026
1b8b30e
test(racer): use consistent returns in fake server dispatch
jveski Oct 23, 2026
4bc4c32
refactor(racer): close vLLM loader clients with context managers
jveski Oct 23, 2026
903a1e3
chore(racer): add cc to NOTICE
jveski Oct 23, 2026
ca32343
fix(racer): explain ignored errors in Python CUDA finalizers
jveski Oct 23, 2026
9504276
test(racer): explain ignored wakeup errors in the fake server
jveski Oct 23, 2026
18594b5
fix(racer): record vLLM staging events on the target device stream
jveski Oct 23, 2026
59f3055
fix(racer): fence GPU work before releasing vLLM staging targets
jveski Oct 23, 2026
81c5031
fix(racer): bind the allocation's CUDA context for host copies
jveski Oct 23, 2026
19e4615
fix(racer): cap descriptors received across a request head
jveski Oct 23, 2026
394b6bb
fix(racer): close vLLM weights iterator before closing the client
jveski Oct 23, 2026
0dd0544
fix(racer): release dedicated GPU targets as soon as they are consumed
jveski Oct 23, 2026
15d57bc
fix(racer): retain failed GPU verdicts the owner mailbox cannot carry
jveski Oct 23, 2026
bbae30c
fix(racer): ship cuFile library in CUDA dataplane image
jveski Oct 23, 2026
71450b0
feat(racer): add dma-buf device page pools to rdma-verbs
jveski Oct 23, 2026
4cb3673
feat(racer): back simulated GPU staging with a memfd a dma-buf export…
jveski Oct 23, 2026
f1ad90b
feat(racer): GPU landing buffers for RDMA and decrypt from them
jveski Oct 23, 2026
aa9f79f
feat(racer): register GPU landing buffers on RDMA rails and grant int…
jveski Oct 23, 2026
fdf0b57
feat(racer): receive a requested peer page into a GPU landing buffer …
jveski Oct 23, 2026
c6b7522
feat(racer): land gpu-read peer pages in GPU memory through the fill …
jveski Oct 23, 2026
f2f5183
test(racer): cover gpu-read peer landing through the fill path
jveski Oct 23, 2026
501a2b7
test(racer): land a native peer page in GPU memory over simulated RDMA
jveski Oct 23, 2026
7d8d677
docs(racer): describe GPUDirect RDMA landing and rdma-verbs device pools
jveski Oct 23, 2026
e1fdda5
chore(racer): satisfy clippy for GPU landing receive
jveski Oct 23, 2026
d966c26
fix(racer): settle failed landed GPU verdicts on the reading worker
jveski Oct 23, 2026
abfd8cb
docs(racer): describe RACER_GPU_STAGING_BYTES as per-GPU read staging
jveski Oct 23, 2026
7110a4d
refactor(racer): drop dead assignment in vLLM weight stream cleanup
jveski Oct 23, 2026
db672ba
fix(racer): stage torch tensor targets on their own GPU
jveski Oct 23, 2026
8bdbf05
fix(racer): retain host copy sources until GPU stream sync
jveski Oct 23, 2026
8f3e796
fix(racer): reject non-integer safetensors shapes and offsets
jveski Oct 23, 2026
032f4e3
fix(racer): release host registration exports when pinning fails
jveski Oct 23, 2026
41f8f6e
refactor(racer): drop the host registration ctypes export explicitly
jveski Oct 23, 2026
6b20bc8
fix(racer): attach received descriptors to the request head they arri…
jveski Oct 23, 2026
aada0b3
refactor(racer): build the derived GCM nonce from the XAES nonce dire…
jveski Oct 23, 2026
2fce902
fix(racer): reopen slab descriptors without O_NOFOLLOW for cuFile
jveski Oct 23, 2026
70f6c27
fix(racer): turn off cuFile compatibility mode by default
jveski Oct 23, 2026
64a8fac
fix(racer): give cuFile the udev database and libnuma
jveski Oct 23, 2026
7730f3e
feat(racer): count GPUDirect disk reads
jveski Oct 23, 2026
613331f
fix(racer): do not retry a failed cuFile driver open
jveski Oct 23, 2026
11a50eb
fix(racer): decrypt cached ciphertext on the GPU for gpu-read
jveski Oct 23, 2026
ac56411
docs(racer): describe gpu-read with a ciphertext-only memory cache
jveski Oct 23, 2026
0bb9061
feat(racer): run cuFile reads off the GPU helper thread
jveski Oct 23, 2026
7a543eb
perf(racer): read slabs into GPU staging on four reader threads
jveski Oct 23, 2026
ee71612
perf(racer): open the cuFile driver when the GPU helper starts
jveski Oct 23, 2026
5f979a8
perf(racer): end vLLM loader chunks on Racer page boundaries
jveski Oct 23, 2026
d0a8472
docs(racer): describe cuFile reader threads and the eager driver open
jveski Oct 23, 2026
f0a94a1
perf(racer): keep four vLLM loader reads in flight by default
jveski Oct 23, 2026
682c723
perf(racer): fill a GPU read's whole window directly
jveski Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
74 changes: 74 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,69 @@ jobs:
if [ -n "$VERBS_FEATURES" ]; then features=(--features "$VERBS_FEATURES"); fi
timeout --signal=TERM --kill-after=10s 300s cargo +1.96.0 test --locked --manifest-path cmd/racer-dataplane/Cargo.toml -p rdma-verbs --no-default-features "${features[@]}"

racer-gpu:
name: Racer GPU (${{ matrix.configuration }})
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- configuration: no-default-features
features: ""
native: false
- configuration: simulation
features: simulation
native: false
- configuration: native
features: native
native: true
- configuration: native-and-simulation
features: native,simulation
native: true
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/bin/racer-gpu-cargo
CARGO_BUILD_JOBS: "2"
GPU_FEATURES: ${{ matrix.features }}
LD_LIBRARY_PATH: ${{ github.workspace }}/bin/racer-gpu-native
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up pinned Rust
run: timeout --signal=TERM --kill-after=10s 300s rustup toolchain install 1.96.0 --profile minimal --component rustfmt,clippy

# No CUDA toolkit on hosted runners: the shim builds without decrypt
# kernels and loads without a driver. Kernel math is covered by the
# C-core tests below and the kernel emulation step.
- name: Compile CUDA shim without kernels (not hardware validation)
if: matrix.native
run: timeout --signal=TERM --kill-after=10s 300s sh images/racer-dataplane/build-native-cuda.sh cmd/racer-dataplane/gpu/native bin/racer-gpu-native/libracer_gpu_cuda.so.1

- name: Require CUDA shim ABI and symbols (no hardware)
if: matrix.native
run: timeout --signal=TERM --kill-after=10s 300s cargo +1.96.0 test --locked --manifest-path cmd/racer-dataplane/Cargo.toml -p racer-gpu --no-default-features --features "$GPU_FEATURES" --lib ffi::tests::required_native_shim_loads_abi_and_symbols -- --exact --ignored

- name: Run decrypt kernels on the CPU (kernel emulation)
if: matrix.native
run: timeout --signal=TERM --kill-after=10s 300s sh cmd/racer-dataplane/gpu/native/run-kernel-emulation.sh bin/racer-gpu-emulation

- name: Check GPU formatting
run: timeout --signal=TERM --kill-after=10s 300s cargo +1.96.0 fmt --manifest-path cmd/racer-dataplane/Cargo.toml -p racer-gpu --check

- name: Strict GPU Clippy
run: |
features=()
if [ -n "$GPU_FEATURES" ]; then features=(--features "$GPU_FEATURES"); fi
timeout --signal=TERM --kill-after=10s 300s cargo +1.96.0 clippy --locked --manifest-path cmd/racer-dataplane/Cargo.toml -p racer-gpu --all-targets --no-default-features "${features[@]}" -- -D warnings

# Includes the C AES-GCM/CRC core check against racer-crypto (16 MiB pages).
- name: Test GPU crate without requiring GPU hardware
run: |
features=()
if [ -n "$GPU_FEATURES" ]; then features=(--features "$GPU_FEATURES"); fi
timeout --signal=TERM --kill-after=10s 300s cargo +1.96.0 test --locked --manifest-path cmd/racer-dataplane/Cargo.toml -p racer-gpu --no-default-features "${features[@]}"

runtime-miri:
name: Runtime Miri (${{ matrix.group }})
runs-on: ubuntu-24.04
Expand Down Expand Up @@ -392,6 +455,17 @@ jobs:
- name: Provision envtest and run controller API-server race tests
run: timeout --signal=TERM --kill-after=10s 300s make racer-envtest-ci

racer-python:
name: Racer Python Client
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Run Python client and vLLM plugin tests
run: timeout --signal=TERM --kill-after=10s 540s make racer-python-test

# ---------- Orca Integration Tests ----------
# Spins up Garage and Azurite via testcontainers-go and runs the
# orca in-process integration suite (internal/orca/inttest). Docker
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,15 @@ racer-server-test: ## Lint and race-test the Racer server

racer-test: racer-server-test ## Check the Racer controller

RACER_PY_VENV ?= $(CURDIR)/tmp/racer-python-venv

.PHONY: racer-python-test
racer-python-test: ## Run the Racer Python client and vLLM plugin tests (no GPU needed)
@test -x "$(RACER_PY_VENV)/bin/pytest" || { timeout --signal=TERM --kill-after=10s 120s python3 -m venv "$(RACER_PY_VENV)" && \
timeout --signal=TERM --kill-after=10s 300s "$(RACER_PY_VENV)/bin/pip" install -q pytest; }
cd clients/python/racer && PYTHONPATH=src timeout --signal=TERM --kill-after=10s 300s "$(RACER_PY_VENV)/bin/pytest" -q -p no:cacheprovider
cd clients/python/racer-vllm && PYTHONPATH=src:../racer/src timeout --signal=TERM --kill-after=10s 300s "$(RACER_PY_VENV)/bin/pytest" -q -p no:cacheprovider

$(SETUP_ENVTEST):
@mkdir -p bin tmp/envtest-tools
TMPDIR="$(CURDIR)/tmp/envtest-tools" GOBIN="$(CURDIR)/bin" timeout --signal=TERM --kill-after=10s 300s $(GOCMD) install sigs.k8s.io/controller-runtime/tools/setup-envtest@$(SETUP_ENVTEST_VERSION)
Expand Down
9 changes: 9 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ notices:
link: https://docs.rs/crate/base64/0.22.1/source/LICENSE-APACHE
- name: MIT License
link: https://docs.rs/crate/base64/0.22.1/source/LICENSE-MIT
- dependency: cc
ecosystem: cargo
copyright:
- Copyright (c) 2014 Alex Crichton
license:
- name: Apache License, Version 2.0
link: https://docs.rs/crate/cc/1.5.1/source/LICENSE-APACHE
- name: MIT License
link: https://docs.rs/crate/cc/1.5.1/source/LICENSE-MIT
- dependency: chacha20poly1305
ecosystem: cargo
copyright:
Expand Down
5 changes: 5 additions & 0 deletions clients/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__pycache__/
*.egg-info/
.pytest_cache/
build/
dist/
83 changes: 83 additions & 0 deletions clients/python/racer-vllm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# racer-vllm

A vLLM plugin that loads model weights from a Racer cache. It adds the load
format `racer`. It uses the `racer-client` package.

## Install

```
pip install ./clients/python/racer ./clients/python/racer-vllm
```

vLLM finds the plugin through the `vllm.general_plugins` entry point. It was
written for vLLM v0.25.x.

## Model location

A model lives at `racer://<cache>/<bucket>/<prefix>`. The plugin reads
objects through `/run/racer/<cache>/client/socket`. Set `RACER_SOCKET` to use
another socket. Object keys follow racer-object, so `<bucket>/<prefix>/<file>`
names the S3 object.

## Use

vLLM reads the model config and tokenizer before it loads weights, so these
small files must be on local disk first. Fetch them, for example in an init
container:

```
racer-vllm-fetch racer://models/my-bucket/llama-3-8b /models/llama-3-8b
```

This copies `config.json`, tokenizer files, `model.safetensors.index.json`
and similar files, plus small files named in the index metadata. It also
writes `racer-model.json`, which tells the loader where the weights are.

Then start vLLM on that directory:

```
vllm serve /models/llama-3-8b --load-format racer \
--model-loader-extra-config '{"staging_bytes": 268435456, "concurrency": 4}'
```

Extra config keys, all optional:

| Key | Default | Meaning |
|---|---|---|
| `uri` | from `racer-model.json` | The `racer://` model location. |
| `staging_bytes` | 256 MiB | Size of each GPU staging buffer. |
| `concurrency` | 4 | Staging buffers, and reads in flight. |
| `clone` | true | Copy each tensor out of staging before handing it to vLLM. |
| `socket` | none | Client socket path. |
| `use_vmm` | true | Allow exportable `cuMemCreate` staging, needed for `gpu-read`. |

On fast local disks, more reads in flight help only when the dataplane also
fetches further ahead. Set `concurrency` to 8 together with a larger
`RACER_RANGE_WINDOW_PAGES` and `RACER_GPU_STAGING_BYTES` on the dataplane. See
the GPU reads section of the Racer reference.

## How it loads

1. Find the safetensors files from `model.safetensors.index.json`, or use
`model.safetensors`.
2. For each file, read the 8-byte header length and the JSON header.
3. Group tensors into ranges that fit a staging buffer. Each range ends on a
Racer page boundary (16 MiB), so no page is read twice. A tensor that
crosses the boundary is split across two ranges and joined again before vLLM
sees it. Read each range into
GPU memory with `gpu-read`. If the dataplane cannot do that, use
`host-read` into pinned memory and copy, else the normal stream.
4. Give each tensor (right dtype and shape) to `model.load_weights`. While
vLLM uses one buffer, the next range is read into another.

A tensor bigger than a staging buffer gets its own GPU allocation.

With `clone` set to false, tensors are views into staging memory. They stay
valid only until vLLM asks for the next tensors after the buffer's last one.
Only use this when the model copies each weight at once.

## Tests

```
make racer-python-test
```
27 changes: 27 additions & 0 deletions clients/python/racer-vllm/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"

[project]
name = "racer-vllm"
version = "0.1.0"
description = "vLLM model loader that reads weights from a Racer cache"
readme = "README.md"
license = { text = "Apache-2.0" }
requires-python = ">=3.10"
dependencies = ["racer-client"]

[project.optional-dependencies]
test = ["pytest"]

[project.entry-points."vllm.general_plugins"]
racer = "racer_vllm:register"

[project.scripts]
racer-vllm-fetch = "racer_vllm.model:main"

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
testpaths = ["tests"]
8 changes: 8 additions & 0 deletions clients/python/racer-vllm/src/racer_vllm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
"""vLLM plugin that loads model weights from a Racer cache."""

from .loader import LOAD_FORMAT, register
from .model import ModelURI, fetch, parse_uri

__all__ = ["LOAD_FORMAT", "ModelURI", "fetch", "parse_uri", "register"]
97 changes: 97 additions & 0 deletions clients/python/racer-vllm/src/racer_vllm/loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
"""vLLM model loader for --load-format racer.

Targets vLLM v0.25.x. The loader interface used is
vllm/model_executor/model_loader/base_loader.py (BaseModelLoader with
download_model(model_config) and load_weights(model, model_config)), and
registration uses register_model_loader from
vllm/model_executor/model_loader/__init__.py. Recent main adds optional hooks
(get_external_weight_memory, create_model) with defaults, so this loader
works there too.
"""

from __future__ import annotations

import logging

from .model import client_for, resolve_uri, weight_files
from .weights import DEFAULT_DEPTH, DEFAULT_STAGING_BYTES, TorchBackend, iter_weights

log = logging.getLogger(__name__)

LOAD_FORMAT = "racer"
_registered = False


def _settings(extra: dict) -> dict:
return {
"staging_bytes": int(extra.get("staging_bytes", DEFAULT_STAGING_BYTES)),
"concurrency": int(extra.get("concurrency", DEFAULT_DEPTH)),
"clone": bool(extra.get("clone", True)),
"socket": extra.get("socket"),
"use_vmm": bool(extra.get("use_vmm", True)),
}


def make_loader_class(base):
class RacerModelLoader(base):
"""Loads safetensors weights from a Racer cache.

model_loader_extra_config keys:
uri racer://<cache>/<bucket>/<prefix>; optional when the
model directory has racer-model.json (racer-vllm-fetch)
staging_bytes size of each GPU staging buffer (default 256 MiB)
concurrency number of staging buffers and reads in flight (default 4)
clone copy each tensor out of staging (default true)
socket client socket path (else RACER_SOCKET, else the cache)
use_vmm allow exportable cuMemCreate staging (default true)
"""

def __init__(self, load_config):
super().__init__(load_config)
self.extra = dict(getattr(load_config, "model_loader_extra_config", None) or {})
self.settings = _settings(self.extra)

def _client(self, model_config):
uri = resolve_uri(str(model_config.model), self.extra)
client = client_for(uri, self.settings["socket"], staging_bytes=self.settings["staging_bytes"])
return uri, client

def download_model(self, model_config) -> None:
# Nothing to download; check the weights are reachable.
uri, client = self._client(model_config)
with client:
weight_files(client, uri)

def load_weights(self, model, model_config) -> None:
uri, client = self._client(model_config)
s = self.settings
with client:
backend = TorchBackend(clone=s["clone"], use_vmm=s["use_vmm"])
weights = iter_weights(client, uri, backend, s["staging_bytes"], s["concurrency"])
try:
loaded = model.load_weights(weights)
finally:
# Run the generator's cleanup (executor shutdown and GPU
# fences) before the client closes, even if load_weights
# raised or returned without exhausting the iterator.
weights.close()
if loaded is not None and getattr(model_config, "quantization", None) is None:
missing = {n for n, _ in model.named_parameters()} - set(loaded)
if missing:
raise ValueError(f"racer loader: weights not loaded: {sorted(missing)[:10]}")

return RacerModelLoader


def register() -> None:
"""vllm.general_plugins entry point. Safe to call more than once."""
global _registered
if _registered:
return
from vllm.model_executor.model_loader import register_model_loader
from vllm.model_executor.model_loader.base_loader import BaseModelLoader

register_model_loader(LOAD_FORMAT)(make_loader_class(BaseModelLoader))
_registered = True
Comment thread
jveski marked this conversation as resolved.
Loading
Loading