RX9070XT — どの kernel が実際に選ばれるのか

RX9070XT: Which kernel actually gets selected at runtime?

このページが追う問いは一つ。Q4_K_M を推論する Ollama は、RX9070XT 上で MMVQ・MMQ・BLAS のどれを使うのか?
経路はソースに書いてある。しかし実際に選ばれる経路は実行時にしか決まらない。 Phase A〜F の調査が何を固定し、何を固定できなかったかを、ここで一本の線として読めるようにした。

One question drives this page: when Ollama runs Q4_K_M on an RX9070XT, which path does it actually take — MMVQ, MMQ, or BLAS?
The paths exist in source. But which one is selected only becomes real at runtime. This page traces what Phase A–F fixed, and what remains unresolved.

gfx1201 Q4_K_M Phase A–F 完了 Phase A–F Complete

Step 1 — ソースで分岐を確認する(Phase A) Step 1 — Locate the Dispatch Branch in Source (Phase A)

観測ポイント: 分岐を決める閾値はソースのどこにあるのか。

Observation target: Where in source is the threshold that decides the path?

実機でどの kernel が走っているかを直接読む前に、まず「理論上、どんな条件でどの経路に入るのか」をソースで固定する必要があった。 最初に読むべき場所は ggml_cuda_mul_mat() の dispatch ロジックだ。

Before trying to observe which kernel runs on hardware, we first needed to fix the theoretical routing: under what conditions does each path get selected? The right starting point is the dispatch logic in ggml_cuda_mul_mat().

ggml_cuda_mul_mat() —— Q4_K_M tensor が降りてきた時点の dispatch 分岐 ggml_cuda_mul_mat() —— dispatch branch when a Q4_K_M tensor arrives ne11 ≤ 8 mul_mat_vec_q   decode 小バッチ(vector × matrix)向け   decode small-batch (vector × matrix) ne11 ≤ 256 (Q4_K) mul_mat_q   prefill 中バッチ(src1 を q8_1 に repack して matmul)   prefill mid-batch (repack src1 to q8_1 then matmul) それ以外otherwise ggml_cuda_op_mul_mat_cublas hipBLAS rocBLAS Tensile / Cijk_*

ここで分かること: 分岐は ne11(矩阵の列数 = prompt token 数に対応)で決まる。 短い prompt → MMVQ、中程度 → MMQ、長い prompt → BLAS。これはソースコードの事実であり、gfx1201 固有ではない。

What this tells us: Dispatch is determined by ne11 (matrix columns, corresponding to prompt token count). Short prompt → MMVQ, medium → MMQ, long → BLAS. This is a source-code fact, not gfx1201-specific.

ステップ 1 の結論: 理論上、3 経路すべてが存在する。
→ 次の問い: ではその分岐は RX9070XT 上で「実際に動くバイナリ」として存在しているのか? ソースに書いてあっても、gfx1201 向け hsaco が fatbin に入っていなければ動かない。
Step 1 conclusion: Theoretically, all three paths exist.
→ Next question: Do the binaries for these paths actually exist for gfx1201? Even if the source branch exists, if no gfx1201 hsaco is embedded in the fatbin, it won't run.
ggml dispatch flow — ne11 threshold branches to MMVQ / MMQ / BLAS

クリックで拡大 · Phase A ソース閾値 + Phase D bundle アンカーから生成

Click to enlarge · Generated from Phase A source thresholds + Phase D bundle anchors

Step 2 — gfx1201 向けバイナリが存在するか(Phase C/D/E) Step 2 — Do gfx1201 Binaries Exist? (Phase C/D/E)

観測ポイント: MMVQ・MMQ・BLAS の各経路に対応する gfx1201 hsaco が実際に fatbin に埋め込まれているか。

Observation target: Are gfx1201 hsacos for MMVQ / MMQ / BLAS actually embedded in the fatbin?

Phase C で /proc/<runner>/maps を確認し、12 ライブラリのロードを確認した。 Phase D では libggml-hip.so 内の .hip_fatbin(587 MiB)を解析し、 Phase E で gfx1201 ターゲットの hsaco を逆アセンブルした。

Phase C confirmed that 12 libraries are loaded via /proc/<runner>/maps. Phase D analyzed the .hip_fatbin (587 MiB) inside libggml-hip.so. Phase E disassembled gfx1201-target hsacos.

Bundle サイズSize 主なシンボルKey Symbols 役割Role 対応経路Path
bundle_0012 173 KB dequantize_block_q4_K<float> Q4_K dequantQ4_K dequant shared
bundle_0019 337 KB flash_attn_ext_f16<...> Flash AttentionFlash Attention Attention
bundle_0030 1019 KB mul_mat_vec_q<Q4_K, 1, false> MMVQ anchor(decode 小バッチ)MMVQ anchor (decode small-batch) MMVQ
bundle_0037 17 KB quantize_mmq_q8_1<layout0/1/2> MMQ repack(src1 → q8_1)MMQ repack (src1 → q8_1) MMQ
bundle_0039 332 KB rope_multi / rope_neox / rope_norm RoPE familyRoPE family RoPE
bundle_0096 918 KB mul_mat_q<Q4_K, 8, false> exact Q4_K MMQ anchor(prefill)Exact Q4_K MMQ anchor (prefill) MMQ
Kernels.so-000-gfx1201.hsaco Cijk_S_GA, Cijk_S_PostGSU3 BLAS/Tensile contraction familyBLAS/Tensile contraction family BLAS

※ gfx1201 の wavefront_size = 32(MI25 の 64 と異なる)。v_mfma 命令は現在の検査範囲では検出されていない。

※ gfx1201 wavefront_size = 32 (differs from MI25's 64). No v_mfma instructions detected in the current inspection window.

ここで分かること: MMVQ・MMQ・BLAS のすべての経路に対応する gfx1201 向けバイナリが存在する。 どの経路も「バイナリがない」という理由では動かない、ということはない。

What this tells us: gfx1201 binaries exist for all three paths — MMVQ, MMQ, and BLAS. None of these paths is blocked simply because the binary is missing.

load ≠ dispatch — ステップ 2 の結論と次の問い
ステップ 2 の結論: MMVQ・MMQ・BLAS のすべての gfx1201 バイナリが fatbin に存在する。バイナリの欠如が経路をブロックしているわけではない。
→ 次の問い: ではそのバイナリは live run で実際に dispatch されたのか? バイナリが存在することと、そのカーネルが実際に呼ばれることは別問題。これを確認するのが Step 3 の課題。
Step 2 conclusion: gfx1201 binaries for all three paths exist in the fatbin. No path is blocked by a missing binary.
→ Next question: Were those binaries actually dispatched in a live run? A binary existing in the fatbin is a separate question from whether that binary actually gets dispatched. Verifying this is the challenge of Step 3.

Step 3 — 実行時の信号を読む(Phase F: phase proxy) Step 3 — Reading Runtime Signals (Phase F: phase proxy)

観測ポイント: runtime を壊さずに、「どの dispatch 圏で実行しているか」の信号を得られるか。

Observation target: Can we obtain a signal for "which dispatch zone this run is in" without breaking the runtime?

rocprofv3・ROCBLAS_LAYER などの直接 observer はすべてブロック済み(→ Observer 制約マップ)。 唯一の現実的な手段は response JSONprompt_eval_count を ne11 の proxy として使うことだった。 これはランタイムを壊さず、かつソース側の閾値(ne11 ≤ 8 / ≤ 256)と照合できる。

All direct observers (rocprofv3, ROCBLAS_LAYER, etc.) are blocked (→ Observer Constraint Map). The only practical approach was using prompt_eval_count from response JSON as a proxy for ne11. This doesn't break the runtime, and it can be cross-referenced against source thresholds (ne11 ≤ 8 / ≤ 256).

case prompt_eval_count eval_count eval_duration 判定(近似)Assessment (approx.)
short_np1 3 1 MMVQ 圏
medium_np1 11 1 bundle_0096 寄り(MMQ 側)bundle_0096-leaning (MMQ-side)
long_np1 290 1 境界(fallback or chunking 未確定)Boundary — fallback or chunking, unresolved
short_np16 3 16 0.1479s decode-heavy / prompt MMVQ 圏decode-heavy / prompt MMVQ zone
ステップ 3 の現時点で最も筋のいい読み:
short case(prompt_eval_count = 3)は ne11 ≤ 8 の MMVQ 圏に入っていると読むのが最も自然。 medium case(11)は bundle_0030 の `1..8` 圏を超えており、bounded cluster 内では bundle_0096 側がより自然。 long case(290)は BLAS fallback または internal chunking のどちらかであり、現時点では切り分けできない。
Step 3 — strongest current reading:
The short case (prompt_eval_count = 3) most naturally falls into the MMVQ zone (ne11 ≤ 8). The medium case (11) sits above the bundle_0030 `1..8` range, so within the bounded cluster it aligns more naturally with bundle_0096. The long case (290) is either BLAS fallback or internal chunking — not yet distinguishable.
proxy の限界: 上記は「最も筋のいい読み」であり、確定した dispatch 判定ではない。 prompt_eval_count は response JSON の値であり、kernel launch 時の ne11 を直接読んでいない。 他に runtime を壊さない observer が存在しない現状では、これが現在の frontier。 Proxy limitations: The above is the "most natural reading," not a confirmed dispatch judgment. prompt_eval_count is from the response JSON — it does not directly read ne11 at kernel launch. With no other runtime-safe observer available, this is the current frontier.

このページの結論 Page Conclusion

RX9070XT では MMVQ / MMQ / BLAS の 3 経路すべての gfx1201 バイナリが存在し、 short case(prompt_eval_count = 3)は MMVQ 圏に入ったと読むのが最も自然。 しかし dispatch の直接確認は observer 制約により不可能であり、 phase proxy による近似観測が現時点での限界 On RX9070XT, gfx1201 binaries exist for all three paths — MMVQ, MMQ, and BLAS. The short case (prompt_eval_count = 3) most naturally places in the MMVQ zone. However, direct dispatch confirmation is blocked by observer constraints; phase proxy approximation is the current frontier.

Phase A–F で示せること / 示せないこと What Phase A–F Can and Cannot Show

示せることCan Show 示せないことCannot Show
dispatch 分岐の閾値(ne11 ≤ 8 / ≤ 256)がソースに存在する Dispatch thresholds (ne11 ≤ 8 / ≤ 256) exist in source 実際に「今この MulMat で ne11 が何だったか」 What ne11 actually was for any given MulMat call
MMVQ・MMQ・BLAS の gfx1201 バイナリが fatbin に存在する gfx1201 binaries for MMVQ / MMQ / BLAS exist in the fatbin それぞれのカーネルが live run で dispatch されたか Whether each kernel was dispatched in a live run
phase proxy(prompt_eval_count)が dispatch 圏の近似 signal を与える Phase proxy (prompt_eval_count) provides an approximate dispatch-zone signal bundle_0096 が live short case で実際に踏まれたか(直接確認不可) Whether bundle_0096 was exercised in the live short case (not directly confirmed)
Cijk_* (BLAS/Tensile) family が gfx1201 向けに存在する Cijk_* (BLAS/Tensile) family exists for gfx1201 Cijk_* が short live case に入ったかどうか Whether Cijk_* entered the short live case

未確定事項Open Questions

次の観測点Where to Look Next

→ Path Worklog(調査の時系列記録) → Path Worklog (chronological investigation log)

掲載情報は観測記録に基づきます。「示せないこと」欄は observer 制約による限界であり、調査の欠如ではありません。 Content is grounded in observation logs. "Cannot Show" entries reflect observer constraints, not gaps in investigation effort.