Repository navigation
HRX: restore consumer-driven activation publication (dropped whole in f2099e9b) #449
Description
hrx-backend-test fails 7 host cases because the consumer-driven activation-publication set is gone, and the finding is bigger than the tests: f2099e9b ("hrx: keep our ggml-hrx backend on AMD's core") dropped 27 *_publish_* kernels from the corpus and from dispatch_registration/ in one move. Nothing in the tree registers them any more, and only one of them still has a kernel behind it.
From engine #445's ruling row set (class C REGRESSION + gdn_rmsnorm_gate_dispatch).
Kernel list: corpus / registered today
loom_libs:ggml_mul_mat_tiled_input_f32_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_tiled_input_f32_publish_f32_aligned corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_tiled_input_f32_publish_f32_f16_alternate corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_tiled_input_f32_{bias_residual,iq1_m,iq1_s,iq2_s,iq3_s,iq3_xxs}_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_tiled_pair_input_f32_binary_publish_f32{,_k16} corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_tiled_pair_input_f32_binary_bias_residual_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_skinny_input_f32_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_skinny_input_f32_bias_residual_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_id_{tiled,skinny}_input_f32_publish_f32 corpus=N reg=N f2099e9b / 56c3c8a3
loom_libs:ggml_mul_mat_id_*_postops[_next_rmsnorm]_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_mul_mat_id_*_swiglu_publish_f32 corpus=N reg=N f2099e9b
loom_libs:ggml_rmsnorm_binary_q8_1_x4_publish corpus=N reg=N f2099e9b
loom_libs:ggml_rmsnorm_binary_f16_publish corpus=N reg=N f2099e9b
loom_libs:ggml_binary_f32_publish_q8_1_x4 corpus=N reg=N f2099e9b
loom_libs:ggml_binary_bc_f32_publish_q8_1_x4 corpus=N reg=N f2099e9b
loom_libs:ggml_flash_attention_f32_f16_wmma_publish_f16 corpus=N reg=N f2099e9b
loom_libs:ggml_rmsnorm_gate_f32_publish corpus=Y reg=N f2099e9b <-- kernel still builds
qwen3_moe:qwen3_moe_routed_down_weighted_reduce_next_rmsnorm_f32_publish_q8 corpus=N reg=N f2099e9b
Per-shape cost (the plan each case produces now)
| Case (#445 row) | Expected | Plan now |
|---|---|---|
packed_f16_producer_consumer |
f16 alternate from a publishing producer | ggml_copy_f16_k16_major, ggml_mul_mat_swiglu_q4_k_f16_wmma_prefill_wave32, ggml_mul_mat_q6_k_f16_wmma_prefill_wave32; alternate == nullptr |
generic_swiglu_k16_publish |
publish producer | ggml_mul_mat_swiglu_f32_f32_wmma, ggml_copy_f16_k16_major, ggml_mul_mat_q6_k_f16_wmma_prefill_wave32 |
tiled_matmul_alternate_publish |
publish producer | ggml_mul_mat_f32_f32_wmma, ggml_copy_f32_f16, ggml_mul_mat_q6_k_f16_wmma_prefill_wave32 |
rmsnorm_binary_k16_output |
packed-f16 publish producer | ggml_rmsnorm_binary_f32, ggml_copy_f16_k16_major, ggml_mul_mat_q4_k_f16_wmma_prefill_wave32 |
rmsnorm_binary_f16_output |
f16 publish producer | ggml_rmsnorm_binary_f32, ggml_copy_f32_f16, ggml_mul_mat_q4_k_f16_wmma_prefill_wave32 |
qwen_decode_publication_consumer_qualification |
q8 alternate present | ggml_binary_f32, ggml_kquant_mul_mat_decode_tokens_f32; no alternate |
qwen_weighted_reduce_next_rmsnorm_q8_publication |
..._publish_q8 producer |
no such kernel in the corpus |
gdn_rmsnorm_gate_dispatch |
ggml_rmsnorm_gate_f32_publish |
kernel exists (corpus=Y), registered nowhere -> unreachable |
Cost: where the producer used to publish a packed/q8 value as part of its own dispatch, the plan now runs an explicit ggml_copy_* dispatch (one extra dispatch per layer on the affected paths), or loses the fused q8 publication. ggml_rmsnorm_gate_f32_publish is the cheap one: the kernel still builds, so a registration would restore it.
What to decide
- Restore the publication set (kernels + registrations) from the pre-f2099e9b tree, and re-point the tests; or
- Rule the loss accepted, in which case the 7 class C cases become expectation updates (they are the only red left of their kind) and this issue is the record of the cost.
The eight test rows stay red until one of those happens; nothing in this issue asks for a test edit.
Related: engine #445 (ruling comment), 1bit-MONSTER/llama.cpp#103 (the build/port PR; those rows are untouched there on purpose).
Activity
bong-water-water-bong commentedon Oct 18, 2026
The accepted regression now has a guard that cannot be quietly accepted: 1bit-MONSTER/llama.cpp#105 (added to the open #105 branch, base 8dafc4a0).
hrx-backend-testrunner has a KNOWN-FAIL status: a tagged case must fail, prints[KNOWN-FAIL #449]and is counted apart from real failures; if it ever passes it prints[UNEXPECTED-PASS #449]and the run exits non-zero, so the marker has to be retired on purpose.activation_publication_diagnostics()isalternate_values()now):generic_swiglu_k16_publish,tiled_matmul_alternate_publish,rmsnorm_binary_f16_output,qwen_decode_publication_consumer_qualification,qwen_weighted_reduce_next_rmsnorm_q8_publication(re-added - HRX: pin llama.cpp 96f6b89, fixing #95 (GLM-4.7-Flash, Qwen3-Coder at full context) #104 had deleted them) andpacked_f16_producer_consumer,rmsnorm_binary_k16_output,gdn_rmsnorm_gate_dispatch(put back from HRX: pin llama.cpp 96f6b89, fixing #95 (GLM-4.7-Flash, Qwen3-Coder at full context) #104's rewritten-to-pass versions).Host suite on CPU: 66 cases - 44 passed, 13 failed, 9 known-fail #449/#450, 0 unexpected-pass. All eight #449 rows report KNOWN-FAIL, so the lost publication paths stay visible until the kernels and registrations come back or the loss is ruled accepted, at which point the tag is removed deliberately.
bong-water-water-bong commentedon Oct 18, 2026
Per-family evidence for the 8 #449 known-fail guards, gathered on the current line: fork
1bit/hrx-vulkan-patched@7227a77, hrx-system2ab3114966a4,hrx-backend-testbuilt Releaseagainst
HRX_SOURCE_DIR, host suite on CPU (ryzen, no GPU). Baseline on this pin is exactly what theguard PR reported: 44 passed, 13 failed, 9 known-fail, 0 unexpected-pass, 66 total. Each guard was run
with a temporary plan dump (kernel names, bindings, alternates, generated resources; reverted).
Correction to this issue's kernel table
There is no
*publish*-named kernel in the corpus on this pin at all. Countingkernel.def export(...)names across the four manifests: 124 exports, 0 containingpublish. In particularggml_rmsnorm_gate_f32_publishis corpus=N, not corpus=Y: the AMD-core re-head kept thermsnorm_gate_f32.publish_bodytemplate and split it into two exports,ggml_rmsnorm_gate_f32_f16andggml_rmsnorm_gate_f32_q8_1_x4, with the publication format as acompile parameter. So the "cheap one, only the registration was removed" premise in the task does not
hold; whatever is restored here has to be written for the current corpus, not re-registered.
What each guard actually fails on, and what that means
gdn_rmsnorm_gate_dispatchggml_rmsnorm_gate_f32_publishllm_gated_delta_net_f32_wmma_head128,ggml_copy_f32,ggml_rmsnorm_gate_f32_f16(5 bindings, publishes a 262144 B F16K16Major generated resource),ggml_mul_mat_q4_k_f16_wmma_prefill_wave32(f16_input_layout=1),ggml_scale_bias_f32qwen_decode_publication_consumer_qualification(q8 != nullptr) == test.q8on theUnsupportedWeightcaseqwen3_moe_rmsnorm_f32_quantize_q8_1_x4publishes a 2304 B q8_1 x4 alternate for a BF16 consumer (and for a 63-output consumer);DenseandAliasedDenseare finehas_decode_q8_consumer()indispatch-qwen-rmsnorm.cppaccepts any MUL_MAT/MUL_MAT_ID consumer. A qualified-consumer check restores it (Q4_K/Q6_K weights with the right geometry; the q8-consuming consumer kernels exist:qwen3_moe_dense_linear_q4k_q8_1_x4_next_q8,..._routed_gate_up_swiglu_q4k_q8). TheRoutedRoutecase additionally needs the routed chain to be qualified as a whole, not just the first consumer.qwen_weighted_reduce_next_rmsnorm_q8_publicationqwen3_moe_routed_down_weighted_reduce_f16_f32(4 bindings, no alternate); the fused..._next_rmsnorm_f32path exists (5 bindings) but is not matched in this graphqwen3_moe_routed_down_weighted_reduce_next_rmsnorm_q8_1_x4, qwen_moe manifest, config decls identical to the f32 variant) and registered nowhere. Needs the registration plus the consumer qualification, i.e. the same work as the row above.rmsnorm_binary_k16_outputproducerisggml_rmsnorm_binary_f32_k16ggml_rmsnorm_binary_f32,ggml_copy_f16_k16_major,ggml_mul_mat_q4_k_f16_wmma_prefill_wave32has_qualified_rmsnorm_k16_consumer()allows only tokens=512 x hidden {4096,5120,6144,8192} and 1024 x 5120. The kernel itself needs hidden a multiple of 1024 in [1024,8192], so the guard's 3072 case cannot be served by it at all; 2048 can. Either restore a 128-wide k16 publisher or split the row.rmsnorm_binary_f16_outputproducerisggml_rmsnorm_binary_f32_f16ggml_rmsnorm_binary_f32,ggml_copy_f32_f16,ggml_mul_mat_q4_k_f16_wmma_prefill_wave32(f16 alternate 7340032 B present)_f32_f16export in the corpus; the f16 alternate exists but costs a separate copy dispatch per layer.tiled_matmul_alternate_publishggml_mul_mat_tiled_input_f32_publish_f32_f16_alternateggml_mul_mat_f32_f32_wmma,ggml_copy_f32_f16,ggml_mul_mat_q6_k_f16_wmma_prefill_wave32(f16 alternate present)mul_mat_f32_f32_wmma.generic_swiglu_k16_publishggml_mul_mat_tiled_pair_input_f32_binary_publish_f32_k16ggml_mul_mat_swiglu_f32_f32_wmma,ggml_copy_f16_k16_major,ggml_mul_mat_q6_k_f16_wmma_prefill_wave32packed_f16_producer_consumer(alternate != nullptr) == test.alternateon the first sub-case that expects the f16 alternateggml_copy_f16_k16_major,ggml_mul_mat_swiglu_q4_k_f16_wmma_prefill_wave32(f16_output_layout=1), q6_k projection; two F16K16Major generated resources, no f16 alternateShape of the remaining work, cheapest first
qwen_weighted_reduce_next_rmsnorm_q8_publication: register the q8 kernel that is already in thecorpus. Needs a device check (numbers + logits against the f32 path).
qwen_decode_publication_consumer_qualification: make publication consumer-driven again indispatch-qwen-rmsnorm.cpp; same device check, plus the negative cases are plan-level and cheap.rmsnorm_binary_k16_output/rmsnorm_binary_f16_output: backend kernel work (k16 for 128-widehiddens,
_f32_f16export for the plain f16 alternate), then the shape gate.tiled_matmul_alternate_publish,generic_swiglu_k16_publish,packed_f16_producer_consumer: onefamily, the f16/k16 alternate emitted from inside the producer; biggest kernel-side job.
Items 1 and 2 change what runs on the device, so each gets
test-backend-ops -b HRX0plus a Qwen3 MoEand a dense model tg/pp A/B against this pin (dispatch count per token, tok/s) and the needle 7341
@4732 before a marker is retired; items 3 and 4 additionally need pp/tg on the affected prefill shapes.
Everything above is plan-level evidence only; no device run was made for this comment.
Command for reproducing the plan dumps: build
hrx-backend-testwith-DGGML_HRX=ON -DGGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT=binary -DHRX_SOURCE_DIR=<hrx-system at 2ab3114966a4>and
-DGGML_HRX_HIP_TARGETS=gfx1151, then run it on CPU (the device cases skip without a GPU).bong-water-water-bong commentedon Oct 18, 2026
Hygiene pass (2026-10-18): the fork side moved, the issue is not fixed end to end, so this stays open.
Correction to this issue's own list. The original comment named
gdn_rmsnorm_gate_dispatchas one of the rows this issue files against. That row has since been ruled the other way and retired: fork #106 (953b6397, "tests: retire the #449 guard for gdn rmsnorm-gate publication", engine #449). The reason given is thatloom_libs:ggml_rmsnorm_gate_f32_publishwas not a kernel that shipped and died -ggml_rmsnorm_gate_f32_f16and_q8_1_x4run the samepublish_bodyand publish the packed alternate from inside their own dispatch, selected byf16_output_row_width, so the row's "publication unreachable" claim did not hold on this pin. If that reasoning is right it belongs here too, because it says the set is smaller than 8; worth a ruling rather than another guard.What is still red on purpose, at branch tip
953b6397(tests/hrx-backend-test.cpp, tagged"#449"):packed_f16_producer_consumer,rmsnorm_binary_k16_output,generic_swiglu_k16_publish,tiled_matmul_alternate_publish,rmsnorm_binary_f16_output,qwen_decode_publication_consumer_qualification,qwen_weighted_reduce_next_rmsnorm_q8_publication- 7 rows, plus#450'ssymmetric_i4_consumer_qualification. Totals after #106: 45 passed, 13 failed, 8 known-fail, 0 unexpected-pass (66), from that commit's own message.Not done here. No suite run and no build: an HRX build on this box is the engine's
ExternalProject(TheRock toolchain, GPU lock) and the box was busy withhw_gate. The per-family evidence already in this thread stands; what is missing is the ruling on the remaining 7 rows, not a measurement.Closing this needs either the kernels back (or the registration fixed) so the 7 rows pass, or a per-row ruling like #106's that retires them with the reason. Until then the tags are correct and the runner keeps them from being quietly accepted.
bong-water-water-bong commentedon Oct 18, 2026
Device verification of the #449 guards, from the T422 GPU slot (strixhalo, gfx1151, build
d9fac8aa):hrx-backend-test, all eightknown_fail("#449")rows report KNOWN-FAIL, noneUNEXPECTED-PASS:packed_f16_producer_consumer,rmsnorm_binary_k16_output,gdn_rmsnorm_gate_dispatch,generic_swiglu_k16_publish,tiled_matmul_alternate_publish,rmsnorm_binary_f16_output,qwen_decode_publication_consumer_qualification,qwen_weighted_reduce_next_rmsnorm_q8_publication.zero_output_device_support, asupports_opcapability claim - reported on hrx-backend-test: 49 host cases red after the AMD-core re-head — classification (stale expectation vs needs a ruling) #445, unrelated to publication). Host part unchanged at 44/13/9.So the publication losses this issue records are still visible on hardware, and the guards cannot rot silently: the day the kernels and registrations come back (or the loss is ruled accepted), the row turns
UNEXPECTED-PASSand the run fails until the marker is retired on purpose.bong-water-water-bong commentedon Oct 18, 2026
Items 1 and 2 are implemented and past the device gate. Both PRs stacked, markers retired in the same PRs.
What changed. (1) llama.cpp#107 registers
qwen3_moe:qwen3_moe_routed_down_weighted_reduce_next_rmsnorm_q8_1_x4, which was in the corpus and registered nowhere: the fused reduce+next-RMSNorm publishes the Q8_1 x4 next-projection input in place of the f32 row (same five bindings as the f32 form, so it removes the f32 row and the separate quantize). (2) llama.cpp#108 makesdispatch-qwen-rmsnorm.cpppublication consumer-driven again:has_decode_q8_consumer()accepted any MUL_MAT/MUL_MAT_ID, so it quantized a value for BF16 and 63-output consumers too. Both use one shared qualification header (qualified dense q8 projection, directly or through a full-range alias, or the fused routed-MoE chain).Device gate, HRX0 on strixhalo (Thermal-run wrapper, one process at a time, Tctl <= 65 C):
test-backend-ops -b HRX0: Testing 2 devices, Backend 1/2: HRX0, 1141/1141 tests passed.-p 512 -n 128 -r 2 -dev HRX0 -ngl 99 -t 4, every rowdevices=HRX0,gpu_info=AMD Radeon 8060S Graphics (gfx1151):953b6397341, ptok 4732, same sha each rep.qwen_router_top8_dispatch.Box note, affects other slots. HRX registers no device unless
IREE_HAL_AMDGPU_LIBHSA_PATHpoints at TheRock'slibhsa-runtime64.so.1(~/therock100/lib/python3.14/site-packages/_rocm_sdk_core/lib/…): the distro's answers the PM4_EMULATION probe wrongly on gfx1151, which is whatcmake/hrx.cmakedocuments. Without itllama-bench --list-devicesprints(none),test-backend-ops -b HRX0silently runs CPU-only ('Skipping'), andllama-serversays 'no usable GPU found';backends=HRXin a llama-bench CSV only means the registry loaded, not that a device was used. Worth re-checking any earlier HRX device results that did not pass this variable.Remaining for #449: items 3-4 (rmsnorm_binary k16/f16 fused publisher, tiled-matmul and swiglu f16/k16 producers) are the four fused-producer rows; per the orchestrator they wait until these two land.
Move the llama.cpp pin to 00f2a68de: qwen3moe q8 next-RMSNorm writes …
bong-water-water-bong commentedon Oct 23, 2026
Ruled out / landed at the current pin, PR: 1bit-MONSTER/llama.cpp#126 (closes this issue).
Short version: the corpus on this pin has 99 kernels and none named
publish— publication is done in the consumer (common_prepare_f16_input()emitsggml_copy_f32_f16/common.mul_mat.f16and records the alternate;common_prepare_k16_major_f16_input()the same for the F16K16Major pack), so what f2099e9b removed is the fusion into the producing dispatch, not the publication. The five remainingknown_fail("#449")guards now assert that publication and all five pass; markers retired.Measured cost of the whole F16/K16 path on/off (arm B disables
common.mul_mat.f16,…k16_major_f16,…swiglu.k16_major_f16,…rmsnorm_binary.k16_major_f16,…rmsnorm_gate.k16_major_f16), strixhalo gfx1151, llama-bench-p 512 -n 128 -r 2 -dev HRX0 -ngl 99 -t 4, 90 W cap, PCM pad (23 Oct): Qwen3-8B pp512 2070.84 ± 5.62 vs 2115.34 ± 24.50 t/s, tg128 42.45 ± 0.05 vs 42.53 ± 0.03 t/s — publishing costs nothing measurable, which is why the two shapes where nothing is published (rmsnorm_binary hidden 7168, the two-token silu graph) are ruled out rather than restored from history.Host suite at the pin: 58 passed, 0 failed, 8 known-fail (#533 x2, #534, #445 x5), 0 unexpected-pass, exit 0. Device half and the 30B-A3B arm were cut short by the release-candidate holds and are re-queued.
bong-water-water-bong commentedon Oct 23, 2026
Closed by 1bit-MONSTER/llama.cpp#126 (merged 9b846c17, pi issues-b): on the current pin the corpus has no publish kernels because consumer-driven publication happens in the consumer (common_prepare_f16_input / common_prepare_k16_major_f16_input record the alternate; the gated producers that fuse the pack are still registered). What f2099e9b removed was the fusion of the pack into the producing dispatch, not the publication; hrx-backend-test now asserts the publication each line makes, and the eight known_fail("#449") rows are retired. Cross-repo 'Closes' does not fire from the fork, hence this manual close.