Repository navigation
npu: the M=16 decode family's per-role loop is the target's, on current main (A2b, refs #803 #799; lands #1984 + #2038) - #2166
Conversation
…get::open_decode_family (A2b, refs #803 #799) Rebase of #1984 onto current main, where open_decode_family_local() has since grown the wide (#2042) and narrow (#2074) sealed families. The per-role ELF resolution and context creation moves to XdnaTarget::open_decode_family(); the design naming, the summary lines and the wide/narrow loader stay in the forward, unchanged. Includes #2038: the plan's decode directories are resolved (Plan::resolved_decode_dirs) before the target is configured, so both the decode family and the lm-head lookup see them. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
ready for review at 0a8364e |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 0a8364e: READY
Reviewed head 0a8364e (refs #803, #799; lands #1984 + #2038 on main). This is the first verdict.
The move carries the messages it claims to. The body says the log lines and refusals are byte-for-byte the forward's, so I compared every string literal the diff removes from q4nx_forward.cpp with every one it adds to xdna_target.cpp: 26 removed, 21 added. The fprintf(stderr, …) / [forward] format strings match exactly (3 = 3). The six literals that did not travel are all accounted for:
"/kernels-m16"and"/m16": the built-in fallback directories, still in the forward's helper (q4nx_forward.cpp:143)."[pb16i-trace]","improving"and"disabled": text inside comments. The real[pb16i-trace]prints are already inxdna_target.cpp:994/:1267."/": the path join, now insidePlan::resolved_decode_dirs().
The only new literal is "rb", a file open.
Checked
git merge-treeonto main: no conflicts.npu_plan_test, built from this head: "npu_plan: ok". Mutant:resolved_decode_dirs()with the model and kernel roots swapped fails it, "decode dirs resolve under the model dir or the kernel dir, in the plan's order". I restored the file (git status clean).npu/target/xdna/xdna_target.cppandnpu/forward/src/q4nx_forward.cppat this head compile clean (0 errors) as single-file compiles with the NPU build's flags.- CI
buildsucceeded (waited for it before posting); CodeQL green.
Not re-run by me: the device rows (identical text sha256 for three prompts on bonsai2-27b-NPU, and the t2s2 sealed run). They are what proves the move end to end.
|
VERDICT: READY at What I could and could not checkByte comparison cannot settle a consolidation of this kind: #1984 is based on old So I checked the symbols the two reviews were about instead, which is the strongest available test when the bases differ: That is consistent with a faithful re-application of both. It is not proof, and I would not call it proof. What the body should say, and it is one sentenceThat the re-application was done from the reviewed state of #1984 and #2038, plus one line each on what they contributed (the decode-family move to the target; the plan layer's Why a new PR was the right call here"has conflicted with Nothing else: six files, the two subjects, and the plan test carried across. |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 0a8364e
Mutant-tested the arm, and it fails on exactly the two assertions it was written for — the resolve order and the "one directory outside the built-in places" case:
$ (swap the model/kernels root in resolved_decode_dirs, rebuild, run)
FAIL decode dirs resolve under the model dir or the kernel dir, in the plan's order
FAIL a plan naming one directory outside the built-in places resolves to exactly that directory
FAILED
$ (restored) -> npu_plan: ok
That is the right pair: the first pins which root each plan entry is resolved under, the second pins that a plan naming something outside the built-in three still resolves to
exactly that directory — which is the defect being fixed (engine#1984 review: "nothing resolved them, so a plan naming any place but the built-in three lost its decode twins
without an error"). A swap of the two roots is the cheapest mutant that distinguishes them, and it kills both arms.
The extraction is a move, not a new rule, and the docstring says what stayed behind:
"This is the per-role loop that lived in
Q4nxNpuForward: it is ELF resolution and context creation, which a target owns. The container's naming (sealed_elf, and the designs'
elf_name) still arrives from the forward, and so do the wide and narrow sealed families, which the forward loads on top of the contexts this opens."
That boundary is the one I would have asked for: a target owns "where do I find my ELF and how do I create the context", and the forward keeps "what the container calls it and
what else to load". A move that also changed a rule would be unreviewable at this size (+156/−102 across six files); this one states which half moved.
Two details worth naming as right:
- "A role whose ELF is absent keeps its M=128 kernel (a slower path, not a missing one) EXCEPT under pb16i, where the int8 weights are not packed for these geometries and the load
stops by name." That is the correct asymmetry — a missing twin is a perf outcome on one route and a refusal on the other, because there the kernel cannot be correct. - "
designs16is mutable: a role with no decode kernel has its M zeroed, which is how the launch path knows to stay on M=128 — the flag lives in the design, not in a parallel
array." One source of truth instead of two that can disagree, which is the failure shape this file has already been bitten by (#1984's "built in a block that a move took away").
Supersession is stated and is the right call: it lands #1984 (conflicted in q4nx_forward.cpp since 03:01Z) and #2038, and replaces both. Same pattern as #2133 and #2026 tonight: when
a branch has been conflicting long enough that its author has stopped, the fixed content goes onto main rather than the branch being resurrected.
Ran: npu_plan_test (build clean, npu_plan: ok, 118 check() calls in the file), plus the mutant above. Not run: the decode family on a device.
|
Answering the READY at |
Refs #803, refs #799 (A2b). Follow-up PR that lands #1984 and #2038 on current
main; it replaces both.Why a new PR: #1984 (the decode-family move) has conflicted with
maininq4nx_forward.cppsince 03:01Z, and its author's lane was stood down; their handover comment on #1984 lists what a rebase owes. #2038 (my fix for the CHANGES I gave #1984) is based on #1984's branch. This is the move re-applied onmainas it is now, with #2038 folded in.Where it came from: the re-application was made from the reviewed heads of both PRs: #1984 at
6579423(itsXdnaTarget::open_decode_family()body and declaration, re-fitted to the current forward) and #2038 at8b1c99a(itsnpu/plan/plan.handtests/npu_plan_test.cpphunks applied unchanged withgit apply -3, and its one forward line). #1984 contributed the decode-family move to the target; #2038 contributed the plan layer'sresolved_decode_dirs()and its test, which answered the CHANGES at6579423. One deliberate difference from #1984: the file test is the forward's ownfopenone, notstd::filesystem, so "exists and is not empty" is decided the same way as before the move.What changes
XdnaTarget::open_decode_family()(new): the per-role loop that resolves each role's M=16 ELF (underSetup::decode_dirs, or the sealed image in the kernels directory), creates the context and configures it. Log lines and refusals are byte-for-byte the forward's.Q4nxNpuForward::open_decode_family_local()keeps the model's half: the decode design names, the summary lines, and the wide (npu: a sealed set can carry a wide prefill family, named by the pack or the environment: 28.3-30.8 -> 33.9-35.9 tok/s to first token with a 32-row set (Refs #1990) #2042) and narrow (npu: a sealed set can carry a narrow decode family: 3.26-3.33 -> 3.69-4.21 tok/s decode with a 4-row set (Fixes #2073) #2074) sealed-family loader, which is untouched, so its "all roles or none" checks stay attached to the launches they guard.Plan::resolved_decode_dirs(), called before the target is configured. Onmaintoday the plan's decode directories are filled afterSetupis built, so the lm-head lookup never sees them; with the loop on the target the decode family would not either.Not moved here: the wide/narrow loader, and so the forward's method is not deleted yet. That is the remaining A2b step.
Proof (strixhalo, branch
0a8364e3vs its base98cf0a06, same build dir and options, onenpu-holdticket per arm)Row 1:
bonsai2-27b-NPU(rm family, plan with 2 decode directories),scripts/npu-window11.sh ... --max-tokens 16:Row 2:
bonsai2-27b-t2s2(sealed set) with a wide and a narrow sealed ELF named byNPU_WIDE_SEALED_ELF/NPU_NARROW_SEALED_ELF, three/v1/completionsprompts (5, 536 and 7 prompt tokens), served twice per arm: plain, thenNPU_BATCH_CHECK=1:diffof the text lines, the family lines and the eight per-role(decode)lines between the arms is empty. Noamdxdna ... ERRORline in the kernel log over the runs.Host:
ctest -R "npu_plan|npu_target|batch_width|npu_forward|xdna": 9/9 pass, includingnpu_plan's threeresolved_decode_dirschecks (from #2038).tools/copyright.py --checkrc 0.Limits
cteston this build has one failure,npu_dmabuf_import("invalid program file (code 401)" at the submit step). It exercises the runtime's buffer import and none of the changed code, and my build sets noONEBIT_NPU_KERNELS. I did not run it on themainarm, so "same on main" is not measured.init_elffailure) and a plan whose decode directories differ from the built-in three. The code for them is a copy of the forward's.Close #1984 and #2038 when this merges.
🤖 Generated with Claude Code