Skip to content

tests: known-answer MUL_MAT cases with a resident weight, for the packed-layout registrations (engine #1997) - #287

Merged
bong-water-water-bong merged 1 commit into
1bit/hrx-vulkan-patchedfrom
test/1997-resident-weight-mul-mat
Nov 10, 2026
Merged

bong-water-water-bong merged 1 commit into
1bit/hrx-vulkan-patchedfrom
test/1997-resident-weight-mul-mat

Conversation

@bong-water-water-bong

Copy link
Copy Markdown

Test-only. First part of 1bit-MONSTER/engine#1997.

Why

Five HRX MUL_MAT registrations read the weight in a packed layout, which the backend materialises only for a tensor in a buffer flagged GGML_BACKEND_BUFFER_USAGE_WEIGHTS. test_mul_mat keeps its weight in the ordinary buffer, so a case that reaches one of them is refused at execution (the engine ggml-org#969 line) and test-backend-ops then compares the output tensor it never wrote — still holding the harness's random [-1, 1] fill — against the CPU. That comes out as ERR ≈ k/3 + 1 and reads like a kernel fault. It is not one: the kernels are correct when the weight is flagged. But it does mean none of these kernels had a known-answer case, and they are the prefill and decode paths for Q4_K and Q6_K.

What

test_mul_mat_resident_weight: the weight goes through the harness's existing weight context (use_weight_context()), as a model's does. One case per registration, plus the native-layout Q5_K prefill as a control.

Proof (strixhalo, 2026-11-10 19:34Z, one gpu-hold ticket; test-backend-ops compiled from this branch against the CI build of engine main, llama.cpp fa533bd21; GGML_HRX_LOG_DISPATCH=1, one case per process)

##### resident weight (new cases)
q4_K m=2048 n=512 k=4096 -> q4_k_q8_1_x4_prefill            | 1/1 tests passed
q6_K m=2048 n=512 k=4096 -> q6_k_prefill_wave32             | 1/1 tests passed
q6_K m=2048 n=8   k=4096 -> q6_k_i8_prepacked               | 1/1 tests passed
q6_K m=4096 n=8   k=512  -> q6_k_aligned_skinny             | 1/1 tests passed
q6_K m=2048 n=1   k=4096 -> q6_k_token1_final_projection_q8 | 1/1 tests passed
q5_K m=2048 n=512 k=4096 -> q5_k_iq4_xs_q8_1_x4_prefill     | 1/1 tests passed
##### the same shapes, weight in the ordinary buffer (plain test_mul_mat)
q4_K m=2048 n=512 k=4096 -> ERR = 1367.463382731 | refusing to run that kernel over unpacked weight bytes | 0/1 tests passed
q6_K m=2048 n=8   k=4096 -> ERR = 1361.288244016 | refusing to run that kernel over unpacked weight bytes | 0/1 tests passed
q6_K m=2048 n=1   k=4096 -> ERR = 1378.027059095 | refusing to run that kernel over unpacked weight bytes | 0/1 tests passed
##### whole MUL_MAT op with the new cases
  598/598 tests passed      Backend HRX0: OK

(k/3 + 1 at k = 4096 is 1366.3.) The "before" rows are not in the suite; they are the same shapes through test_mul_mat, shown to make the point that the registration is reached either way and only the flag differs.

Not in this PR

Ready for review at 6987788.

🤖 Generated with Claude Code

…ked-layout registrations (engine ggml-org#1997)

Several HRX MUL_MAT registrations read the weight in a packed layout that
is only materialised for a tensor in a buffer flagged as weights.
test_mul_mat keeps its weight in the ordinary buffer, so any case that
reached one of them was refused at execution and the suite compared the
never-written output (an "ERR" of k/3 + 1): those kernels had no
known-answer case at all.

test_mul_mat_resident_weight puts the weight in the weight context, as a
model's is, with one case per registration: the Q4_K packed prefill, the
Q6_K prefill, the Q6_K i8 prepacked and aligned-skinny forms, the Q6_K
one-token final projection, and the Q5_K prefill (native layout) as the
control.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@bong-water-water-bong

Copy link
Copy Markdown
Author

ready for review at 6987788 (lane cl-hrxnan). Test-only; first part of 1bit-MONSTER/engine#1997.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 6987788: READY

Checked at 6987788 (test-only). I compiled tests/test-backend-ops.cpp from this head against a clean HRX build of its exact parent 50d28600a (#286, so fa533bd included). That build was made after its commit, has no dirty files, and uses its own libhrx/libloomc (checked with ldd). One gpu-hold ticket on strixhalo:

-o MUL_MAT -p "weight=resident", GGML_HRX_LOG_DISPATCH=1:
  common.mul_mat.q4_k_q8_1_x4_prefill            common.mul_mat.q6_k_prefill_wave32
  common.mul_mat.q6_k_i8_prepacked               common.mul_mat.q6_k_aligned_skinny
  common.mul_mat.q6_k_token1_final_projection_q8 common.mul_mat.q5_k_iq4_xs_q8_1_x4_prefill
  6/6 tests passed
-o MUL_MAT (whole op): 598/598 tests passed, Backend HRX0: OK

So each new case reaches the registration it names, and all six give the right answer with a resident weight.

The mechanism in the description is also right, and it corrects my comment on ggml-org#1997. Re-running my plain-buffer probe with full stderr, every case logs the executor's "refusing to run that kernel over unpacked weight bytes" line (q6_K n=1, q6_K n=8, q4_K n=512: one refusal line each, ERR 1395 / 1398 / 682). So the k/3 + 1 error is the never-written output buffer, and the guard does fire. My probe had kept only the first matching log line, which was the GTT guardrail, and I'll correct that on the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant