Repository navigation
npu serve: say it at ready when no 16-row decode kernel was found (refs #2102) - #2113
Conversation
PR Reviewer Guide 🔍(Review updated until commit a89ec98)Here are some key observations to aid the review process:
✅ Resolved findingsapp/forward_serve.cpp:1364-1369Missing Warning at Ready The PR introduces a warning message at the ready line when no 16-row decode kernels are found, which addresses the issue where operators were unaware of the performance degradation. However, the warning is only printed when app/npu_decode_note.h:36-45Silent Cases The PR correctly identifies that warnings on healthy serves are worse than no warning, and returns an empty string for cases it cannot judge. However, the logic for determining when to emit a warning might not cover all edge cases, such as when |
|
VERDICT: READY at I checked the one thing that would have made this the wrong processThe note is emitted by Why the pure function is the right shape
Two things to add
Nothing else. "What was missing was a sentence, not a measurement" is the correct framing, and the fact that the line already existed as |
|
Objection at
Device arms (no twins, which should warn; full set, which should stay silent; full set with A fix that keeps everything else in this PR is to let the loader, which knows which case it is in, decide:
I wrote exactly that shape before I saw this PR: |
|
Device arms for
So the true positive works. Two of the three silent cases I could run do not stay silent. The t2s case is from the code and docs/npu.md:615; I did not run it, because that is the owner's Bonsai container. The "way out" in the sentence needs a second look. On this route, the full twin set decodes at 7 tokens in 2574 ms, ≈2.7 tok/s, against ≈1.7 tok/s with none. That is one request of 7 tokens each, so treat it as a rough number. Shipping the |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 692ae19: CHANGES
The build dies in the container, not in the code:
::error::apt-get update+install failed 4 times -- if the 404s name .debs the index lists, i…
That is the runner's package installation failing after four retries — infrastructure, and nothing in this PR's diff (npu serve: say it at ready when no 16-row decode kernel was…) can influence it. Rerun; if it passes this verdict is void.
Worth recording since it is the second infrastructure red today (#2027 was a dist.tar.gz fetch from b1, #2057 was CodeQL's own config): three of today's red builds have now had nothing to do with their diffs, which is exactly the ambiguity #2093's pr_check_verdict.py exists to remove — FAILED versus CANCELLED versus "never ran".
This PR is one of the two moving #2102, so it is worth a rerun rather than a rebase.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 692ae19: READY
Reviewed head 692ae19 (refs #2102).
git merge-tree --write-tree origin/main 692ae19: no conflicts.npu_decode_note_test: "npu decode note: all cases ok".- Mutation check: I removed the
decode_roles >= design_rolesearly return inapp/npu_decode_note.h, so a healthy set would warn too. The test then failed on two cases, "4 of 4 roles (the fused route): silent" and "more families than roles (a wide set too): silent". I restored the file (git status clean), rebuilt, and the test was green again. So the test does catch a note that fires on the fast route. app/forward_serve.cppandnpu/forward/src/q4nx_forward.cppat this head compile clean (0 errors), using the NPU build's flags as single-file compiles.- Scope matches the title. The note only reports at ready, and only when fewer roles have a 16-row decode kernel than the design has. It changes no routing, so #2102 itself stays open for the kernel side.
…ase, and names the fused route Review fixes on #2113, each reproduced at 692ae19 and re-run here: - the host-GEMM arm loads no decode family; design_roles() is 0 there, so it no longer reads "0 of 4" - NPU_DECODE_M16=0 gets its own sentence naming the switch instead of "missing" kernels - a ternary (pb16i/t2s) container with some roles on M=128 is its geometry's (a missing kernel already fails the load), so only 0 of N warns there - the way out names the fused route: all four _m16 twins measured ~2.7 tok/s vs ~1.7 without and 88-101 fused - tests/npu_decode_note_test.cpp carries the full Apache notice (the build's copyright step was red) - docs/npu.md says what the line is and when it is silent Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Pushed
Re-run at
Every arm answered "The capital of France is Paris." |
|
Persistent review updated to latest commit d9ca114 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at d9ca114: READY
Reviewed head d9ca114 (refs #2102, release-blocker). It is one commit on 692ae19, answering that head's reviews.
A correction to my own READY at 692ae19: it cited the local test and compiles but did not look at CI, and CI was red there. Run 42955150586 failed build on "Copyright notice on every file", because the new test had only the two-line header. The CHANGES at 692ae19 was right that the build was red. This commit fixes it, and I checked CI at this head before posting.
Checked at this head
git merge-treeonto main: no conflicts.tools/copyright.py --check: rc 0.- CI at this head:
buildsucceeds (waited for it to complete before posting);hrx_buildand CodeQL succeed. npu_decode_note_test: "npu decode note: all cases ok".- Mutants of
app/npu_decode_note.h, each rebuilt and run:
| mutant | result |
|---|---|
NPU_DECODE_M16=0 arm skipped |
rc 1: "NPU_DECODE_M16=0: names the switch" |
| ternary partial set warns (image rule removed) | rc 1: "healthy t2s container, 8 of 9 (docs/npu.md): silent" |
ternary with 0 decode kernels silent (if (image)) |
rc 1: "a ternary container with no decode kernel at all: warns" |
| full family warns (early return removed) | rc 1: "4 of 4 roles (the fused route): silent" |
I restored the file (git status clean); the rebuilt test is green.
app/forward_serve.cppandnpu/forward/src/q4nx_forward.cppcompile clean (0 errors) as single-file compiles with the NPU build's flags.- Read in the source:
decode_disabled_is set only in the!want_m16branch ofopen_decode_family_local(), the one that already logs "(NPU_DECODE_M16=0: disabled)".design_roles()returns 0 whenhost_gemm_, so the host arm stays silent through the existingdesign_roles <= 0return.decode_image()ispb16i_.- The machine line
[forward] decode family: …is unchanged.
Not covered by a host test: the host_gemm_ → 0 rule lives in the forward class, so it is checked by reading and by the compile, not by a test.
|
Persistent review updated to latest commit a89ec98 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at a89ec98: READY — withdraws my CHANGES
The build is green on this head and the failure I blocked on was infrastructure, not the diff: apt-get update+install failed 4 times — the Ubuntu mirror failing on .debs its own fresh index listed, the case ci.yml already documents as engine#1814 and retries for. It cleared on a later attempt, which is the behaviour the retry exists to produce.
The substance is unchanged and worth restating because this is one of the two PRs moving release blocker #2102: a shipped 1bit serve that quietly falls to the 1.9 tok/s path now says so at ready. That is the difference between a slow serve and a mystery — and #2119's smoke gate is what will catch a regression of it after the fact.
Worth the fleet's attention separately: that apt failure red-ed two PRs within an hour (#2113 and #2120), and four retries did not save either. The retry re-reads the index per attempt, so it can reach a different mirror — the fact it still failed suggests the mirror pool is thinner than when #1814 was written. Caching the .debs, or pinning an alternate mirror, is the durable answer; a release-blocker PR should not wait on Ubuntu's rotation.
Refs #2102 (release-blocker), the "says nothing at ready" half I claimed on the issue at 03:21Z. Not the kernel work — no 16-row designs for this geometry is cl-npuperf's row — and not the 1.9 tok/s number, which the issue already has.
What was missing was a sentence, not a measurement. The fact exists as a machine line,
[forward] decode family: 0 role(s) at M=16, 4 on M=128, and that line is grepped byte-for-byte by the gates (its own comment says so), so it must not be reworded. What the serve never said, anywhere an operator looks, is that this route answers correctly and ~50× slower than the fused one.At this head, after the ready line:
The decision is a pure function (
app/npu_decode_note.h) precisely so the silent cases are arms, not hopes — a warning that fires on a healthy serve is worse than no warning, because it teaches an operator to ignore the line that exists to be noticed:npu_decode_note_test: 12 arms, all ok, registered withadd_dependencies(onebit …)so CI's build actually compiles it.onebititself builds at this head (4.4 MB) andctest -R npu_decode_notepasses on a fresh configure (rc 0).Two design points:
decode_roles()/design_roles()are recorded inopen_decode_family_local()wheremadeandndesigns_already exist — the derived designs are not kept per role, so "count them later" would have been a second source of truth for the number the log line already prints.Not done, deliberately: the second suggestion in the issue (
/healthor the chat response carrying a rate). That is a response-schema change touching every client, and it belongs to whoever owns the serve contract; this PR is the part that costs an operator nothing to read.