Repository navigation
hrx-backend-test: 49 host cases red after the AMD-core re-head — classification (stale expectation vs needs a ruling) #445
Description
tests/hrx-backend-test.cpp builds again after 1bit-MONSTER/llama.cpp#103, but 49 of its 85 host cases fail on CPU. This issue carries the per-case classification, taken from the plan each case actually produced (temporary dump of plan.dispatches with kernel names, since REQUIRE prints only the expression) and from whether the kernel a case expects still exists in the corpus and in dispatch_registration/.
Read this as: class A/B are expectation updates (the test encodes the pre-re-head dispatcher), class C/D are behaviour changes that should be ruled on before anything is edited. I did not update A-D in #103 on purpose: writing the current plan shape back into the test would turn a red regression net green against a plan that may be worse than the one the test was built to protect.
Repro
git clone --filter=blob:none --single-branch --branch 1bit/hrx-vulkan-patched https://github.com/1bit-MONSTER/llama.cpp.git
cd llama.cpp && git switch 1bit/hrx-test-symmetric-i4-removed # or PR #103's branch
# the pinned pair, not the older submodule checkout: the corpus needs Loom's multiple_of
git clone --filter=blob:none https://github.com/1bit-MONSTER/hrx-system.git ../hrx-system
git -C ../hrx-system checkout d3c731e1d7f47de2d64739b1ec298f0d0fe829d4 # the engine's pin after #441
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=gcc-15 -DCMAKE_CXX_COMPILER=g++-15 \
-DLLAMA_BUILD_TESTS=ON -DGGML_HRX=ON \
-DHRX_SOURCE_DIR=$PWD/../hrx-system \
-DGGML_HRX_HIP_COMPILER=$HOME/sdk-gfx1201-devel/bin/amdclang++ # any amdclang++ with gfx1151
cmake --build build --target hrx-backend-test -j8
./build/bin/hrx-backend-test # 85 host cases, 14 device cases skipped without a device
./build/bin/hrx-backend-test --hrx-backend-test-case scale_add_f32_dispatchGCC 15 note: the vendored IREE/loom builds with -Werror and trips GCC 15 false positives (array-bounds, format-overflow). For a local build, wrap the compiler so -Wno-error lands last (exec gcc-15 "$@" -Wno-error) or use clang. Device cases (14) need an HRX device; not covered here.
A. Stale plan shape: a fused dispatch the corpus no longer has (17)
The plan covers the same nodes as separate dispatches, each with a kernel that exists; the expectation of one fused dispatch is what is gone. Evidence is the actual plan for the first graph of each case.
| Case | Expectation | Actual plan (first graph) |
|---|---|---|
scale_add_f32_dispatch (1565) |
dispatches.size() == 1 |
2: ggml_scale_f32, ggml_binary_f32 |
rmsnorm_two_binary_dispatch (1473) |
== 1 |
2: ggml_rmsnorm_binary_f32, ggml_binary_f32 |
graph_index (2383) |
== 1 |
2 (4th graph): ggml_rmsnorm_f32, ggml_binary_bc_f32 |
rope_set_rows_dispatch (2478) |
== 1 |
2: ggml_rope_f32, ggml_concat_dim0_strided_source_f32 |
get_rows_rmsnorm_binary_dispatch (4575) |
== 1 |
2: ggml_get_rows_f32, ggml_rmsnorm_binary_f32 |
get_rows_scale_dispatch (4629) |
== 1 |
2: ggml_get_rows_f32, ggml_scale_f32 |
tiled_pair_matmul_postops_dispatch (3581) |
== 1 |
2: ggml_mul_mat_swiglu_f32_f32_wmma, ggml_binary_bc_f32 |
generic_ssm_conv_binary_dispatch (7345) |
== 1 |
2: llm_ssm_conv_f32, ggml_binary_f32 |
lfm_dconv3_dispatch (7415) |
fused present | 3: ggml_concat_dim0_strided_source_f32, llm_ssm_conv_f32, ggml_copy_strided_source_f32 |
lowtoken_residual_dispatch (13560) |
fused == 1 |
1: ggml_kquant_mul_mat_decode_f32 |
lowtoken_bias_dispatch (13596) |
skinny_bias == 1 |
1: ggml_mul_mat_bias_f32_f32_wmma |
qwen_matmul_dispatch (3249) |
dispatches.size() == command_count |
1: ggml_kquant_mul_mat_decode_tokens_f32 |
qwen_attention_postprocess_dispatch (5710) |
5 with q8 input | 4, no q8 variant |
prefill_value_projection_cache_dispatch (9021) |
fused == expect_fusion |
no dump captured (asserts before scheduling) |
disjoint_transient_plan_packing (12002) |
transients.arena_size == 256 |
4 x ggml_binary_f32 |
iq2_codebook_resource_reuse (8844) |
constant_initializations.size() == 1 |
2 dispatches, 0 constant inits |
qwen_attention_postprocess_dispatch/qwen_terminal_q6k_q8_command.tokens1 |
q8 publication shape | see C |
B. Stale kernel name: the expected kernel is gone from the corpus and from the registrations (14)
| Case | Expectation (gone) | Actual |
|---|---|---|
dispatch_registry (711) |
common.mul_mat_swiglu.tiled_pair_f32_f32 (Fused) |
registration absent (tiled_pair_postops_f32_f32 still there) |
quantized_value_projection_dispatch (8922) |
llm_attention_v_matmul_set_rows_vector_f32_f32 |
llm_attention_v_matmul_set_rows_decode_f32_f32 |
get_rows_q8_1_alternate_command.q4_k / .bf16 (4245) |
ggml_mul_mat_vector_q6_f32_f32 |
ggml_mul_mat_q6_k_packed_token1_f16_wmma |
iq1_codebook_matmul_dispatch (3372) |
codebook kernel (expected_kernel) |
ggml_kquant_mul_mat_decode_f32 |
iq3_xxs_codebook_matmul_dispatch (8779) |
codebook kernel | ggml_kquant_mul_mat_decode_f32 |
iq4_matmul_dispatch (3263) |
expected_kernel_name |
ggml_mul_mat_f32_f32_decode_wave64 / ..._wmma |
qwen_terminal_q6k_vector_command (3263) |
expected_kernel_name |
ggml_mul_mat_q6_k_packed_token1_f16_wmma |
qwen_terminal_q6k_q8_command.tokens1 (3962) |
qwen3_moe:ggml_linear_q6k_q8_1_x4 (still registered) |
qwen3_moe_rmsnorm_f32_quantize_q8_1_x4 + ggml_mul_mat_q6_k_packed_token1_f16_wmma |
rmsnorm_lowtoken_striped_dispatch (1690) |
test.expected_kernel |
ggml_rmsnorm_binary_f32 |
binary_q8_publication (2026) |
test.expected_kernel producer |
ggml_binary_f32, ggml_kquant_mul_mat_decode_tokens_f32 |
common_mul_mat_id_swiglu_dispatch (9834) |
common_mul_mat_id_swiglu_f32_kernel_name(ne) |
no dump captured (fails on a .at()/table lookup) |
qwen_routed_gate_up_dispatch (9747) |
common_mul_mat_id_f32_kernel_name(ne) |
same |
common_mul_mat_id_postops_dispatch (10051) |
expected_kernel_name |
same |
qwen_weighted_reduce_next_rmsnorm_q8_publication (10878) |
expected_kernel |
same |
C. Publication / alternate values: different kernels, and in places no alternate at all (11)
The alternate-value machinery is still live (22 append_alternate_value call sites), so these are not "the feature was deleted" as a class; each case asserts a specific producer kernel or that an alternate exists for a specific shape, and the current plan produces a different kernel or no alternate.
| Case | Expectation | Actual |
|---|---|---|
packed_f16_producer_consumer (6008) |
(alternate != nullptr) == test.alternate |
3: ggml_copy_f16_k16_major, ggml_mul_mat_swiglu_q4_k_f16_wmma_prefill_wave32, ggml_mul_mat_q6_k_f16_wmma_prefill_wave32 |
generic_swiglu_k16_publish (6077) |
publish producer present | 3, no publish producer |
generic_swiglu_k16_publication_edges (6139) |
publish producer present | 1: ggml_mul_mat_swiglu_f32_f32_wmma |
tiled_matmul_alternate_publish (6268) |
publish producer present | 3: ggml_mul_mat_f32_f32_wmma, ggml_copy_f32_f16, ggml_mul_mat_q6_k_f16_wmma_prefill_wave32 |
rmsnorm_binary_k16_output (6695) |
(producer != end) == test.packed |
3, ggml_copy_f16_k16_major present |
rmsnorm_binary_f16_output (6770) |
producer present | 3, ggml_copy_f32_f16 present |
swiglu_q8_output (6512) |
(producer != end) == test.packed |
2: ggml_kquant_swiglu_decode_tokens_f32, ggml_kquant_mul_mat_decode_tokens_f32 |
rmsnorm_gate_packed_output (6946) |
producer present | 2: ggml_rmsnorm_gate_f32_f16, ggml_mul_mat_q4_k_f16_wmma_prefill_wave32 |
rmsnorm_gate_q8_output (7071) |
(producer != end) == test.q8 |
3: ggml_rmsnorm_gate_f32_q8_1_x4, ggml_mul_mat_f32_f32_wmma, ggml_scale_f32 |
qwen_decode_publication_consumer_qualification (4154) |
(q8 != nullptr) == test.q8 |
no dump captured |
qwen_weighted_reduce_next_rmsnorm_q8_publication (10878) |
publish producer | see B |
D. Behaviour that looks wrong or needs a ruling (7)
| Case | Evidence | Why it is not just an expectation |
|---|---|---|
symmetric_i4_consumer_qualification (7160) |
plan dispatches loom_libs:ggml_rmsnorm_binary_symmetric_i4_k32 |
This is the route f2099e9b deleted with "Disabled because the route causes a substantial numerical performance regression". The current dispatch set has it back, with no knob; the case exists to assert it is never selected. |
gdn_rmsnorm_gate_dispatch (7729) |
expects loom_libs:ggml_rmsnorm_gate_f32_publish; corpus=true, registered=false |
The kernel is in the corpus but nothing registers it, so the gated-delta-net rmsnorm-gate publish path cannot be reached. |
iq2_codebook_resource_reuse (8844) |
constant_initializations.size() == 0 |
The case exists to prove codebook tables are initialized once and reused; nothing initializes them now. |
qwen_router_top8_dispatch (9240) |
dispatch.bindings[1].length != route_id_length |
A binding length changed on the router kernel; that is a data-shape assertion, not a naming one. |
qwen_token_embedding_dispatch (4514) |
manual_token_embedding_graph_is_supported(...) is now true |
The case asserts the manual token-embedding graph is not supported; it is. Either the support was added deliberately or it should not match. |
gather_add_dispatch (227) |
expected compile parameter absent (found == end()) |
hrx:ggml_gather_add_f32 is dispatched but without the parameter the case pins. |
qwen_flash_attention_dispatch, gdn_native_projection_pair_dispatch |
process aborts: terminate called after throwing an instance of 'std::out_of_range' what(): map::at |
The test indexes an integer/compile parameter with .at() that the current dispatch does not set, so the case crashes instead of reporting. The missing key is itself the finding; the .at() should also be guarded. |
Not covered here
tests/test-hrx-ops.cpp (9 sites) and tests/test-hrx-loom-jit.cpp (4 sites) use the same removed members (workload_specialization, activation_publication_diagnostics). In loom-jit those assignments are what makes two specializations distinct for the JIT disk cache, so they need a replacement discriminator rather than deletion. The 14 device cases need an HRX device (gfx1151) and are unverified.
Activity
bong-water-water-bong commentedon Oct 18, 2026
Ruling recommendations for the 19 class C/D cases. Method and evidence per case: the plan each case actually produced (
plan.dispatchesdumped with kernel names, temporary instrumentation, reverted), whether the kernel a case expects is still inkernel-corpus/and indispatch_registration/, andgit log -Son the branch for the commit that moved it. No test edits, no PRs.The single fact behind most of class C: f2099e9b ("hrx: keep our ggml-hrx backend on AMD's core") dropped our consumer-driven activation-publication set whole - 27
*_publish_*kernels are absent from the corpus and fromdispatch_registration/today:Class C - publication / alternate values (11)
packed_f16_producer_consumerggml_copy_f16_k16_major,ggml_mul_mat_swiglu_q4_k_f16_wmma_prefill_wave32,ggml_mul_mat_q6_k_f16_wmma_prefill_wave32- 3 dispatches, andalternate == nullptrwhere the case expects one. The producer (..._publish_f32_f16_alternate) is gone (f2099e9b); the copy that publication fused into the producer is now its own dispatch. File under the restore-publication issue.generic_swiglu_k16_publish*_publish_*producer; plan isggml_mul_mat_swiglu_f32_f32_wmma,ggml_copy_f16_k16_major,ggml_mul_mat_q6_k_f16_wmma_prefill_wave32- the publish producer is gone, the copy appears separately. Same root cause.generic_swiglu_k16_publication_edgesggml_mul_mat_swiglu_f32_f32_wmma): no copy, no publish, i.e. fewer dispatches than the publication version and the same math on the same kernel that exists. Expectation becomes "one dispatch, no producer".tiled_matmul_alternate_publishggml_mul_mat_f32_f32_wmma,ggml_copy_f32_f16,ggml_mul_mat_q6_k_f16_wmma_prefill_wave32. The copy is a separate dispatch where the publish producer used to fuse it; the producer kernel is gone (f2099e9b).rmsnorm_binary_k16_outputggml_rmsnorm_binary_f32,ggml_copy_f16_k16_major,ggml_mul_mat_q4_k_f16_wmma_prefill_wave32. Expected(producer != end) == test.packed: the packed-f16 publish producer no longer exists, and the copy stands alone.rmsnorm_binary_f16_outputggml_copy_f32_f16as the separate dispatch; the f16 publish producer is gone (f2099e9b).swiglu_q8_outputggml_kquant_swiglu_decode_tokens_f32,ggml_kquant_mul_mat_decode_tokens_f32. AMD's decode kernels consume f32 directly, so the q8 publication this case pinned is not needed: 2 dispatches, same math, no extra copy.rmsnorm_gate_packed_outputggml_rmsnorm_gate_f32_f16,ggml_mul_mat_q4_k_f16_wmma_prefill_wave32- the norm kernel emits f16 itself (_f32_f16), i.e. the dtype conversion the case expected from a publish producer is fused into the producer that exists. Equivalent, one fewer dispatch.rmsnorm_gate_q8_outputggml_rmsnorm_gate_f32_q8_1_x4,ggml_mul_mat_f32_f32_wmma,ggml_scale_f32. Publication still happens, through AMD'sggml_rmsnorm_gate_f32_q8_1_x4(in the corpus and registered) instead of ourggml_rmsnorm_gate_f32_publish. Expectation change: the producer's name.qwen_decode_publication_consumer_qualification..._publish_q8, and theggml_binary_f32_publish_q8_1_x4family) is not in the corpus any more, and the plan isggml_binary_f32+ggml_kquant_mul_mat_decode_tokens_f32with no alternate. Same root cause.qwen_weighted_reduce_next_rmsnorm_q8_publicationqwen3_moe:qwen3_moe_routed_down_weighted_reduce_next_rmsnorm_f32_publish_q8; that kernel is absent from the corpus and the registrations (f2099e9b), so the fused weighted-reduce + rmsnorm + q8 publish path is unreachable.What to file for the seven REGRESSION rows: one issue, "restore consumer-driven activation publication (dropped whole in f2099e9b)", listing them with these plan dumps, and stating the cost: each shape gains an explicit copy dispatch (or loses the fused q8 publish) where the pre-re-head plan had none.
generic_swiglu_k16_publication_edges,swiglu_q8_output,rmsnorm_gate_packed_outputandrmsnorm_gate_q8_outputare not part of it - those shapes are equal or better now.Class D - behaviour that is not just a renamed expectation (8)
symmetric_i4_consumer_qualificationloom_libs:ggml_rmsnorm_binary_symmetric_i4_k32(corpus=Y, registered=Y,dispatch-rmsnorm.cpp). Registration came back in aadd6025 (Aaryaman Vasishta, "hrx: add generic gfx1151 graph optimizations", AMD-authored); our own f2099e9b deleted it with the comment "Disabled because the route causes a substantial numerical performance regression". Re-enabled against our recorded measurement, with no knob. Confirm with a device run (pp/tg and logits vs the disable), then file.gdn_rmsnorm_gate_dispatchloom_libs:ggml_rmsnorm_gate_f32_publish: corpus=Y, registered=N. The kernel is shipped and dead - f2099e9b removed the registration, so the fused rmsnorm-gate publish path for gated-delta-net cannot be reached. File with the restore-publication issue (this one is cheap: the kernel still builds).iq2_codebook_resource_reuseggml_kquant_mul_mat_decode_f32(the codebook kernels are gone; onlykquant_decode_f32.loomcarries them now). One generic decode kernel needs no per-shape codebook tables, soconstant_initializations == 0is the correct new value; there is no resource left to reuse. Expectation change: 0 constant initializations,ggml_kquant_mul_mat_decode_f32.qwen_router_top8_dispatchqwen3_moe_router_top8_f32(it takes%route_id_strideas a workload argument now), but the plan adds AMD'sggml_moe_build_expert_tableandggml_moe_build_expert_partition_table, andbindings[1].lengthno longer equalsroute_id_length. Whether that is a moved convention or extra per-token work cannot be settled from the plan alone. Device run must measure: dispatches per decoded token (was 1, now 3?), tg tok/s against the pre-re-head build, and logits/argmax equality on a fixed prompt.qwen_token_embedding_dispatchggml_get_rows_f32per embedding + matmul), not through a new special kernel. More graphs served, same operations. Expectation change: supported, with the kernel list.gather_add_dispatchhrx:ggml_gather_add_f32, but its three dims are now workload/integer arguments (ints=3) instead of compile parameters (cparams=0); the test'srequire_compile_parameterlooks in the wrong map. The corpus kernel declares%source_token_count, %output_token_count, %hidden_sizeas arguments. Expectation change: assertinteger_parameters, notcompile_parameters.qwen_flash_attention_dispatchggml_copy_transpose_f16+loom_libs:ggml_flash_attention_f32_f16_wmma, the kernel the case expects. The abort (std::out_of_range: map::at) is the test reading aggml.flash_attention.*parameter the current dispatch does not set, from one of theschedule_*_flash_attention_*helpers. Expectation change: pin the parameters the kernel sets now (which of them needs one CPU probe, not a device run); no route or dtype change.gdn_native_projection_pair_dispatchepilogue->kernel.integer_parameters.at("element_count")throws, whiledispatch-gated-delta-net.cpp:794setsllm.gated_delta_net.epilogue_element_count. Expectation change: assert that compile parameter; also guard the.at()so a future rename reports instead of aborting.Totals
generic_swiglu_k16_publication_edges,swiglu_q8_output,rmsnorm_gate_packed_output,rmsnorm_gate_q8_output,iq2_codebook_resource_reuse,qwen_token_embedding_dispatch,gather_add_dispatch,qwen_flash_attention_dispatch,gdn_native_projection_pair_dispatchpacked_f16_producer_consumer,generic_swiglu_k16_publish,tiled_matmul_alternate_publish,rmsnorm_binary_k16_output,rmsnorm_binary_f16_output,qwen_decode_publication_consumer_qualification,qwen_weighted_reduce_next_rmsnorm_q8_publication,symmetric_i4_consumer_qualification,gdn_rmsnorm_gate_dispatchqwen_router_top8_dispatchTwo issues to file if this is accepted: (1) restore consumer-driven activation publication, dropped whole in f2099e9b - 7 class C cases plus
gdn_rmsnorm_gate_dispatch; (2) the symmetric-i4 consumer route came back in AMD's aadd6025 after our f2099e9b removed it as a numerical/perf regression - decide whether to re-disable it (the case says it must never be selected).Deferred device work (added to NEED-GPU T422): the 14 device cases, plus the
qwen_router_top8_dispatchmeasurement (dispatches per token, tg tok/s, logits equality) and the symmetric-i4 confirmation (pp/tg and logits with the route on vs off).bong-water-water-bong commentedon Oct 18, 2026
Owner ruling on this table: ACCEPTED as posted. Acting on it:
Restore consumer-driven activation publication (the 7 class C REGRESSION rows +
gdn_rmsnorm_gate_dispatch): engine HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449.The symmetric-i4 consumer route re-enabled by AMD's aadd6025 after our f2099e9b removed it: engine HRX: symmetric-i4 consumer route re-enabled by AMD aadd6025 after f2099e9b removed it #450 (with the deferred on/off device measurement).
ACCEPT rows in the test: hrx-backend-test: drop the use of the deleted dispatch-symmetric-i4.h (#422) llama.cpp#103, commit
ebeb0e0e— 5 of the 9 updated so far, each change citing its row here:gdn_native_projection_pair_dispatch(element count is the compile parameterllm.gated_delta_net.epilogue_element_count),iq2_codebook_resource_reuse(generic kquant decode; no constant initialization, no transient grid),qwen_token_embedding_dispatch(IQ3_S / IQ4_NL graphs are claimed now),swiglu_q8_output(kquant swiglu -> kquant matmul decode, no alternate),rmsnorm_gate_q8_output(publication viaggml_rmsnorm_gate_f32_q8_1_x4).Suite after that commit: 41 pass / 44 fail (was 36 / 49). The 9 REGRESSION rows and the NEEDS-DEVICE row are untouched and still red, as ruled.
Still to update (not done, and deliberately not guessed at):
gather_add_dispatch,generic_swiglu_k16_publication_edges,rmsnorm_gate_packed_output,qwen_flash_attention_dispatch. Each turns out to have further variants beyond the one that failed first, and each needs its own plan dump before an expectation is written - e.g.gather_add_dispatchalso asserts that several unsupported graph variants stay unsupported, and three of them are claimed now (the dims became runtime arguments), while the strided-coalesced variant is still refused;generic_swiglu_k16_publication_edgeshas a second variant whose producer is neither the deleted publish kernel nor the swiglu matmul the first variant uses;qwen_flash_attention_dispatchfails per-variant on kernel names once the parameter and alternate assertions are fixed. Writing those without the plan in hand would encode whatever the backend happens to do, which is the thing the ruling process exists to avoid.bong-water-water-bong commentedon Oct 18, 2026
Per-variant evidence for the four ACCEPT rows that were still red, gathered on the new base (
8dafc4a0, PR #104, which rewrote the suite into a single fail-fastmain()). The backend did not change between8d9ce2c1aand8dafc4a0— only the test file did — so these plan dumps describe what1bit/hrx-vulkan-patcheddoes today. Dumps are from the scheduler (plankernel names, alt = alternate values, t = transients), temporary instrumentation, reverted.Recommendations are for the owner; I have not edited these tests.
gather_add_dispatchhrx:ggml_gather_add_f32(bindings 4)(2048, 13, 1, false)— the case asserts not supportedggml_get_rows_f32,ggml_get_rows_f32,ggml_binary_strided_f32(2048, 13, 1, true, 1024)(strided-coalesced)(96, 13, 1, true)partial_gather_add_graphqwen_flash_attention_dispatchggml_flash_attention_f32_f16_wmma(bindings 6)ggml_flash_attention_decode_split_f32_f16_wmma_next_q8(bindings 10), alt=1, t=4ggml_attention_rows_f32_f16(bindings 5)dispatch-flash-attention.cpp:449explains the columns-wide copy for MLA); the expected kernel name and its parameter list are what is stale, not the route.rmsnorm_gate_packed_outputggml_rmsnorm_gate_f32_f16,ggml_mul_mat_q4_k_f16_wmma_prefill_wave32; alt=1 for the packed shape, generatedF16K16Majorresource presentggml_rmsnorm_gate_f32_publishproducer and apublish_q8compile parameter. Caveat: the fail-fast run does not reach this case yet (it stops earlier, currently at theqwen_attention_postprocessvariantdispatches.size() == (q8_input ? 5 : 4)), so this dump is from the identical backend via the old runner; re-confirm when the run reaches it.generic_swiglu_k16_publication_edges8dafc4a0); backend unchanged: 1 dispatchggml_mul_mat_swiglu_f32_f32_wmma, no alternateAlso worth recording while it is visible: on the new fail-fast suite the run stops at the first stale expectation, so one red row hides everything after it. Today that is
gather_add(hrx-backend-test.cpp:3731); with that flipped out of the way it stops next atqwen_flash_attention(:3768), then atqwen_attention_postprocess(:4167,dispatches.size() == (q8_input ? 5 : 4)), i.e. rows from the earlier class A set are still red on the rewritten file too. A per-case selector (or a non-fatal mode) would make this suite usable for incremental work; right now every fix is all-or-nothing for the run.bong-water-water-bong commentedon Oct 18, 2026
Carried the ACCEPT rows onto the #104 suite and made the runner per-case: 1bit-MONSTER/llama.cpp#105 (base 1bit/hrx-vulkan-patched @ 8dafc4a0).
Host suite there: 47 passed, 13 failed, 60 total (device cases skip without an HRX device; the fork has no CI, so that table is the gate). The 13 red rows are the class A/B rows plus the NEEDS-DEVICE
qwen_router_top8_dispatch.Also visible now that the suite reports per case: of the 9 REGRESSION rows, six cases no longer exist in #104's suite and the three that remain pass, so #449/#450 currently have no red test protecting them. Left as #104 made them, per the task.
bong-water-water-bong commentedon Oct 18, 2026
Known-regression guards are in (added to the open 1bit-MONSTER/llama.cpp#105, base 8dafc4a0):
[UNEXPECTED-PASS #nnn]and exits non-zero.activation_publication_diagnostics()→alternate_values(), and the symmetric-i4 predicate dropped because its header was deleted in f2099e9b.qwen_router_top8NEEDS-DEVICE row).Also deferred to the next GPU slot and written down in ~/NEED-GPU-T422.md: the 14 device cases, the router measurement, the symmetric-i4 on/off, and the MLA (QK-layout) flash shape that now routes to
ggml_attention_rows_f32_f16(kernel time or tok/s vs the flash kernel, plus logits/argmax equality).bong-water-water-bong commentedon Oct 18, 2026
Hygiene pass (2026-10-18): not fixed yet, and #106 just moved one row, so the classification in this issue needs a re-read before it is acted on.
What is merged in
1bit-MONSTER/llama.cppon1bit/hrx-vulkan-patched(tip953b6397):7227a771: the fail-fastmain()is now a table of cases with a per-case runner, which is the second item of HRX: hrx-backend-test and test-hrx-ops abort on stale kernel-routing expectations #444 and what makes this classification usable (one red row no longer hides the rest). The same commit takes the ACCEPT rows HRX: pin llama.cpp 96f6b89, fixing #95 (GLM-4.7-Flash, Qwen3-Coder at full context) #104 had left stale, and tags the REGRESSION rows as known-fail per HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449/HRX: symmetric-i4 consumer route re-enabled by AMD aadd6025 after f2099e9b removed it #450.953b6397("tests: retire the HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449 guard for gdn rmsnorm-gate publication", engine HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449): one of the HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449 guard rows is retired, with the reason thatloom_libs:ggml_rmsnorm_gate_f32_publishis not a kernel that exists any more but the publication is still done insideggml_rmsnorm_gate_f32_f16/_q8_1_x4throughf16_output_row_width. So at least one row this issue filed under "class C - needs a ruling" has since been ruled.Nothing new was measured in this pass: the host suite needs an HRX build, and the only HRX builds on this box are engine
ExternalProjectbuilds ofllama-server/llama-benchthat need the TheRock toolchain and the GPU lock, so the current 47/13/9/0 totals were not re-taken. Last numbers in this thread are from #449 (66 total: 44 passed, 13 failed, 9 known-fail, 0 unexpected-pass on7227a771).The remaining work is unchanged and is a ruling, not a fix: the class A/B rows are expectation updates, and the class C/D rows have to be decided against what the backend intends on this pin. Suggest the next pass starts from the per-case table #105 produced, retires any row already ruled like #449's gdn rmsnorm-gate one, and keeps the rest red.
bong-water-water-bong commentedon Oct 18, 2026
Device half of the suite, run on strixhalo against gfx1151 (this is the first time these 11 cases have executed since the AMD-core re-head). Build:
1bit/hrx-test-445-ruling@d9fac8aa,-DLLAMA_BUILD_TESTS=ON -DGGML_HRX=ON, hrx-systemd3c731e1, amdclang++ from TheRock for the HIP kernels.Device cases:
scale_f32_device_support,qwen_expert_table_partition_prefill_512_execution,add_f32,scale_f32,scale_f32_inplace,two_independent_add_f32,chained_add_f32,same_uid_distinct_graph_reuses_graph_program(both variants) andunsupported_op_failspass.One device failure:
zero_output_device_support-hrx-backend-test.cpp:8329: ggml_backend_supports_op(backend, cpy)is false, i.e. the backend no longer advertises support for the zero-outputCPYthe case builds, while the case asserts it does. This is a device-only capability row (the host plan path does not asksupports_op), so it was invisible before. Not in the ruled set; listing it here so it can be triaged with the class A/B rows.Two operational notes worth recording for anyone running this suite on the box:
device: skipped, no HRX devices availableunlessIREE_HAL_AMDGPU_LIBHSA_PATHpoints at TheRock'slibhsa-runtime64.so.1(/opt/rocm-therock/lib/python3.14/site-packages/_rocm_sdk_devel/lib/). The distro libhsa rejects the gfx1151 PM4-emulation probe, so HRX registers no device - same reason the engine'shrx_libhsa()exists.-Wno-errorfor the vendored IREE/loom code under GCC 15 (array-bounds,format-overflowfalse positives), hence the compiler wrapper.All nine KNOWN-FAIL rows reported
[KNOWN-FAIL #449]/[KNOWN-FAIL #450]on the device run too, and none reportedUNEXPECTED-PASS- so #449/#450's guards hold on hardware, not just on the CPU planner.bong-water-water-bong commentedon Oct 18, 2026
Device measurement done on strixhalo (gfx1151), which closes this row as ACCEPT.
qwen_router_top8_dispatchis about a plan that gained dispatches and a binding length that no longer equalsroute_id_length. Measured on Qwen3-Coder-30B-A3B-Instruct-Q4_K_M (MoE, 30.5B/A3B; the router is on every token):-dev HRX0 -ngl 99).' Paris. The capital of Belgium is Brussels. What is the capital of Luxembourg?…').qwen3_moe_router_top8_f32+ggml_moe_build_expert_table+ggml_moe_build_expert_partition_table); the two table builders that came with the re-head do not change the result.So the
bindings[1].length == route_id_lengthexpectation is stale (the route ids are described byroute_id_stridenow, and the table builders consume them), not a defect: ACCEPT on this row. Caveat on the record: no pre-re-head build exists on the box, so "was it faster before" was not measured - only that the current numbers are healthy and numerically equal to the CPU path.bong-water-water-bong commentedon Oct 18, 2026
MLA (QK-layout) shape measured on hardware, closing the
qwen_flash_attention_dispatchACCEPT row: the route toggml_attention_rows_f32_f16is equal or better and numerically identical.GLM-4.7-Flash-Q4_K_M (
deepseek229.94B/A3B, MLA) on HRX0,llama-bench -dev HRX0 -ngl 99 -p 512 -n 64 -r 2, one arm per route:common.attention_strided_f32_f16->ggml_attention_rows_f32_f16)GGML_HRX_DISABLE_DISPATCH=common.attention_strided_f32_f16) ->ggml_flash_attention_f32_f16_wmmaGreedy 24-token completion at temperature 0, same prompt/seed: identical between the two arms (
' Paris. The capital of the United Kingdom is London. The capital of the United States is Washington, D.C. The…').So the MLA shape moving off the flash kernel is not a regression: prefill is level within the error bars, decode is ~7 0x0p+0head, and the output is bit-identical on this prompt. Expectation update in 1bit-MONSTER/llama.cpp#105 stands as written.
bong-water-water-bong commentedon Oct 18, 2026
zero_output_device_supportclassified: stale expectation (ACCEPT), and the case has never run before.What it does: builds
3840 x 0tensors (a zero-token batch) and asserts the backend advertises support forADD,MUL,SCALEandCPYon them, and not forACC/SET. On gfx1151 the first four pass exceptCPY:Evidence:
ggml-hrx.cpp:838 zero_output_elision_supported()->zero_output_elision_safe_op()(line 744), a list of ~30 ops (DUP,ADD,ADD1,SUB,MUL,DIV,SUM_ROWS,RMS_NORM,MUL_MAT, ...).GGML_OP_CPYis not in it (0 occurrences in the list).device_supports_op()(line 1132) therefore returns false for that node and falls through to the per-op matchers, none of which claims a zero-element copy. So the backend does not advertise support; it is not a runtime failure, and the node would be placed on the CPU and copy zero bytes.8dafc4a0), is adevice_case, and the device half of this suite had not been executed at all since the re-head - so itsCPYexpectation was never checked against the shipped backend. The elision list itself arrived in AMD's aadd6025 ("add generic gfx1151 graph optimizations").CPY- the only way to get one is the hand-builtggml_cpy(lhs, rhs)the case itself constructs.Recommendation: ACCEPT - change the assertion to
REQUIRE(!ggml_backend_supports_op(backend, cpy))and note that a zero-element copy is a CPU-placed no-op. Two caveats for the record: the omission ofCPYfrom the elision list reads as incidental rather than reasoned (eliding a zero-byte copy is as safe as elidingDUP), and if a real graph ever contains one it costs a graph split, which #390's placement report would then name. If you would rather have the capability, the fix is onecase GGML_OP_CPY:inzero_output_elision_safe_op(), i.e. a backend change, not a test change - say which and I will do it.bong-water-water-bong commentedon Oct 23, 2026
Classification of the host suite at the current engine pin, taken today. Everything here is plan-level
evidence from the scheduler (temporary instrumentation printing
plan.dispatcheskernel names and bindingcounts, reverted afterwards), plus the backend's own
verify_command_program()where the case fails on it.Where this was taken, and one pin caveat
1bit/hrx-vulkan-patched@851fa6c8(3 commits ahead of the engine's llama.cpp pinaf04c9f2;tests/and the corpus are identical to the pin).82804197b, not the engine's pinned98d05d94: the pinned Loom predates themultiple_ofrename that our corpus needs (fork
37c499d5), soloom-linkrejects the corpus at the pinned pair andno test binary can be built there. Reported separately; the numbers below are the first that exist.
-DGGML_HRX=ON -DGGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT=binary -DGGML_HRX_HIP_TARGETS=gfx1151,GCC 15 with a
-Wno-errorwrapper. (The fork also needed a one-line fix to compile at all:op_params_json()had no
PadParamsbranch sinceba64834d/PR Zyphra Zamba2 on Vulkan: carry ggml-org#21412, and a d_state-64 Mamba-2 scan #114 — hard error withGGML_HRX=ON.)None of the original class A/B rows (
scale_add_f32_dispatch,rmsnorm_two_binary_dispatch,graph_index,rope_set_rows_dispatch,get_rows_*,dispatch_registry, …) are red any more: they are green on this pin.The 12 red host rows
qwen_attention_postprocess_dispatchdispatches.size() == (q8_input ? 5 : 4)ggml_kquant_mul_mat_decode_tokens_f32+qwen3_moe_attention_postprocess_f32_f16= 4kquant_mul_mat_decodeconsumes f32 directly, so the separate q8-publication dispatch is gone. Update to 4.qwen_matmul_dispatchdispatches.size() == command_countggml_kquant_mul_mat_decode_tokens_f32command_countisq8_input ? 2 : 1, and there is no quantize dispatch any more.lowtoken_residual_dispatchfused == (c.fused ? 1 : 0)ggml_kquant_mul_mat_decode_f32with 4 bindings (the residual is fused into the kquant decode)ggml_mul_mat_bias_*/…_add_*names as the fused route; the kquant decode row is the fused route now.gdn_selected_rms_q8_dispatchcommand_program_verifies(commands)4 × ggml_scale_f32,llm_gated_delta_net_f32_wmma_head128_selected_snapshot_projection_rms_gate_q8(14 bindings),ggml_mul_mat_f32_f32_wmma,ggml_scale_f32quantized_value_projection_dispatchdispatches.size() == 2llm_attention_v_matmul_set_rows_decode_f32_f32schedule_get_rows_q8_1_alternate_command.{q4_k,bf16}qwen3_moe:qwen3_moe_rmsnorm_f32_quantize_q8_1_x4/b4,qwen3_moe:ggml_linear_q6k_q8_1_x4/b3qwen_router_top8_dispatchbindings[1].length == route_id_lengthqwen3_moe_router_top8_f32/b3+ggml_moe_build_expert_table/b2+ggml_moe_build_expert_partition_table/b2; binding lengths 2048, 1568, 128route_id_stride, the table builders consume them). Only the expectation is stale.common_mul_mat_id_swiglu_dispatch… == "loom_libs:ggml_mul_mat_id_f32_f32_wmma"ggml_mul_mat_id_decode_f32_wave64/b4common.mul_mat_id.decode_f32_wave64is the registration that names the one-token route (same ruling as the Q4_K one-token →ggml_kquant_mul_mat_decode_f32row).qwen_routed_gate_up_dispatchmatch_dispatch_at_index(); the scheduler plan for the graph is router + the two expert-table buildersmatch.dispatchesdump still to be pinned down.common_mul_mat_id_postops_dispatchcommand_program_verifies(commands)ggml_mul_mat_id_postops_f32_f32_wmmarows verifyok=1 errors=0; the…_next_rmsnorm_f32_f32_wmmarow (10 bindings) fails:binding bias value=5 origin=Transient access=Read range=[0,16384) reads transient value 5 before writedisjoint_transient_plan_packingtransients.arena_size == 256ggml_binary_f32, verification clean, 2 allocations, arena 512transient-allocator.cpp:364setsarena_alignment = 256, so 2 × 128 B used to land in one 256 B arena). Worth a row of its own rather than an expectation bump.So: 8 rows are stale expectations whose routes the current registrations do name (and two of those were
already ruled here on hardware), 2 rows are verifier rejects (#533), 1 row is a plan-packing
regression, and 1 row (
schedule_get_rows_q8_1_alternate_command) is a stale expectation whose exactdispatcher still needs pinning down.
The five #449 guards on this pin
Re-pointed at the publication the line actually makes (producer names → "one dispatch writes the
alternate/pack from this value and a consumer reads it"), markers removed:
generic_swiglu_k16_publish,tiled_matmul_alternate_publishandrmsnorm_binary_f16_outputpass. Two still have a real gap and arebeing ruled under #449 rather than papered over:
rmsnorm_binary_k16_output— thepackedcolumn is now correct perhas_qualified_rmsnorm_k16_consumer()(512 × {4096,5120,6144,8192} or 1024 × 5120), but the
hidden == 7168row asserts an f16 alternate thatthis line does not publish at all.
packed_f16_producer_consumer— one table row expects an f16 alternate where the plan produces neither analternate nor a k16-major generated resource.
Both are the same question (“the f16 operand is simply not published for this shape — restore it or rule the
loss accepted with the measured cost”), which is #449's decision, with the A/B
llama-benchnumbers beingtaken now.
What I am doing next
known_fail("#533")so the suite is green except rows pointing at anopen issue, and the packing regression as
known_fail("#<row to file>")unless the packer's change turnsout to be intended.
gpu-holdand the closing totals here.bong-water-water-bong commentedon Oct 23, 2026
Host suite is green at the pin after the expectation pass. Fork PRs:
#126 (test expectations, closes #449) and
#127 (the
test-hrx-opsrunner + the PAD compile fix).The 8 known-fail rows, all pointing at an open issue:
gdn_selected_rms_q8_dispatch,common_mul_mat_id_postops_dispatch#533verify_command_program()rejectsdisjoint_transient_plan_packing#534qwen_attention_postprocess_dispatch,qwen_matmul_dispatch,lowtoken_residual_dispatch#445qwen_router_top8_dispatch,qwen_routed_gate_up_dispatch#445Rows that went green with evidence, beyond the ones listed in my classification comment:
quantized_value_projection_dispatch(one…_set_rows_decode_f32_f32dispatch, no quantize),schedule_get_rows_q8_1_alternate_command.{q4_k,bf16}(q8 rows consumed by the qwen q6k linear or the packedtoken1 final projection),
tiled_matmul_alternate_publish(two consumers now publish both operands,Q8_1 and F16),
packed_f16_producer_consumer,rmsnorm_binary_k16_output,rmsnorm_binary_f16_output,generic_swiglu_k16_publish.One harness bug worth recording:
require_compile_parameter()calledstd::abort()on a mismatch, whichkilled the whole run instead of failing one case — it truncated two runs today and is why the earlier lists
in this thread stopped early. It throws now.
Deferred by the release-candidate holds (re-queued): the device half of this suite and of
test-hrx-ops, andthe 30B-A3B arm of #449's A/B measurement (Qwen3-8B: pp512 2070.84 vs 2115.34, tg128 42.45 vs 42.53 with the
publication path disabled — no measurable cost).
bong-water-water-bong commentedon Oct 23, 2026
Remaining rows, host-side, in fork PR 1bit-MONSTER/llama.cpp#129 (merged #128 already landed the kquant route translation for
test-hrx-ops).Now green with the rule documented in the test:
qwen_matmul_dispatchandqwen_attention_postprocess_dispatch(kquant decode route: one and four dispatches, no separate q8 publication, no q8 transient),lowtoken_residual_dispatch(the residual ADD is folded into the kquant decode store's fourth binding, so the fused counter counts that route),qwen_router_top8_dispatch(route-id binding carriesggml_nbytes(route_ids); the ascending and descending router graphs are claimed on this pin, the case asserted they were refused).Moved to #533:
qwen_attention_postprocess_dispatch's postprocess program andqwen_routed_gate_up_dispatch's decode route failverify_command_program— the second with a forward dependency (command 6 reads a transient command 7 writes). Both taggedknown_fail("#533")and added to that issue.Still
known_fail("#445"), one downstream assertion each, all binding-order/pointer checks left from the pre-re-head helpers rather than routing:qwen_matmul_dispatch:commands.commands.back().bindings.size() == 3(the kquant store carries the residual as a fourth binding),lowtoken_residual_dispatch: the fused counter on a later table row,qwen_router_top8_dispatch: one more unsupported-graph negative block.Suite at the pin: 58 passed, 0 failed, 8 known-fail (#533 x3, #534 x1, #445 x3), 0 unexpected-pass, exit 0. Device half still deferred to the GPU lane.
bong-water-water-bong commentedon Oct 23, 2026
Re-read at the current pin (fork tip
7ca8ba5a+ hrx-system82804197bc, the engine main pair) rather than the olderaf04c9f2/851fa6c8pairs the earlier rulings were written against: fork PR 1bit-MONSTER/llama.cpp#130.qwen_router_top8_dispatchggml_nbytes(route_ids)= 1568 (ne0=8, ne1=4, nb1=512), which is what the command reportsqwen_matmul_dispatchknown_fail("#445")lowtoken_residual_dispatchknown_fail("#445")tokens=1 q4_K fused_exp=1andtokens=1 q4_K fused_exp=0both planggml_kquant_mul_mat_decode_f32/b4(+ggml_binary_f32/b3in the unfused case). Needs the kernel's binding semantics, so it is a kernel-side question, not an expectationqwen_attention_postprocess_dispatchknown_fail("#533")re-confirmedVERIFY-ERROR: command 0 … bindings=12 … query_input value=22 / key_input value=2 / value_input value=15 … reads transient value before writeqwen_routed_gate_up_dispatchknown_fail("#533")re-confirmedVERIFY-ERROR: command 6 … deps=1 … raw_gate value=33 … reads transient value 33 before write by command 7— forward dependencyAlso in that PR: the projection is selected as the last matmul dispatch instead of
dispatches.back()(an unfused residual ends the plan with the ADD), and the expected kernel for that case is now "the table's kernel or one of our registered matmul routes" — the specialised registrations (q6_k packed token1 final projection, kquant decode, wmma/decode) gate on shape and the registry picks between them, so pinning one per row was wrong.Totals at this pin:
hrx-backend-test59 passed, 0 failed, 7 known-fail (#533 x4, #534 x1, #445 x2), 0 unexpected-pass, exit 0;test-hrx-opshost 2 passed, 0 failed (237 device cases still skip). #533 is bw220's — the four rows stay tagged and I have not touched the kernel side.