feat(snapshot): add shared CUDA CustomStorage operation layer - #12488
Conversation
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
dyn-3691-extract-shared-target-pid-cuda-customstorage-operation-layer * 'main' of https://github.com/ai-dynamo/dynamo: (192 commits) feat(frontend): add opt-in SSE keep-alive (#12453) fix(frontend): return 4xx for Backend(InvalidArgument) on streaming c… (#12036) feat(router): orchestrate conditional disagg bypass (#11725) docs: fix snapshot chart README link to relocated snapshot guide (#12469) fix(operator): allow component-scoped topology (#12448) fix(gms): support SGLang 0.5.16 memory pool API (#12445) docs: align documentation paths with site structure (#12373) fix(frontend): return 400 instead of 500 when chat template rendering fails (#12404) perf(mocker): optimize offline replay hot paths (#12341) feat(kv-router): route vLLM STORAGE KV events to the Disk tier with locality gating (#11571) ci: Publish all containers for dynamo nightly (#12280) fix(snapshot): enter PID namespace for GPU probe (#12227) docs(kubernetes): add vanilla vllm gaie on-ramp (#10957) ci(checkpoint): mount shared model-cache PVC in DynamoCheckpoint tests (#12400) feat(observability): Add embedding cache metrics (#11969) feat(request-trace): native S3 sink for request-trace records (#11806) fix(planner): resolve aggregate workers by component type (#11578) fix(examples): configure KV transfer for vLLM decode workers (#11468) fix(snapshot): exit vLLM source without engine teardown (#12184) fix(vllm): expand Kimi K3 media pads at the worker (#12394) ... Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
This comment has been minimized.
This comment has been minimized.
WalkthroughThis change adds CUDA checkpoint compatibility types, custom-storage operation management, and a standalone CUDA 13.4 round-trip benchmark. The benchmark coordinates a child workload, transfers checkpoint extents through files, validates restore behavior, and tests truncated and same-size corrupted artifacts. ChangesCUDA CustomStorage round-trip
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (6)
benchmarks/cuda_custom_storage/Makefile (2)
12-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider adding a
testtarget.checkmake reports that the required
testtarget is missing. The README already documents the exact round-trip command. Atesttarget would encode that command once and remove the duplication between the README and manual invocation. The target needs a GPU and the CUDA 13.4 driver, so document that requirement in the recipe.♻️ Proposed addition
-.PHONY: all clean +.PHONY: all clean test all: $(TARGET) + +# Requires a GPU and a CUDA driver that exposes the CUDA 13.4 CustomStorage API. +ARTIFACT_DIR ?= $(shell mktemp -d)/artifact +BYTES ?= 67108864 + +test: $(TARGET) + timeout 130s ./$(TARGET) --artifact-dir "$(ARTIFACT_DIR)" --bytes $(BYTES)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@benchmarks/cuda_custom_storage/Makefile` around lines 12 - 25, Add a `test` target to the Makefile following the existing pattern of the `all` and `clean` targets. First, add `test` to the `.PHONY` declaration alongside `all` and `clean`. Then, create a `test:` recipe that executes the round-trip command currently documented in the README, removing the duplication between documentation and the Makefile. Include a comment in the recipe documenting that the target requires a GPU and CUDA 13.4 driver to run successfully.Source: Linters/SAST tools
9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAnchor
SHARED_DIRto the Makefile location.
SHARED_DIRis relative to the working directory. The README documentsmake -C benchmarks/cuda_custom_storage, which works.make -f benchmarks/cuda_custom_storage/Makefilefrom the repository root fails, because the relative path no longer resolves. Derive the directory fromMAKEFILE_LISTso both invocations work.♻️ Proposed refactor
TARGET := cuda-custom-storage-roundtrip -SHARED_DIR := ../../deploy/snapshot/cmd/cuda-checkpoint-helper -SOURCES := roundtrip.cpp $(SHARED_DIR)/custom_storage_operation.cpp +HERE := $(dir $(lastword $(MAKEFILE_LIST))) +SHARED_DIR := $(HERE)../../deploy/snapshot/cmd/cuda-checkpoint-helper +SOURCES := $(HERE)roundtrip.cpp $(SHARED_DIR)/custom_storage_operation.cpp🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@benchmarks/cuda_custom_storage/Makefile` around lines 9 - 10, Update SHARED_DIR in the Makefile to derive its base directory from MAKEFILE_LIST rather than the caller’s working directory, while preserving the existing path to cuda-checkpoint-helper and SOURCES usage so both make invocation forms resolve correctly.benchmarks/cuda_custom_storage/roundtrip.cpp (3)
547-548: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReplace the
bool checkpointparameter with a direction enum.
CopyExtentselects two different behaviors from one boolean. The call sites readCopyExtent(..., true)at Line 624 andCopyExtent(..., false)at Line 649, so the direction is not visible without opening the function. A small enum removes that ambiguity and matches the existingCorruptionModestyle in this file.♻️ Proposed refactor
+enum class CopyDirection { + kDeviceToFile, + kFileToDevice, +}; + void -CopyExtent(const compat::PerDeviceData& device_data, CUcontext context, const fs::path& path, bool checkpoint) +CopyExtent(const compat::PerDeviceData& device_data, CUcontext context, const fs::path& path, CopyDirection direction) { CheckCUDA(cuCtxSetCurrent(context), "cuCtxSetCurrent"); + const bool checkpoint = direction == CopyDirection::kDeviceToFile;Then update the call sites:
CopyExtent(info->perDeviceData[0], context, checkpoint_file, CopyDirection::kDeviceToFile); CopyExtent(info->perDeviceData[0], context, directory / kExtentFilename, CopyDirection::kFileToDevice);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@benchmarks/cuda_custom_storage/roundtrip.cpp` around lines 547 - 548, Replace the boolean checkpoint parameter in CopyExtent with a direction enum, such as CopyDirection, defining explicit device-to-file and file-to-device values. Update CopyExtent’s branching to use the enum and change both call sites to pass the corresponding direction values instead of true or false.
768-769: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRewrite the
--bytesbranch with a real body.This branch has an empty body and performs the assignment plus the validation inside the condition.
ParseUnsignedwrites intooptions.bytesbeforeoptions.bytes > 0is evaluated, so an invalid value mutates the option and then falls through to the usage error. The behavior is correct, but the control flow is hard to follow and it is easy to break during a later edit. Parse into a local, then validate.♻️ Proposed refactor
- } else if ( - argument == "--bytes" && ++index < argc && ParseUnsigned(argv[index], &options.bytes) && options.bytes > 0) { + } else if (argument == "--bytes" && index + 1 < argc) { + ++index; + size_t bytes = 0; + if (!ParseUnsigned(argv[index], &bytes) || bytes == 0) { + throw std::runtime_error("--bytes must be a positive byte count"); + } + options.bytes = bytes; } else if (argument == "--device" && ++index < argc) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@benchmarks/cuda_custom_storage/roundtrip.cpp` around lines 768 - 769, Rewrite the --bytes branch in the argument-parsing logic to use a real block body: parse the argument into a local unsigned value, validate that parsing succeeds and the value is greater than zero, then assign the validated value to options.bytes. Preserve the existing usage-error path for missing or invalid values.
789-796: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueClose the permission window on the artifact directory.
fs::create_directoryapplies the process umask, which is commonly0022, so the directory is briefly group- and world-readable. The harness narrows it toowner_allonly on the next statement. The README targets shared GPU hosts, so another local user can open the directory during that window and later readcheckpoint.bin. Set the umask around the creation, or create the directory and immediately verify ownership before writing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@benchmarks/cuda_custom_storage/roundtrip.cpp` around lines 789 - 796, The permission window between fs::create_directory and fs::permissions allows other users to access the artifact directory. Close this window by setting the process umask to a restrictive value (such as 0077) before calling fs::create_directory on options.artifact_dir, then restore the previous umask immediately after. This ensures the directory is created with owner-only permissions from the start, eliminating the brief exposure period where the default umask (commonly 0022) would make it group- and world-readable.deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.h (1)
19-25: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a debug assertion in the destructor to enforce the documented "must exit" contract.
The comment above the class states that a caller must check
fatal()and exit instead of relying on destruction to complete the operation. Nothing in the class enforces this today. Add a destructor that asserts!fatal(). This catches contract violations during testing without changing release behavior, sinceassertis compiled out underNDEBUG.The move constructor already resets the moved-from object's state via
std::exchange, so a moved-fromOperationreportsfatal() == falseand will not trigger a false assertion.🛡️ Proposed destructor addition
Operation() = default; Operation(const Operation&) = delete; Operation& operator=(const Operation&) = delete; Operation(Operation&& other) noexcept; Operation& operator=(Operation&&) = delete; + ~Operation();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.h` around lines 19 - 25, Update the Operation class by adding a destructor that asserts !fatal(), enforcing the documented requirement that callers check fatal() and exit before destruction. Keep the existing move-constructor behavior so moved-from instances remain non-fatal, and rely on assert’s normal NDEBUG behavior for release builds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@benchmarks/cuda_custom_storage/roundtrip.cpp`:
- Around line 1-4: Add benchmarks/cuda_custom_storage/** to
.github/codeowners/areas.yaml and assign it to the same owning team used for
deploy/snapshot/cmd/cuda-checkpoint-helper. No direct changes are needed in
benchmarks/cuda_custom_storage/roundtrip.cpp (lines 1-4),
benchmarks/cuda_custom_storage/Makefile (lines 1-2), or
benchmarks/cuda_custom_storage/README.md (lines 1-4); they are covered by the
new glob.
- Around line 623-633: Move the CopyExtent call into the existing try block in
the checkpoint flow, keeping checkpoint_file available to the catch cleanup.
Ensure failures during copying or checkpoint completion remove the partial
checkpoint_file before rethrowing, while preserving the current completion and
process-state checks.
- Around line 862-876: Update the kTruncate branch to record the checkpoint
file’s actual size after resize_file and assert it equals artifact.extent.size -
1 before calling ValidateExtentFile; remove reliance on matching “wrong size” in
the caught exception, while preserving ValidateExtentFile as the rejection check
and existing success output.
- Around line 644-648: Add validation of the restored extent's device identity
in the Run function. After the existing ValidateStandaloneStorageInfo call,
extract the GPU device from the stream field in info->perDeviceData[0] and
compare it with artifact.extent.device to ensure they match. If the devices
differ, throw a std::runtime_error similar to the existing size mismatch error.
Place this device comparison check before any CopyExtent operation to validate
device identity in addition to the existing size check.
In `@deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.cpp`:
- Around line 29-38: Persist storage-shape validity so invalid adopted
checkpoints cannot be reported as successful: in
deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.cpp lines
29-38, have Operation::Adopt store the HasValidStorageShape result in
storage_shape_valid_ and return the corresponding status; in lines 68-81,
require storage_shape_valid_ before invoking complete(handle) and transfer it in
the move constructor; in
deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.h lines
32-42, add the private bool storage_shape_valid_ initialized to false.
---
Nitpick comments:
In `@benchmarks/cuda_custom_storage/Makefile`:
- Around line 12-25: Add a `test` target to the Makefile following the existing
pattern of the `all` and `clean` targets. First, add `test` to the `.PHONY`
declaration alongside `all` and `clean`. Then, create a `test:` recipe that
executes the round-trip command currently documented in the README, removing the
duplication between documentation and the Makefile. Include a comment in the
recipe documenting that the target requires a GPU and CUDA 13.4 driver to run
successfully.
- Around line 9-10: Update SHARED_DIR in the Makefile to derive its base
directory from MAKEFILE_LIST rather than the caller’s working directory, while
preserving the existing path to cuda-checkpoint-helper and SOURCES usage so both
make invocation forms resolve correctly.
In `@benchmarks/cuda_custom_storage/roundtrip.cpp`:
- Around line 547-548: Replace the boolean checkpoint parameter in CopyExtent
with a direction enum, such as CopyDirection, defining explicit device-to-file
and file-to-device values. Update CopyExtent’s branching to use the enum and
change both call sites to pass the corresponding direction values instead of
true or false.
- Around line 768-769: Rewrite the --bytes branch in the argument-parsing logic
to use a real block body: parse the argument into a local unsigned value,
validate that parsing succeeds and the value is greater than zero, then assign
the validated value to options.bytes. Preserve the existing usage-error path for
missing or invalid values.
- Around line 789-796: The permission window between fs::create_directory and
fs::permissions allows other users to access the artifact directory. Close this
window by setting the process umask to a restrictive value (such as 0077) before
calling fs::create_directory on options.artifact_dir, then restore the previous
umask immediately after. This ensures the directory is created with owner-only
permissions from the start, eliminating the brief exposure period where the
default umask (commonly 0022) would make it group- and world-readable.
In `@deploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.h`:
- Around line 19-25: Update the Operation class by adding a destructor that
asserts !fatal(), enforcing the documented requirement that callers check
fatal() and exit before destruction. Keep the existing move-constructor behavior
so moved-from instances remain non-fatal, and rely on assert’s normal NDEBUG
behavior for release builds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 45f0134f-4e5f-429d-b082-b2f5c876d276
📒 Files selected for processing (6)
benchmarks/cuda_custom_storage/Makefilebenchmarks/cuda_custom_storage/README.mdbenchmarks/cuda_custom_storage/roundtrip.cppdeploy/snapshot/cmd/cuda-checkpoint-helper/cuda_checkpoint_compat.hdeploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.cppdeploy/snapshot/cmd/cuda-checkpoint-helper/custom_storage_operation.h
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
dyn-3691-extract-shared-target-pid-cuda-customstorage-operation-layer * 'main' of https://github.com/ai-dynamo/dynamo: (50 commits) docs(cli): correct removed vLLM prefill-worker flag reference (#12581) docs(operator): reserve webhook Ignore for emergencies (#12563) ci(docs): make previews and checks match what actually publishes (#12339) refactor(vllm): organize custom encoder modules (#12416) feat(llm): Select reasoning output field via env var (#11464) feat(runtime): add TLS support to TCP request plane (#10921) fix: convert conditional disagg sglang warning to httperror 400 (#12578) feat(operator): add runtime feature gates (#12421) refactor(runtime): extract PushRouter transport seam behind StreamingDispatch trait (#12447) feat(replay): add deterministic canonical offline reports (#12363) build: bump ModelExpress to 0.5.0(OPS-7978) (#12455) fix(mocker): use logical KV tokens for decode timing (#12583) fix(examples): update Triton example for CUDA 13 + fix libdcgm copy (DYN-3697) (#12577) refactor(operator): implement composition-first DGD reconciliation (#12283) feat(frontend): add basetenkenizer backend (#12376) fix(profiler): configure rapid mocker without planner (#12573) docs(vllm): correct worker-role flags and document --kv-transfer-config (#12568) ci: add Kubernetes deploy test to nightly (#12090) fix(container): reuse pinned protoc in runtime image (#12535) feat(self-host): flip DYN_SELF_HOST_METADATA default to ON (gh-8749) (#11417) ... Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
|
/ok to test 3ac6bd3 |
|
The PR Description is stale. Besides the comments - LGTM |
Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
dyn-3691-extract-shared-target-pid-cuda-customstorage-operation-layer * 'main' of https://github.com/ai-dynamo/dynamo: (65 commits) fix(frontend): emit SGLang stream role once (#12741) docs(fern): promote v1.3.1 to current release (#12752) fix(docs): remove duplicate unscoped community-rail CSS rules (#12615) feat(operator): migrate CRD storage to v1beta1 (#11904) fix: synchronize self-benchmark capacity across DP ranks (#12021) chore(deps): bump dynamo-tokenizers to 1.8.0 (#12707) fix(frontend): preserve split UTF-8 characters (#12688) docs: align Kubernetes build selector with CLI (#12729) fix(frontend): preserve completion backend error status (#12706) fix(operator): replace snapshot pods after GMS restart (#11286) refactor(media): rename installer module, drop --packages per review fix(media): harden installer against three pre-redesign review findings fix(media): verify installs in a fresh interpreter; teach --pip-args= form test(serve): install test-time decoders at the validated bounds feat(media): explicit installer for additional media decoders docs(spica): correct kv_load_ratio support guidance (#12714) feat(operator): add experimental grove.forceScalingGroup for single-node components (#11772) fix(vllm): declare entry-stage engine_input_source in GLM-Image NIXL config (#12709) chore: bump trtllm to v1.3.0rc23 (#12532) perf: remove trtllm postprocessing workers from the args as post processing workers are not effective in dynamo (#12592) ... Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
dmitry-tokarev-nv
left a comment
There was a problem hiding this comment.
Approve from DevOps process only.
|
/ok to test 614e1c1 |
…uda-customstorage-operation-layer
…uda-customstorage-operation-layer
|
/ok to test c296a30 |
areas.yaml auto-merged; only the generated CODEOWNERS conflicted. Resolved by regenerating from the merged areas.yaml rather than hand-merging, so the committed artifact is reproducible and the workflow's regenerate-and-diff step passes. Main gained ownership entries from #12488, #12012, #11874 and #11923 while this branch was in review, plus #12361, which co-owns the docs publish workflow and the link-checker config with docs. All survive: fern-docs.yml and .lycheeignore still resolve to ops and docs. This branch's own additions survive too: CODEOWNERS carries all 23 areas and areas.yaml carries ops and process. Validation: strict full-tree gate exits 0 at 5200/5200 owned with no stale globs; 150 tests pass. Signed-off-by: Dan Gil <dagil@nvidia.com>
Overview:
Details:
Where should the reviewer start?
benchmarks/cuda_custom_storage/custom_storage_operation.{hpp,cpp}— CUDA operation ownership and completionbenchmarks/cuda_custom_storage/storage.cpp— POSIX transfer and checkpoint/restore sequencingbenchmarks/cuda_custom_storage/roundtrip.cppandworkload.cpp— controller orchestration and workload verificationRelated Issues
🔗 This PR is linked to an issue: