You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
dense_nvfp4_gemm.h caches the Marlin repack in a process-static map keyed on the weight's ADDRESS, the stale-pointer hazard ResidentSlot exists to fix #984
include/vllm/model_executor/models/dense_nvfp4_gemm.h:379-384 caches the dense Marlin repack in a process-static map keyed on the weight object's address.
An address is only a valid identity while the object lives. Across two engine builds in one process — the second engine's weights allocated where the first's used to be — a hit on that map returns the previous engine's repacked device buffer. The result is numerically plausible and silently wrong: right shapes, right dtypes, wrong values.
Why this is a known class, not a new theory
#237 exists for precisely this, and ResidentSlot is the fix it produced. qwen3_5.cpp:2429-2431 already uses ResidentSlot, and Nvfp4Weightcarries an unused resident_marlin slot — so the correct mechanism is present in the type and simply not used by the shared header.
I could not find this instance filed anywhere; #237 tracks the class and the qwen3_5.cpp call site, not dense_nvfp4_gemm.h.
Why it matters more now than when it was written
The header was, until recently, effectively single-consumer. Two things changed:
dense_nvfp4_gemm.h is a shared seam — ResidentNvfp4, MatmulNvfp4MarlinD, MatmulNvfp4W4A16D plus a policy layer at compressed_tensors/schemes/nvfp4.h. It is the seam every NVFP4 consumer is told to route through rather than hand-rolling a parallel path.
So the hazard moves from latent to reachable as the seam gains its second consumer.
What done looks like
Key the cache on ResidentSlot rather than the weight address, mirroring qwen3_5.cpp:2429-2431, and use the resident_marlin slot Nvfp4Weight already carries.
A red-before test: build two engines in one process such that the second's weight lands at a recycled address, and show the current code returns the first engine's buffer. That test is the whole value of the fix — without it this is a refactor with no evidence, and the defect is invisible to any single-engine gate.
Consider whether a structural checker belongs here, in the shape of scripts/check-fp4-resident-consistency.py, which already enforces a neighbouring obligation on ResidentNvfp4 — an address-keyed static in a shared header is a pattern worth refusing by construction rather than by review.
Found while scoping A2-Q of #810. Not fixed there: it is a behaviour change with its own gate, and folding it into a model row would land it without the two-engine test that gives it meaning.
Related: #237 (the class and ResidentSlot), #940 (the FP8 seam extraction, which deliberately left an adjacent latent defect to #974 for the same reason), #974.
Claim
include/vllm/model_executor/models/dense_nvfp4_gemm.h:379-384caches the dense Marlin repack in a process-static map keyed on the weight object's address.An address is only a valid identity while the object lives. Across two engine builds in one process — the second engine's weights allocated where the first's used to be — a hit on that map returns the previous engine's repacked device buffer. The result is numerically plausible and silently wrong: right shapes, right dtypes, wrong values.
Why this is a known class, not a new theory
#237 exists for precisely this, and
ResidentSlotis the fix it produced.qwen3_5.cpp:2429-2431already usesResidentSlot, andNvfp4Weightcarries an unusedresident_marlinslot — so the correct mechanism is present in the type and simply not used by the shared header.I could not find this instance filed anywhere; #237 tracks the class and the
qwen3_5.cppcall site, notdense_nvfp4_gemm.h.Why it matters more now than when it was written
The header was, until recently, effectively single-consumer. Two things changed:
dense_nvfp4_gemm.his a shared seam —ResidentNvfp4,MatmulNvfp4MarlinD,MatmulNvfp4W4A16Dplus a policy layer atcompressed_tensors/schemes/nvfp4.h. It is the seam every NVFP4 consumer is told to route through rather than hand-rolling a parallel path.MODEL-NEMOTRON-H(Run Nemotron-3.5-Lightning-30B-A3B-NVFP4 end to end: NemotronH hybrid (23 Mamba2 / 6 GQA / 23 non-gated relu² MoE) with a MIXED_PRECISION checkpoint #517, The paged runner's RECURRENT allocation is Qwen3.5-shaped: hybrid models are refused by the wrong model's name, and the only correct behaviour reads as a user config error #810) is about to routelm_headand 5935 expert projections through it. That is a second engine class in the same process space, which is exactly the condition the address key cannot survive.So the hazard moves from latent to reachable as the seam gains its second consumer.
What done looks like
ResidentSlotrather than the weight address, mirroringqwen3_5.cpp:2429-2431, and use theresident_marlinslotNvfp4Weightalready carries.scripts/check-fp4-resident-consistency.py, which already enforces a neighbouring obligation onResidentNvfp4— an address-keyed static in a shared header is a pattern worth refusing by construction rather than by review.Found while scoping A2-Q of #810. Not fixed there: it is a behaviour change with its own gate, and folding it into a model row would land it without the two-engine test that gives it meaning.
Related: #237 (the class and
ResidentSlot), #940 (the FP8 seam extraction, which deliberately left an adjacent latent defect to #974 for the same reason), #974.