Repository navigation
gpu, gpu-gates: the nemotron_h resident bytes count every buffer, one owner for the zero-context refusal, the serve gate's checks return their status - #277
Conversation
There was a problem hiding this comment.
Verdict: MUST_FIX: the same K-gemv buffer undercount remains on the sibling Qwen paths.
Must fix
1. Include the K-gemv IDs in both Qwen resident totals
body35.rs:3195 and body.rs:1024 omit self.k.q35. Every Body35 load enables those kernels; Qwen3 enables them when its sites require them. A successful load allocates eight u32 IDs, but neither body total counts them. GpuModel::resident_bytes() sums these totals, so its result and the load records underreport by 32 bytes on those loads [derived]. This is the same defect this PR fixes for Nemotron.
Reuse the new owner now to avoid another accounting repair per model. Append this term to both linked resident_bytes sums:
+ self.k.q35.as_ref().map_or(0, |k| k.kgemv.device_bytes())Non-blocking
⚠ Add a resident-byte regression check: gate_nemotron_serve.rs:344 checks load metadata but never checks resident_bytes. Removing either new accounting term leaves every clause green. Assert the recorded total against an independently derived allocation sum and show that the omitted-term mutant fails. Establishing that check now prevents this fix from regressing silently.
Checked
Duplicates: the two new byte-count methods cover different owned buffers. Dryer reported 0 pairs.
Complexity: crapper flagged no functions; the gate refactor adds no branches.
Silent failure: missing plan context, listen failures, log-read defaults and request errors reach a failed check or an error.
Tests: clauses unchanged. Returned failures remain false through the caller's &= accumulation and reach checks_failed; removing either accounting addition escapes the serve gate.
Gates: no pins, thresholds or cases changed. The common loader rejects zero context before the sole Nemotron body-load call.
Performance: changed accounting runs outside decode and prefill; no kernel or dispatch work changed.
Escape catalog: no patterns matched.
Notes
Dryer excluded gpu-gates; manual Grep covered the changed helpers.
The reported card runs omit the model-file identity required by CONTRIBUTING.md; GPU evidence is incomplete. No build or hardware gate ran locally.
Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu/src/arch/nemotron_h/body.rs, crates/gpu/src/arch/nemotron_h/step.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
There was a problem hiding this comment.
Verdict: MUST_FIX: The same K-gemv resident-byte omission remains on the GLM and MiMo paths.
Must fix
1. Count the K-gemv ids on the remaining model paths
Kind A. crates/gpu-deepseek41/src/block.rs:236 allocates a separate KGemvKernels for each loaded K-block kernel set. A GLM or MiMo file with a K-quant dense block reaches this allocation, but crates/gpu-glm5next/src/body.rs:2367 and crates/gpu-mimo2/src/body.rs:1210 omit it. Their load records omit eight u32 ids, or 32 bytes [derived] per loaded kernel set. BlockScratch::bytes() counts a separate one-id allocation. This is the same omission on sibling paths of this fix PR.
Closing this sibling path now avoids another correction of the same allocation.
In crates/gpu/src/site.rs, keep the existing documentation and expose the new owner across crates:
pub fn device_bytes(&self) -> usize {
self.one.num_bytes()
}Add this method inside the existing impl KBlockKernels in crates/gpu-deepseek41/src/block.rs:
/// Device bytes held beside the kernel modules.
pub fn device_bytes(&self) -> usize {
self.gemv.device_bytes()
}Replace GLM's ChainBody::resident_bytes:
fn resident_bytes(&self) -> usize {
self.store_bytes()
+ self.scratch_bytes()
+ self.prompt.bytes()
+ self
.taps
.as_ref()
.map_or(0, |t| t.iter().map(DeviceBuffer::num_bytes).sum())
+ self
.nextn
.as_deref()
.map_or(0, |n| n.resident_bytes() + n.arena_bytes())
+ self.k.block.as_ref().map_or(0, KBlockKernels::device_bytes)
}Replace MiMo's ChainBody::resident_bytes:
fn resident_bytes(&self) -> usize {
self.store_bytes()
+ self.scratch_bytes()
+ self.prompt.bytes()
+ self
.taps
.as_ref()
.map_or(0, |t| t.iter().map(DeviceBuffer::num_bytes).sum())
+ self.k.block.as_ref().map_or(0, KBlockKernels::device_bytes)
}Non-blocking
⚠ Assert the corrected byte count: crates/gpu/src/arch/nemotron_h/step.rs:194 adds the Mamba scratch term, but gate_nemotron_e2e.rs:500 only prints the total. Deleting this term leaves its assertions green. Add an expected-byte assertion to the existing gate and show FAIL-first with the term removed; this prevents the same omission from returning.
Checked
Duplicates: the two new accounting methods sum their owners' buffers. Dryer reported 0 pairs.
Complexity: crapper flagged no function; the gate refactor preserves predicates and branch order.
Silent failure: a listen failure returns (None, false); run() combines returned statuses and rejects a failed check.
Tests: deleting the added Mamba byte term leaves the e2e gate's assertions unchanged; its only use of the total is printing.
Gates: no bands, thresholds or clauses removed or relaxed. GpuModel::load_blocks rejects zero context before invoking the body callback.
Escape catalog: no C1–C4 pattern matched.
Performance: accounting and gate code; no added work per token.
Notes
Static review only; no builds or GPU gates run here.
Dryer excluded gpu-gates from its scan.
The supplied GPU evidence omits the model file identity required by CONTRIBUTING.md.
Card check: needs-gpu. This pull request changes crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu/src/arch/nemotron_h/body.rs, crates/gpu/src/arch/nemotron_h/step.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
…mba-2 scratch and the gemv ids, the loader owns the zero-context refusal, the serve gate's checks return their status Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt bytes count the K-block gemv ids Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: CLEAN: No must-fix finding remains; recurrence coverage for resident-byte accounting is non-blocking.
Non-blocking
⚠ Guard the resident-byte correction against recurrence: crates/gpu/src/arch/nemotron_h/step.rs:194.
The Nemotron end-to-end gate only prints the byte total. The serve gate's load checks assert architecture, slots, layers and context, but not resident bytes.
Removing the Mamba scratch term or the new K-gemv term leaves these assertions unchanged. Extend the existing load clause with an independently derived total and show FAIL-first to protect this correction.
Checked
Duplicates: the 3 new byte-count methods count distinct owned buffers or delegate to their owner.
Complexity: no decision branches were added.
Silent failure: absent optional kernels contribute zero; missing context or records, failed requests and a missing listener reach gate failure.
Tests: static comparison confirms the 6 check-call conditions and their order are unchanged. Removing either Nemotron byte-count addition has no total assertion to fail.
Gates: no pins, thresholds or clauses moved or were removed.
Adversarial checks: ctx=0 is refused before Body::load; a failed check stays false after later passing checks; a listener failure returns a failed status before completion checks are skipped.
Performance: the changes affect host accounting and gate orchestration; decode and prefill launches, copies and reduction order are unchanged.
Escape catalog: no patterns matched.
Notes
CUDA gates were not run during validation. The reported GPU runs omit the resolved model-file path required by CONTRIBUTING.md.
Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/block.rs, crates/gpu-gates/src/bin/gate_nemotron_serve.rs, crates/gpu-glm5next/src/body.rs … and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
Follow-up to #259: the three findings of Shingler's review of #259 at 2b2b19d, which landed after the merge.
What it changes.
Body::resident_bytescounts the Mamba-2 scratch (Mamba2Scratch::device_bytes:partanddone) and the gemvids (
KGemvKernels::device_bytes:one). Theloadrecord'sresident_bytesread 3,904 bytes short on Nemotron3 Nano 4B [derived in the review].
Body::loadno longer refuses a context of 0 itself:GpuModel::load_blocksrefuses it before the body loads, sothe branch could not run (R14).
gate_nemotron_serve's check functions return their status (Result<bool, _>or a pair) instead of takingok: &mut bool(R24). The clauses and their order are the same.Review fold (Shingler on 0e9e581): the Qwen bodies' resident totals (
body35.rs,body.rs) count the sameK-gemv ids (
self.k.q35 … kgemv.device_bytes()), the undercount this PR fixes for Nemotron.Review fold 2 (Shingler on f0f9170): the GLM and MiMo bodies count the same ids of their K-block kernels
(
KBlockKernels::device_bytes, through the now publicKGemvKernels::device_bytes).No kernel, launch or engine output moves.
What I ran
Head: see the SHA in the push request. Pre-review CLEAN at 421fbaa.
Head 0e9e581 on main 3898696, through the box queue (
BLOOMERY_BOX_QUEUE=1 tools/gate-batch.sh check lint fmt-check gate-gpu-mamba2 gate-gpu-nemotron-e2e gate-gpu-nemotron-serve); the box's cards, as on #259:NVIDIA GeForce RTX 3090, 615.71.09andNVIDIA RTX A6000, 615.71.09.On 421fbaa (main 2a47692, both folds):
check,lint(41),fmt-checkrc 0 through the box queue;just contrib-check --tier t0DONE total=83 red=0;gate-gpu-qwen35moe-e2erc 0 on the same fold one rebaseearlier (0a6d6a1c, main df965c0).
Not run as FAIL-first: no gate pins
resident_bytesto a derived figure; the count's change is the twodevice_bytesterms above.🤖 Generated with Claude Code