fix(gms): rebind non-parameter tensors to private memory after publish - #11201
Conversation
The publisher builds the whole model inside the GMS weights pool, so fp8 KV scale attrs, quantization ranges, and other torch buffers land in the committed allocations that are remapped read-only after publish. Unlike parameters, these can be written after load (init_fp8_kv_scales on wake, range updates on the forward path), which faults with NVRM Xid 31 FAULT_RO_VIOLATION. Importers already avoid this by cloning non-parameter tensors in materialize_module_from_gms; give the publisher the same binding semantics at the end of finalize_gms_write. The GMS copies stay registered so importer materialization is unchanged, and the rebound byte count is logged to keep the duplication visible. Signed-off-by: Schwinn Saereesitthipitak <schwinns@nvidia.com>
WalkthroughAdds a ChangesNon-parameter tensor rebind
Estimated code review effort: 3 (Moderate) | ~25 minutes Related PRs: None specified. Suggested labels: gpu-memory-service, enhancement, documentation, tests Suggested reviewers: Reviewers familiar with GMS memory allocation and torch module internals. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
lib/gpu_memory_service/integrations/common/utils.py (1)
123-139: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider surfacing
rebound_bytesinGMSCommittedMemoryStats.The rebind byte count is only logged, not returned. Callers such as the TRT-LLM loader that capture
finalize_gms_write(...).committed_bytesfor metrics have no way to also track rebind overhead.♻️ Optional: add field to stats
class GMSCommittedMemoryStats: committed_bytes: int pruned_bytes: int + rebound_bytes: intreturn GMSCommittedMemoryStats( committed_bytes=int(total_bytes), pruned_bytes=int(pruned_bytes), + rebound_bytes=int(rebound_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 `@lib/gpu_memory_service/integrations/common/utils.py` around lines 123 - 139, The commit stats currently log rebound_bytes but do not expose it to callers, so add a corresponding field to GMSCommittedMemoryStats and populate it from finalize_gms_write in the common utils flow. Update the return path where GMSCommittedMemoryStats is constructed so it includes the rebound byte count alongside committed_bytes and pruned_bytes, and ensure any callers relying on finalize_gms_write can access the new field for metrics.
🤖 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 `@lib/gpu_memory_service/client/torch/module.py`:
- Around line 269-273: The tuple-handling branch in _iter_module_tensors
currently skips rebinding for immutable containers, leaving GMS-resident tensors
from tuple attributes read-only. Update the logic around the attr.isdigit() /
not isinstance(mod, torch.nn.Module) path so tuple elements are rebound to
private/writable storage just like list elements, and only keep the debug skip
for truly non-rebindable cases that are not tensor containers. Use the
_iter_module_tensors helper and its container rebinding branch to locate the
change.
In `@lib/gpu_memory_service/tests/test_module_rebind.py`:
- Around line 16-18: The tests in test_module_rebind.py only use the
requires_cuda skipif marker and are missing required repo markers. Update the
test definitions in this module to add a Lifecycle marker such as
pytest.mark.pre_merge, a test type marker such as pytest.mark.unit, and the
appropriate GPU hardware marker used by this repo (for example gpu_0), alongside
the existing requires_cuda guard. Ensure the marker additions are applied to
both test cases referenced in this file so they satisfy marker validation in CI.
---
Nitpick comments:
In `@lib/gpu_memory_service/integrations/common/utils.py`:
- Around line 123-139: The commit stats currently log rebound_bytes but do not
expose it to callers, so add a corresponding field to GMSCommittedMemoryStats
and populate it from finalize_gms_write in the common utils flow. Update the
return path where GMSCommittedMemoryStats is constructed so it includes the
rebound byte count alongside committed_bytes and pruned_bytes, and ensure any
callers relying on finalize_gms_write can access the new field for metrics.
🪄 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: ff752cad-6d23-49d1-a37f-e8d4828427d0
📒 Files selected for processing (4)
lib/gpu_memory_service/client/torch/module.pylib/gpu_memory_service/docs/mutable-state-and-memory-classes.mdlib/gpu_memory_service/integrations/common/utils.pylib/gpu_memory_service/tests/test_module_rebind.py
This comment has been minimized.
This comment has been minimized.
- Rebind tensors held in tuple attributes by rebuilding the tuple on its owner; previously they were skipped and stayed on the read-only mapping (CodeRabbit). - Only allocate the private clone on paths that bind it (Devin). - Replace the standalone fake-manager unit test with an end-to-end test in test_torch_integration.py that drives finalize_gms_write against a live GMS server, then writes to the rebound buffer/tensor-attr after the RO remap; picks up the required pytest markers and _deps conventions from that file (Devin, CodeRabbit). - Fold the design note into the PR description instead of a checked-in doc; the medium-term misc-pool plan moves to an issue. - black formatting (CI pre-commit). Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Schwinn Saereesitthipitak <schwinns@nvidia.com>
|
Pushed d782a99 addressing all review feedback:
|
Summary
Fixes fatal
NVRM Xid 31(FAULT_RO_VIOLATION ACCESS_TYPE_VIRT_WRITE) GPU faults when a GMS publisher engine writes to non-parameter tensors after publish — first hit in practice on all ranks of a Nemotron NVFP4-MoE (fp8 KV, DP8) deployment at the first wake after snapshot restore. The same fault is latent for plain sleep/wake on any--kv-cache-dtype fp8model.The problem
The publisher builds the entire model inside the GMS
weightsmemory pool, so the committed allocations contain more than parameters: torch buffers (expert_map, Mambaconv_weights, ...) and tensor attributes (fp8 KV scales_k_scale/_v_scale/_q_scale/_prob_scale, quantization ranges) are swept into the same caching-allocator segments. That sweep is intentional — a fresh importer never runsload_weights, so everything the forward pass references must be materializable from GMS.The bug is that publish semantics are uniform: after
finalize_gms_write(and after any RO reconnect — wake, restore), the whole tag is remappedCU_MEM_ACCESS_FLAGS_PROT_READ. But some captured tensors are written after load:post_kv_cache_wake_up→init_fp8_kv_scalesdoesfill_()on the fp8 scale attrs on every wake;A write through a
PROT_READmapping is a fatal MMU fault. Cold engines only avoid it by timing: every write lands inside the RW load window, and the late writers first run after a sleep/wake — or after a snapshot restore, which is how this was found. Fault forensics: Xid 31 on all ranks at first post-restore wake, fault addresses at the tail 4 KiB page of 2 MiB small-pool segments (fp8 scale blocks at the segment tail).The fix
materialize_module_from_gmsalready gives importers the right binding: parameters bind to the shared read-only mapping; buffers/tensor attrs aredetach().clone()d into ordinary CUDA memory. This PR gives the publisher the identical rule:rebind_nonparameter_tensors(new,client/torch/module.py): re-binds every GMS-resident non-parameter tensor (buffers, tensor attrs, list/tuple elements) on the publisher's model to a privatedetach().clone(); parameters stay on the shared read-only mapping. Returns bytes rebound.finalize_gms_writecalls it afterregister_module_tensors+ commit + RO remap (so GMS metadata still records the in-pool copies and importer materialization is unchanged), and logs the rebound MiB so per-model duplication stays visible.Consequences:
PROT_READfor every consumer, including snapshot-restored publishers;Notes / constraints
finalize_gms_writeexecutes at model-load time in all three integrations (vLLM/TRT-LLM/SGLang), which precedes capture.miscpool for mutable non-parameter state, converged with KV sleep/wake semantics) is deliberately not in this PR; it will be proposed separately as an issue/DEP rather than a checked-in design doc.Validation
test_finalize_gms_write_rebinds_nonparameter_tensorsinlib/gpu_memory_service/tests/test_torch_integration.py: drives the realfinalize_gms_writeflow (register → commit → RO reconnect → remap → rebind) against a live GMS server, asserts the parameter keeps its shared GMS binding while buffer/tensor-attr move to private memory with values preserved, then writes to the rebound tensors after the RO remap — the exact operation that faulted.assert not _in_gms(gms_model.scale)) when therebind_nonparameter_tensorscall is stubbed out, and passes with the fix.python -m pytest lib/gpu_memory_service/tests/test_torch_integration.py→ 5 passed on a 2×RTX 5880 Ada box.pre-commit run --all-files→ all hooks pass (black/isort/flake8/ruff/pytest-marker-report).schwinns/vllm-snapshot-nightly-overlay-gms): post-restore inference returns 200 withfinish_reason=stop, coherent output, no Xid 31, restored weights left read-only. This commit is patch-equivalent to experiment commit8ef1ab30fbfrom that validated image.AI assistance was used for this PR (review-feedback cleanup and test restructuring); all changes reviewed by the author.