Status
Ongoing — data collection in progress
Snapshot
430 tests across 170 configurations
Recorded
2026-07-31T21:39:58Z to 2026-08-01T04:40:38Z
Built
2026-08-01 05:03 UTC from 8577ff5
code
import marimo as mo
import pandas as pd

from llmbench import (
    as_table,
    audit_runs,
    backend_contrast,
    contrast,
    coverage_matrix,
    depth_contrast,
    figure_html,
    find_results,
    kv_contrast,
    load_runs,
    missing_cells,
    model_catalog,
    plot_backend_ratio,
    plot_depth_scaling,
    plot_kv_penalty,
    plot_throughput_interactive,
    summarize,
    to_wide,
    use_study_style,
)

use_study_style()
pd.set_option("display.width", 200)

KV cache and context depth on a gfx1151 iGPU

Throughput measurements for four models people actually run locally for coding, on an AMD Ryzen AI MAX+ 395 w/ Radeon 8060S (gfx1151, 128 GB unified memory), across five KV cache type pairs and two context depths, recorded under both the ROCm and the Vulkan build of llama.cpp.

What this is. A record of how throughput responds to configuration on one machine: KV cache type, context depth, and which model is loaded.

What this is not. A comparison of ROCm against Vulkan. The two builds are from different llama.cpp commits made days apart, so a difference between them cannot be attributed to the backend rather than to everything else that changed between those commits. Results are reported per backend, within each backend, and are not ranked against each other.

This notebook also does not explain why any measured difference occurs. Where a measurement has more than one possible explanation, the alternatives are left open.

Read the audit section before quoting any number from here.

code
runs = load_runs(find_results(__file__))
code
# Architecture token of `model_type`, per model label. Summaries below group
# by it because the measurements separate along that line.
families = dict(zip(runs["bench_model"], runs["family"], strict=True))

What was measured

data/results.jsonl is the raw llama-bench --output jsonl log, appended to as runs complete and never edited. This snapshot holds 430 tests recorded between 2026-07-31T21:39:58Z and 2026-08-01T04:40:38Z.

Each record is one test. Two metrics are measured at each context depth:

metric meaning
pp2048 prefill: process a 2048-token prompt at cache depth d
tg128 decode: generate 128 tokens from the same depth

The four factors that vary are the harness-injected fields bench_model, bench_backend, bench_depth and bench_kv. Everything else — batch size, thread count, flash attention, layer offload — is held fixed, and the audit below verifies that claim rather than trusting it.

code
model_catalog(runs)
bench_modelmodel_filenamemodel_typefamilyquantdynamic_quantsize_gibparams_bn_tests
0agentworldQwen-AgentWorld-35B-A3B-UD-Q4_K_XL.ggufqwen35moe 35B.A3B Q4_K - Mediumqwen35moeUD-Q4_K_XLTrue20.7834.66130
1glmGLM-4.7-Flash-Q4_K_M.ggufdeepseek2 30B.A3B Q4_K - Mediumdeepseek2Q4_K_MFalse17.0529.94100
2glm-xlGLM-4.7-Flash-UD-Q4_K_XL.ggufdeepseek2 30B.A3B Q4_K - Mediumdeepseek2UD-Q4_K_XLTrue16.3129.94100
3qwenQwen3.6-35B-A3B-Q4_K_M.ggufqwen35moe 35B.A3B Q4_K - Mediumqwen35moeQ4_K_MFalse19.7034.66100

Audit

This is the part that bounds what the rest of the notebook can say. Each check either passes, raises a caveat that constrains interpretation, or raises a blocker that would invalidate a comparison.

code
audit = audit_runs(runs)
audit.to_frame()
severitycheckdetail
0caveatbuild provenanceeach backend was built from a different llama.cpp commit (rocm=a66d505, vulkan=d6d899580). Backend differences are therefore confounded with build version and cannot be attributed to the backend alone
1caveatdesign balance30 of 200 factorial cells were never run (missing per model: {'glm': 10, 'glm-xl': 10, 'qwen': 10}). An unpaired mean over the whole frame would mix different sets of conditions, so every comparison in this study is paired within a configuration
2caveatmeasurement protocolsprefill length is not the same at every depth — d1024→['pp1024', 'pp512', 'tg128']; d2048→['pp1024', 'pp512', 'tg128']; d8192→['pp1024', 'pp512', 'tg128']; d16384→['pp2048', 'tg128']; d32768→['pp2048', 'tg128']. Prefill ratios across depths with different pp sizes are not the same test; tg128 is the decode metric shared by every depth
3caveatreplicationall 430 tests are a single repetition, so stddev_ts is 0 by construction. Run-to-run variance is unmeasured, and differences of a few percent cannot be distinguished from noise
4okfactors4 factors (bench_model=4, bench_backend=2, bench_depth=5, bench_kv=5); all 11 other runtime knobs held constant
5okmachineidentical across all 430 records
6okmetric completenesswithin each depth, every config has that depth's metrics (d1024: ['pp1024', 'pp512', 'tg128']; d2048: ['pp1024', 'pp512', 'tg128']; d8192: ['pp1024', 'pp512', 'tg128']; d16384: ['pp2048', 'tg128']; d32768: ['pp2048', 'tg128'])
7oktest shapesmetrics measured: ['pp1024', 'pp2048', 'pp512', 'tg128']
8okuniquenessexactly one record per (config, test_type)
code
_caveats = len(audit.to_frame().query("severity == 'caveat'"))
mo.md(f"""
**{len(audit.blockers)} blockers, {_caveats} caveats.** The caveats above
carry through everything below, and they are why ratios are reported as
ranges rather than single figures:

* **One repetition per test.** `stddev_ts` is zero by construction, so
  run-to-run variance is unmeasured. Differences of a few percent are not
  separable from noise, and no percentage here should be read to two
  decimal places.
* **The two builds are not a controlled comparison.** ROCm and Vulkan
  records carry different `build_commit` values, from commits made days
  apart, and no record varies one while holding the other fixed. Nothing
  below reads across the two builds as a backend comparison.

Every comparison below is computed pairwise *within* a configuration: one
factor varies, all other factors are held fixed, and a pair with a missing
side is dropped rather than filled in. The factor list is derived from the
log, so sweeping a new runtime knob adds it to the configuration key rather
than being averaged over.
""")

0 blockers, 4 caveats. The caveats above carry through everything below, and they are why ratios are reported as ranges rather than single figures:

  • One repetition per test. stddev_ts is zero by construction, so run-to-run variance is unmeasured. Differences of a few percent are not separable from noise, and no percentage here should be read to two decimal places.
  • The two builds are not a controlled comparison. ROCm and Vulkan records carry different build_commit values, from commits made days apart, and no record varies one while holding the other fixed. Nothing below reads across the two builds as a backend comparison.

Every comparison below is computed pairwise within a configuration: one factor varies, all other factors are held fixed, and a pair with a missing side is dropped rather than filled in. The factor list is derived from the log, so sweeping a new runtime knob adds it to the configuration key rather than being averaged over.

code
coverage_matrix(runs)
bench_backendrocmvulkan
bench_kvf16/f16f16/q4_0f16/q8_0q4_0/q4_0q8_0/q8_0f16/f16f16/q4_0f16/q8_0q4_0/q4_0q8_0/q8_0
bench_modelbench_depth
agentworld10243333333333
20483333333333
81923333333333
163842222222222
327682222222222
....................................
glm-xl327682222222222
qwen10243333333333
20483333333333
163842222222222
327682222222222

17 rows × 10 columns

code
_absent = len(missing_cells(runs))
mo.md(f"""
Each cell above counts tests: `2` means both metrics were measured, `0`
means the cell was never run. Unmeasured cells in the factorial design:
**{_absent}**.

## The measurements

One row per configuration, both metrics side by side.
""")

Each cell above counts tests: 2 means both metrics were measured, 0 means the cell was never run. Unmeasured cells in the factorial design: 30.

The measurements

One row per configuration, both metrics side by side.

code
wide = to_wide(runs)
wide
bench_modelbench_backendbench_depthbench_kvpp1024pp2048pp512tg128kv_class
0agentworldrocm1024f16/f161017.333157NaN974.25686351.219241baseline f16 K, f16 V
1agentworldrocm1024f16/q8_0122.712208NaN143.01664737.154560asymmetric f16 K, quantized V
2agentworldrocm1024f16/q4_0115.862083NaN132.03667835.536938asymmetric f16 K, quantized V
3agentworldrocm1024q8_0/q8_0971.626040NaN994.37336050.733497symmetric quantized K and V
4agentworldrocm1024q4_0/q4_0976.085083NaN1006.95363449.839200symmetric quantized K and V
..............................
165qwenvulkan32768f16/f16NaN614.195671NaN58.824494baseline f16 K, f16 V
166qwenvulkan32768f16/q8_0NaN575.443122NaN61.970905asymmetric f16 K, quantized V
167qwenvulkan32768f16/q4_0NaN563.899297NaN63.163770asymmetric f16 K, quantized V
168qwenvulkan32768q8_0/q8_0NaN501.106428NaN63.703745symmetric quantized K and V
169qwenvulkan32768q4_0/q4_0NaN512.416742NaN65.683514symmetric quantized K and V

170 rows × 9 columns

code
model_filter = mo.ui.multiselect(
    options=sorted(wide["bench_model"].unique()),
    value=sorted(wide["bench_model"].unique()),
    label="models",
)
kv_filter = mo.ui.multiselect(
    options=list(dict.fromkeys(wide["bench_kv"])),
    value=list(dict.fromkeys(wide["bench_kv"])),
    label="KV cache types",
)
mo.hstack([model_filter, kv_filter], justify="start", gap=2)
code
view = wide[
    wide["bench_model"].isin(model_filter.value)
    & wide["bench_kv"].isin(kv_filter.value)
]
view
bench_modelbench_backendbench_depthbench_kvpp1024pp2048pp512tg128kv_class
0agentworldrocm1024f16/f161017.333157NaN974.25686351.219241baseline f16 K, f16 V
1agentworldrocm1024f16/q8_0122.712208NaN143.01664737.154560asymmetric f16 K, quantized V
2agentworldrocm1024f16/q4_0115.862083NaN132.03667835.536938asymmetric f16 K, quantized V
3agentworldrocm1024q8_0/q8_0971.626040NaN994.37336050.733497symmetric quantized K and V
4agentworldrocm1024q4_0/q4_0976.085083NaN1006.95363449.839200symmetric quantized K and V
..............................
165qwenvulkan32768f16/f16NaN614.195671NaN58.824494baseline f16 K, f16 V
166qwenvulkan32768f16/q8_0NaN575.443122NaN61.970905asymmetric f16 K, quantized V
167qwenvulkan32768f16/q4_0NaN563.899297NaN63.163770asymmetric f16 K, quantized V
168qwenvulkan32768q8_0/q8_0NaN501.106428NaN63.703745symmetric quantized K and V
169qwenvulkan32768q4_0/q4_0NaN512.416742NaN65.683514symmetric quantized K and V

170 rows × 9 columns

Measurement 1 — KV cache type, within each backend

KV cache type is the factor associated with the largest measured spread in this dataset. Note the log y-axis: on a linear axis the smallest values flatten against the bottom of the plot and read as missing data.

Click a legend entry to hide or isolate a series, and hover any point for the exact configuration and throughput. Each panel is one backend and one metric; compare within a panel.

Models are grouped by the architecture token of model_typeqwen35moe (qwen, agentworld) and deepseek2 (glm, glm-xl) — because the measurements separate along that line. f16/q8_0 and f16/q4_0 are labelled asymmetric (f16 keys, quantised values); q8_0/q8_0 and q4_0/q4_0 are symmetric. Those are descriptions of the K/V pair, not of a mechanism.

code
mo.iframe(figure_html(plot_throughput_interactive(wide)), height="1700px")
code
kv = kv_contrast(wide)
code
plot_kv_penalty(kv)
figure
code
summarize(
    kv.assign(arch=kv["bench_model"].map(families)),
    ["bench_backend", "arch", "kv_class", "metric"],
)
bench_backendarchkv_classmetricnmedian_ratiomin_ratiomax_ratio
0rocmqwen35moeasymmetric f16 K, quantized Vpp204880.0161770.0116860.022459
1rocmqwen35moeasymmetric f16 K, quantized Vpp1024100.0921560.0330530.135175
2rocmqwen35moeasymmetric f16 K, quantized Vpp512100.0951630.0342810.146796
3rocmqwen35moeasymmetric f16 K, quantized Vtg128180.3049680.0981340.725402
4vulkandeepseek2symmetric quantized K and Vpp204880.4743820.4303220.510237
...........................
27rocmqwen35moesymmetric quantized K and Vpp1024101.0017080.9550721.011621
28vulkandeepseek2asymmetric f16 K, quantized Vpp102481.0029010.9987531.009310
29rocmdeepseek2asymmetric f16 K, quantized Vpp102481.0066490.9887811.014786
30vulkanqwen35moeasymmetric f16 K, quantized Vtg128181.0118260.9934871.073766
31vulkanqwen35moesymmetric quantized K and Vtg128181.0211910.9971991.116601

32 rows × 8 columns

code
_worst = kv.nsmallest(1, "ratio").iloc[0]
mo.md(f"""
Each row of the table above is 8 pairs: 2 models × 2 depths × 2 KV pairs of
that shape, each compared against `f16/f16` at the same model, depth and
backend.

The two largest effects in the dataset fall on different backends *and*
different architectures — ROCm with `qwen35moe` under asymmetric KV, and
Vulkan with `deepseek2` under symmetric KV. In each case the same models and
KV pairs measured on the other backend land close to their own `f16/f16`
baseline. The single largest is `{_worst["bench_model"]}` on
`{_worst["bench_backend"]}` at depth {_worst["bench_depth"]}, `{_worst["level"]}`:
{_worst["metric"]} of {_worst["to"]:.2f} t/s against {_worst["from"]:.2f} t/s
at `f16/f16`, a ratio of {_worst["ratio"]:.4f}x.

**Not established by this data.** Whether the ROCm asymmetric result
reflects a different code path, a fallback, a build-specific behaviour, an
interaction with `flash_attn=1`, or something else. `flash_attn` is 1 in
every record, so this log contains no contrast that separates those.
""")

Each row of the table above is 8 pairs: 2 models × 2 depths × 2 KV pairs of that shape, each compared against f16/f16 at the same model, depth and backend.

The two largest effects in the dataset fall on different backends and different architectures — ROCm with qwen35moe under asymmetric KV, and Vulkan with deepseek2 under symmetric KV. In each case the same models and KV pairs measured on the other backend land close to their own f16/f16 baseline. The single largest is agentworld on rocm at depth 32768, f16/q4_0: pp2048 of 6.22 t/s against 532.35 t/s at f16/f16, a ratio of 0.0117x.

Not established by this data. Whether the ROCm asymmetric result reflects a different code path, a fallback, a build-specific behaviour, an interaction with flash_attn=1, or something else. flash_attn is 1 in every record, so this log contains no contrast that separates those.

Measurement 2 — the same configuration under each build

The same configuration, read once under the ROCm build and once under the Vulkan build, shown as a per-cell ratio.

This is not a backend comparison. The two builds are different llama.cpp commits made days apart, so these ratios contain the backend and every other change between the commits, with no way to separate them. It is included because which build handles which KV configuration is a practical fact for anyone running this hardware — not as a ranking, and no single number is quoted across the two.

code
backend = backend_contrast(wide)
code
plot_backend_ratio(backend)
figure
code
summarize(
    backend.assign(arch=backend["bench_model"].map(families)),
    ["arch", "kv_class", "metric"],
)
archkv_classmetricnmedian_ratiomin_ratiomax_ratio
0deepseek2symmetric quantized K and Vpp204880.5717320.5296580.602964
1deepseek2symmetric quantized K and Vpp102480.7993620.7215350.860745
2deepseek2symmetric quantized K and Vpp51280.8549230.7751610.954357
3qwen35moesymmetric quantized K and Vpp204880.9846700.9542991.015595
4deepseek2symmetric quantized K and Vtg128160.9851320.5670781.228995
........................
19qwen35moesymmetric quantized K and Vtg128181.2551061.1820191.482452
20qwen35moeasymmetric f16 K, quantized Vtg128183.8618461.62422912.782372
21qwen35moeasymmetric f16 K, quantized Vpp5121011.0606427.54741032.146267
22qwen35moeasymmetric f16 K, quantized Vpp10241011.3731658.13864431.020409
23qwen35moeasymmetric f16 K, quantized Vpp2048870.93926148.92994890.433404

24 rows × 7 columns

code
_base = backend[backend["bench_kv"] == "f16/f16"]
_extreme = backend[backend["ratio"] > 2]
_low = backend[backend["ratio"] < 0.75]
mo.md(f"""
With KV at `f16/f16` — {len(_base)} pairs, all four models and both
depths — the two builds read within
**{_base["ratio"].min():.3f}x – {_base["ratio"].max():.3f}x** of each other.

Away from `f16/f16`, {len(_extreme)} pairs read above 2.00x (up to
{_extreme["ratio"].max():.1f}x) and {len(_low)} below 0.75x (down to
{_low["ratio"].min():.3f}x). Those are the same cells as measurement 1, seen
from the other side: they say which build handled which KV configuration,
not which backend is faster.

**Not established by this data.** How any of this divides between the
backend and the rest of what changed between the two commits. Nothing here
varies one while holding the other fixed.

## Measurement 3 — context depth, 16384 → 32768

Every pair below is the same model, backend and KV type measured at both
depths.
""")

With KV at f16/f16 — 43 pairs, all four models and both depths — the two builds read within 1.014x – 1.276x of each other.

Away from f16/f16, 41 pairs read above 2.00x (up to 90.4x) and 14 below 0.75x (down to 0.530x). Those are the same cells as measurement 1, seen from the other side: they say which build handled which KV configuration, not which backend is faster.

Not established by this data. How any of this divides between the backend and the rest of what changed between the two commits. Nothing here varies one while holding the other fixed.

Measurement 3 — context depth, 16384 → 32768

Every pair below is the same model, backend and KV type measured at both depths.

code
depth = depth_contrast(wide)
code
plot_depth_scaling(depth)
figure
code
summarize(depth, ["bench_backend", "metric"])
bench_backendmetricnmedian_ratiomin_ratiomax_ratio
0rocmtg128650.7930660.1222590.995392
1rocmpp512250.8176340.2086921.013725
2rocmpp1024250.8383960.2297890.984595
3vulkanpp1024250.8447750.7478510.961782
4vulkanpp512250.8683830.6787291.009086
5vulkantg128650.9103310.2078680.998604
code
def _pct(models, metric):
    rows = depth[
        (depth["bench_kv"] == "f16/f16")
        & depth["bench_model"].isin(models)
        & (depth["metric"] == metric)
    ]
    return f"{rows['pct'].min():+.1f} % to {rows['pct'].max():+.1f} %"

_qwen = ["qwen", "agentworld"]
_glm = ["glm", "glm-xl"]
mo.md(f"""
The medians above mix architectures and KV types. Restricted to `f16/f16`,
the two architectures separate:

| arch | `pp2048` | `tg128` |
| --- | --- | --- |
| `qwen35moe` | {_pct(_qwen, "pp2048")} | {_pct(_qwen, "tg128")} |
| `deepseek2` | {_pct(_glm, "pp2048")} | {_pct(_glm, "tg128")} |

In both architectures `pp2048` falls by more than `tg128` over the same
depth change.

**Not established by this data.** The shape of the curve between and beyond
these two points. Two depths give one slope per configuration and cannot
distinguish linear from super-linear growth.

## Measurement 4 — two quantisations of the same model

`glm` (`Q4_K_M`) and `glm-xl` (`UD-Q4_K_XL`) report the same `model_type`
and the same parameter count, and differ in quantisation and file size.
They are the only pair in the log where a contrast varies quantisation with
model, backend, depth and KV type all held fixed.
""")

The medians above mix architectures and KV types. Restricted to f16/f16, the two architectures separate:

arch pp2048 tg128
qwen35moe +nan % to +nan % -19.8 % to -0.5 %
deepseek2 +nan % to +nan % -57.6 % to -3.3 %

In both architectures pp2048 falls by more than tg128 over the same depth change.

Not established by this data. The shape of the curve between and beyond these two points. Two depths give one slope per configuration and cannot distinguish linear from super-linear growth.

Measurement 4 — two quantisations of the same model

glm (Q4_K_M) and glm-xl (UD-Q4_K_XL) report the same model_type and the same parameter count, and differ in quantisation and file size. They are the only pair in the log where a contrast varies quantisation with model, backend, depth and KV type all held fixed.

code
glm_pair = wide[wide["bench_model"].isin(["glm", "glm-xl"])]
variant = contrast(glm_pair, "bench_model", baseline="glm")
as_table(variant)
bench_backendbench_depthbench_kvmetricbaselinelevelfromtoratiopctkv_class
0rocm1024f16/f16pp1024glmglm-xl662.76687.341.04x+3.7%baseline f16 K, f16 V
1rocm1024f16/f16pp512glmglm-xl750.15769.791.03x+2.6%baseline f16 K, f16 V
2rocm1024f16/f16tg128glmglm-xl52.1652.611.01x+0.9%baseline f16 K, f16 V
3rocm1024f16/q4_0pp1024glmglm-xl666.45679.631.02x+2.0%asymmetric f16 K, quantized V
4rocm1024f16/q4_0pp512glmglm-xl702.40724.751.03x+3.2%asymmetric f16 K, quantized V
....................................
95vulkan32768f16/q8_0tg128glmglm-xl28.3328.491.01x+0.6%asymmetric f16 K, quantized V
96vulkan32768q4_0/q4_0pp2048glmglm-xl56.5156.681.00x+0.3%symmetric quantized K and V
97vulkan32768q4_0/q4_0tg128glmglm-xl12.5212.521.00x+0.1%symmetric quantized K and V
98vulkan32768q8_0/q8_0pp2048glmglm-xl51.0051.321.01x+0.6%symmetric quantized K and V
99vulkan32768q8_0/q8_0tg128glmglm-xl16.3516.100.98x-1.5%symmetric quantized K and V

100 rows × 11 columns

code
summarize(variant, ["metric"])
metricnmedian_ratiomin_ratiomax_ratio
0tg128401.0057200.9848131.013437
1pp2048201.0079380.9912951.014720
2pp1024201.0174960.9966151.037089
3pp512201.0300151.0028741.083112
code
_above = int((variant["ratio"] > 1).sum())
mo.md(f"""
Across all **{len(variant)} paired configurations**, `glm-xl / glm` falls
between **{variant["ratio"].min():.3f}x and {variant["ratio"].max():.3f}x**,
with medians of
{variant[variant["metric"] == "pp2048"]["ratio"].median():.3f}x (`pp2048`)
and {variant[variant["metric"] == "tg128"]["ratio"].median():.3f}x
(`tg128`). {_above} of {len(variant)} pairs are above 1.000x.

**Not established by this data.** Whether that spread or that direction is
distinguishable from run-to-run variance, which is unmeasured at one
repetition per test, or from a systematic run-order or thermal offset —
runs were sequential and run order is not randomised. Nothing here speaks
to output quality, the other axis on which these two files differ.

`agentworld` is also a `UD` build, but it is a different fine-tune from
`qwen`, so a contrast between them varies the model and the quantisation
together.

## Limitations

* **One repetition per test.** `stddev_ts` is 0 by construction.
  Differences of a few percent — the `f16/f16` reading between the two
  builds, the quantisation-variant spread — are not separable from noise.
* **The two builds are not a controlled comparison.** No record varies
  backend and `build_commit` independently.
* **`flash_attn` is 1 everywhere.** Nothing here shows how the
  measurements change without it.
* **`use_mmap` and the other runtime knobs are constant.** Not yet swept.
* **Throughput only.** No perplexity or task accuracy.
* **Two depths.** 16384 and 32768 only.
* **5 of 9 K/V type pairs.**
* **One machine, sequential runs.** Run order is not randomised and
  thermal state is not recorded.
* **Two architectures, two models each.**

## Open questions

Unresolved by the current data, with the contrast each would need:

1. Does the ROCm `qwen35moe` asymmetric-KV result persist with
   `flash_attn=0`? The factor is constant at 1 in every record.
2. What do the two backends read when both are built from the same commit?
   That is the contrast this log cannot supply.
3. What does `use_mmap` do here, on unified memory with models in the
   16–21 GiB range?
4. Is the `glm-xl` / `glm` difference reproducible under repeated,
   interleaved runs?
5. What is the shape of the depth curve? More depths would distinguish a
   slope from a curve.
6. Does the `deepseek2` / `qwen35moe` split hold with more models per
   architecture, or is it a property of these four files?
7. Do the KV cache quantisations that cost little throughput cost output
   quality? That needs a metric this study does not collect.
""")

Across all 100 paired configurations, glm-xl / glm falls between 0.985x and 1.083x, with medians of 1.008x (pp2048) and 1.006x (tg128). 94 of 100 pairs are above 1.000x.

Not established by this data. Whether that spread or that direction is distinguishable from run-to-run variance, which is unmeasured at one repetition per test, or from a systematic run-order or thermal offset — runs were sequential and run order is not randomised. Nothing here speaks to output quality, the other axis on which these two files differ.

agentworld is also a UD build, but it is a different fine-tune from qwen, so a contrast between them varies the model and the quantisation together.

Limitations

  • One repetition per test. stddev_ts is 0 by construction. Differences of a few percent — the f16/f16 reading between the two builds, the quantisation-variant spread — are not separable from noise.
  • The two builds are not a controlled comparison. No record varies backend and build_commit independently.
  • flash_attn is 1 everywhere. Nothing here shows how the measurements change without it.
  • use_mmap and the other runtime knobs are constant. Not yet swept.
  • Throughput only. No perplexity or task accuracy.
  • Two depths. 16384 and 32768 only.
  • 5 of 9 K/V type pairs.
  • One machine, sequential runs. Run order is not randomised and thermal state is not recorded.
  • Two architectures, two models each.

Open questions

Unresolved by the current data, with the contrast each would need:

  1. Does the ROCm qwen35moe asymmetric-KV result persist with flash_attn=0? The factor is constant at 1 in every record.
  2. What do the two backends read when both are built from the same commit? That is the contrast this log cannot supply.
  3. What does use_mmap do here, on unified memory with models in the 16–21 GiB range?
  4. Is the glm-xl / glm difference reproducible under repeated, interleaved runs?
  5. What is the shape of the depth curve? More depths would distinguish a slope from a curve.
  6. Does the deepseek2 / qwen35moe split hold with more models per architecture, or is it a property of these four files?
  7. Do the KV cache quantisations that cost little throughput cost output quality? That needs a metric this study does not collect.