把 RX 7900 XTX 喂饱:不同精度、不同模型尺寸下的算存比实测

手里有一张 RX 7900 XTX(24 GiB / gfx1100 / RDNA3)。它能跑多大的模型、该用哪种量化、并发开到几才划算——这些问题最后都会收束到同一个量上:算存比(arithmetic intensity, AI)。

这篇文章把一天半里在 7900 XTX 上做的一批推理实验串成一根线:llama.cpp 与 vLLM 两套引擎、FP32 / FP16 / BF16 / INT8 / INT4 / FP8 六种精度、0.5B / 4B / 7B 三种模型尺寸、并发 N=1→16 的扫描,全部对着理论 roofline 校准。

一句话结论:这张卡在 7B 量级上,单请求 decode 能跑到实测 HBM 读带宽的约 91%;但即使是 N=16 的并发,离算力受限区仍然差 2~8 倍(取决于用 HBM 还是 IF 口径算 ridge)。 以及两个反直觉的点——算存比本身并不随模型变大而升高,变的是带宽利用率;还有 96 MiB Infinity Cache 让这张卡的带宽屋顶实际上有两档,笼统地按 960 GB/s 算会系统性低估小算子。

一、先把”算存比”这件事说清楚

算存比(算术强度)的定义很朴素:

1
AI = 一次推理里发生的运算数 / 为完成这些运算从显存搬进来的字节数   [OP/Byte]

Roofline 模型把这张卡的性能上限写成两条线的下包络:

1
性能 = min( 峰值算力 , 带宽 × AI )

于是每条 roofline 都有一个拐点——ridge point:

1
AI_ridge = 峰值算力 / 带宽
  • 当 AI < AI_ridge:带宽受限,性能 ≈ 带宽 × AI,堆算力没用;
  • 当 AI > AI_ridge:算力受限,性能 ≈ 峰值算力,堆带宽没用。

RX 7900 XTX(RDNA3,48 CU)的官方口径:

精度 峰值 说明
FP32 61.4 TFLOPS vector
FP16 / BF16 123 TFLOPS matrix
INT8 123 TOPS matrix
INT4 246 TOPS matrix
FP8 — RDNA3 无原生 FP8 WMMA,不设峰值
HBM 带宽 960 GB/s 24 GB GDDR6

代入 AI_ridge = 峰值 / 960 GB/s:

精度 ridge point (OP/Byte)
FP32 63.96
FP16 / BF16 / INT8 128.125
INT4 256.25

所以任何一次推理,只要算存比落在个位数,就必然是带宽受限。后面所有实测都会反复撞到这条结论。

二、三层口径:别把”等效带宽”当成”实测 DRAM”

做这类实验最容易翻车的地方,是把不同来源的数字混在一起。本文严格区分三层:

  1. 逻辑权重 AI:只计”把权重读一遍 + 每个参数 2 FLOP 的乘加”。不含 KV cache、激活、attention、反量化、采样。
  2. 等效权重读带宽:decode tok/s × 每 token 权重字节。这是一个由吞吐反推的等效量,不是硬件计数器读数。
  3. profiler DRAM counter:真正读 rocprof/uprof 的显存流量计数器。

本次实验没有采集第 3 层,所以本文里出现的”有效带宽””等效带宽”全部属于第 2 层,请勿与硬件计数器混淆。之所以用这套口径,是因为它能在同一把尺子下横向比较不同引擎、不同精度、不同尺寸,而不受各引擎 profiler 支持度差异的干扰。

三、实验平台与方法

硬件:AMD Radeon RX 7900 XTX,24 GiB,gfx1100,48 CU,96 MiB Infinity Cache。

引擎:

  • llama.cpp:/opt/llamacpp 的 gfx1100 ROCm 构建,跑 GGUF;
  • vLLM:Docker 镜像,PyTorch 2.12 + ROCm 10 + HIP,跑 HF 权重。

模型(覆盖三个量级;4B 一档用的是 Qwen3-4B,与另外两档并非同一代,仅作尺寸对照):

模型 hidden inter layers vocab Q/KV heads head_dim tied
Qwen2.5-0.5B-Instruct 896 4864 24 151936 14 / 2 64 是
Qwen3-4B 2560 9728 36 151936 32 / 8 128 是
Qwen2.5-7B-Instruct 3584 18944 28 152064 28 / 4 128 否

精度:

  • llama.cpp:FP32 / FP16 / BF16 / Q8_0 / Q4_K_M(GGUF);
  • vLLM:FP16 / BF16 / FP32 / FP8-dynamic / INT4(GPTQ、AWQ) / INT8(GPTQ)。

workload:input_len=512、output_len=128,5 次测量 + 2 次 warmup;并发用 vllm bench latency --batch-size N,N = 1/2/4/8/16。

HBM microbenchmark:read_sum / write_zero / copy / triad_add 四种访存模式,256 / 512 / 1024 MiB,各 30 次,取中位数。

Infinity Cache(IF Cache)扫描:这块卡有 96 MiB Infinity Cache,在 ROCm 计数器里就是 GL2C 这一级。为了把它从”总带宽”里切出来,做了两组补充实验:

  1. 工作集扫描:同一组访存原语(read_sum / write_zero / copy / triad_add),工作集从 8 MiB 扫到 1 GiB,每档 25 个样本取中位数,样本内部循环若干次以摊平 kernel 启动开销。目的:找出 96 MiB 两侧的带宽断点。
  2. 真实 kernel 权重扫描:用 llama.cpp 自带的 test-backend-ops perf 跑模型实际使用的 ROCm MUL_MAT kernel,固定 m = 4096(输出行数固定 ⇒ 并行度恒定),n = 1(decode)与 n = 16,扫 k 使权重体量 |W| = m·k·bpe 从 8 MiB 走到 512 MiB,在 96 MiB 前后各取足够密的点。类型 f16 / q8_0 / q4_K / f32。

补充实验的完整数据、脚本与图在 experiments/ifcache_arith_7900xtx_20260924/。

四、先量一把这张卡的带宽

所有推理的上限都建立在这张卡真实的访存能力上。1 GiB 工作集下的中位数:

访存模式 有效带宽 (GB/s)
read_sum(纯读) 874.2
write_zero(纯写) 933.4
copy(读+写) 778.4
triad_add(2 读 + 1 写) 801.3

也就是说,官方标称的 960 GB/s,实际纯读大约能摸到 874 GB/s(91%),混合读写会掉到 780~800 GB/s。

但这张卡不止一个带宽档位。 上面测的是”数据远大于缓存”时的情况。7900 XTX 还有 96 MiB Infinity Cache,当工作集装得进这 96 MiB 时,服务它的是 L2 而不是 GDDR6:

工作集大小 vs 有效带宽

每次操作数据 (MiB) read_sum write_zero copy triad_add
8 565 960 1466 1622
16 920 1149 1685 2267
32 1471 1295 1825 2620
48 1313 1362 1464 2543
64 1750 1400 772 793
80 2083 1428 789 782
96 1997 1342 820 786
112 823 892 790 786
128 837 899 802 790
256 860 921 785 787
512 888 919 787 791
1024 750 932 776 801

(单位 GB/s)

三个要点:

  • 断点是硬的,不是渐变。 纯读在 80 MiB = 2083 GB/s、96 MiB = 1997 GB/s,到 112 MiB 直接掉到 823 GB/s——一步 2.4 倍阶跃。96→112 MiB 正好卡在 IF Cache 容量上。
  • copy / triad 的断点提前到 ~48/32 MiB,因为它们同时占用两份数据(footprint = 2 × 数组大小)。triad 在 32 MiB 达到 2620 GB/s,是 IF 读写合计能力的体现。
  • 大于 112 MiB 后所有曲线收敛到 0.78–0.93 TB/s,与上面 1 GiB 那一档完全一致 ⇒ 这一档才是纯 HBM。

注意:8–16 MiB 的 read_sum 偏低(565/920)不是带宽不够,而是并行度不足——小数组喂不满 48 个 CU。IF 的”满血”区间要从 32 MiB 往上看。

所以这张卡的带宽屋顶是两档:工作集 ≤ 96 MiB 时是 ~2 TB/s(IF),超出后是 ~874 GB/s(HBM 实测)/ 960 GB/s(官方)。后面凡是超过 960 GB/s 的”等效带宽”,一定是在吃 IF,而不是 HBM 变快了。

五、算子级:n=1 和 n=512 是两个世界

先看最干净的一层——单个大矩阵乘(m=4096, k=14336)在不同 batch(n)下的 roofline 位置:

算子级 roofline:n=1 与 n=512

右图(n=512,接近 prefill 形状):点集体向右上迁移,落在算力屋顶附近。同一个 kernel,仅仅因为 batch 变大、权重被复用 512 次,就从带宽受限滑进了算力受限。

这一张图就解释了:为什么 prefill 快、decode 慢,为什么它们的瓶颈根本不是一个东西。

5.1 n=1 出现超过 HBM 的数字,说明这一段测的是 IF 不是 HBM

左图(n=1,decode 形状)有个不能放过的细节。n=1 时矩阵乘退化成”把权重整体读一遍、每个元素只参与一次乘加”,算存比很低,本该是纯权重带宽主导。但同一张表里出现了在纯 HBM 模型下不可能的数字:

类型 权重 逻辑 AI 表观权重读带宽 相对 960 GB/s 受限层
F32 224.0 MiB 0.500 886.3 GB/s 92.3% HBM
F16 112.0 MiB 1.000 815.2 GB/s 84.9% HBM
BF16 112.0 MiB 1.000 812.6 GB/s 84.6% HBM
Q8_0 59.5 MiB 1.882 1811.0 GB/s 188.6% IF Cache
Q4_K 31.5 MiB 3.556 900.5 GB/s 93.8% compute / kernel

Q8_0 的 1811 GB/s 是 HBM 标称 960 GB/s 的 1.89 倍——单靠 GDDR6 永远测不出来。 唯一解释是:这份 62 MB 的权重整体驻留进了 96 MiB Infinity Cache,服务它的是 IF 的 ~2 TB/s。F32 的 224 MiB、F16/BF16 的 112 MiB 都超过或贴着 IF 容量,所以那三个数字才真的是 HBM。而 Q4_K 的 900 GB/s 也不是”HBM 打满”,是 kernel 打不满 HBM——它的瓶颈在反量化,不在访存。

5.2 用真实 kernel 把 96 MiB 边界扫出来

光有一个点不够。我们直接用 llama.cpp 的 ROCm MUL_MAT kernel,固定并行度(m=4096),让权重体量从 8 MiB 扫到 512 MiB,跨过 96 MiB:

真实 MUL_MAT 权重带宽 vs 权重体量

n=1(decode)的表观权重带宽(GB/s):

权重体量 (MiB) f16 q8_0 q4_K f32
32 1041 1160 865 543
48 1345 1645 972 1395
64 1512 1884 1023 1885
80 1617 2093 1008 2141
96 979 1426 925 1494
112 973 812 740 821
128 800 811 739 831
512 850 846 773 889

三个要点:

  • f16 / q8_0 / f32 的峰值都落在 64–80 MiB,越过 96 MiB 后集体跌到 ~0.8 TB/s。 而且峰值(1617 / 2093 / 2141 GB/s)都远超 960 GB/s——只有 IF 能解释。
  • 峰值出现在 ~80 MiB 而不是 96 MiB:权重把 96 MiB 填满后,激活、输出、量化 scale 就没地方放了,开始互相驱逐。所以 IF 的”可用容量”实际是 80–96 MiB。
  • Q4_K 是例外:曲线平得多(1023 → 747),IF 内外只差 1.37×。INT4 的瓶颈是反量化与计算,访存不再是主约束,IF 帮不上忙——这正好复现了 5.1 里”Q4_K 的 900 GB/s 是 kernel 上界”那句话。

5.3 LLM 的算子到底放不放得进这 96 MiB?

把 4B / 7B 每层主干算子的单份权重和 96 MiB 对照:

算子 4B BF16 4B Q4_K 7B BF16 7B Q4_K
qkv_proj 30.0 8.4 31.5 8.9
o_proj 20.0 5.6 24.5 6.9
gate_up_proj 95.0 26.7 259.0 72.8
down_proj 47.5 13.4 129.5 36.4
lm_head 741.9 208.7 1039.5 292.4
单层四主干合计 192.5 54.1 444.5 125.0

(单位 MiB;4B 是 tied embedding,lm_head 与 embedding 共享存储。)

算子权重 footprint vs 96 MiB IF Cache

这就把问题回答清楚了:

  • 4B:qkv / o / gate_up / down 四个主干算子的权重单独都能放进 96 MiB(BF16 的 gate_up 95.0 MiB 正好贴上限,Q4 下更是远远够用)。所以 4B 的 decode 权重访存大量命中 IF,测到的是 IF 路径带宽。
  • 7B:只有 qkv(31.5) / o(24.5) 放得下;gate_up(259) / down(129.5) / lm_head(1039.5) 全部放不下,是纯 HBM。7B 的 decode 权重流量是 IF 与 HBM 混合的。
  • 但”层”放不进:单层四主干合计 4B 192.5 MiB、7B 444.5 MiB,任何一层都超 96 MiB。所以 IF 的收益只在算子粒度成立,到层粒度就被打散了。

这解释了一个之前被含糊带过的现象:为什么 4B 的”等效带宽”只有 491–699 GB/s,明明它的算子全都放得进 IF? 因为瓶颈根本不是带宽——是并行度(4B 太小喂不满 48 CU)和 kernel 效率。用小模型测”这张卡能跑多快”会系统性低估 HBM;同样,小模型也不能拿来测”IF 有多快”。

六、模型级:llama.cpp 下的五档精度

先给一张全局对照图——把所有模型级路径的算存比和各自的 ridge 摆在一起(蓝 = llama.cpp 端到端,红 = vLLM batch=1,绿 = vLLM batch=8,叉号 = 理论 ridge):

模型级算存比 vs 理论 ridge

它已经把全篇的骨架画出来了:所有实测柱子都远低于叉号,且越靠右(精度越低)算存比越高。 下面逐档展开。先把整个 7B 模型端到端跑起来,decode 阶段的中位数(每 token 权重字节 × tok/s = 等效读带宽):

精度 文件 每 token 权重 bit/逻辑参数 权重 AI decode tok/s 等效读带宽
FP32 29057 MiB 26972 MiB 32.00 0.500 失败(超显存) —
FP16 14532 MiB 13487 MiB 16.00 1.000 56.40 797.6 GB/s
BF16 14532 MiB 13487 MiB 16.00 1.000 56.07 793.0 GB/s
Q8_0 7723 MiB 7165 MiB 8.50 1.882 93.00 698.8 GB/s
Q4_K_M 4466 MiB 4168 MiB 4.95 3.235 128.90 563.4 GB/s

几个值得注意的点:

  • FP16 的算存比恰好是 1.000,这不是巧合。对权重流主导的 decode:AI = 2 × params / (params × bytes_per_param) = 2 / bytes_per_param。FP16 每参数 2 字节,于是 AI = 2/2 = 1。FP32 是 0.5,Q8_0 是 1.88,Q4_K_M 是 3.24——算存比只由”每个参数占多少位”决定。
  • FP16 单请求就把带宽利用率干到了 91%(797.6 / 874.2),84%(797.6 / 960)。7B 的 FP16 权重总量 ~14 GiB,远大于 96 MiB IF,所以这个 797.6 GB/s 作为端到端等效值是 HBM 主导的,可以信。但要标注一句:端到端里 qkv / o 这类小算子会命中 IF,这个数字已经被 IF 悄悄抬高过一小截,它不是纯 HBM 流量。真正”纯 HBM”的证据是 §四里 >112 MiB 工作集的 874 GB/s。
  • 量化确实提升了算存比,但吞吐不一定同步涨:Q8_0 的 AI 是 FP16 的 1.88 倍,吞吐只涨到 1.65 倍;Q4_K_M 的 AI 是 3.24 倍,吞吐 2.29 倍。多出来的开销都被反量化吃掉了——AI 是理论账,kernel 才是现实。

七、模型级:vLLM 下的 batch=1 / batch=8

换到 vLLM(7B,input 512 / output 128):

路径 batch=1 tok/s batch=1 AI batch=8 tok/s batch=8 AI
BF16 58.82 1.000 288.17 8.000
FP16 58.88 1.000 317.25 8.000
GPTQ-INT4 94.12 3.153 485.80 25.221
AWQ-INT4 55.55 3.156 337.24 25.247
GPTQ-INT8 11.76 1.819 75.77 14.553

这里有全篇最”违背直觉”的一组对照:GPTQ-INT4 和 AWQ-INT4 的算存比几乎一模一样(3.153 vs 3.156),吞吐却差 1.7 倍(94.12 vs 55.55 tok/s)。 原因不在数学,在 kernel:

  • GPTQ 走的是 ROCm 上融合的 W4A16 kernel,反量化融进 GEMM 流水;
  • AWQ 在 ROCm 上退回了整块反量化的 Triton 路径,权重先还原成 FP16 再乘。

同样的 4 bit、同样的带宽需求,不同的反量化实现能拉开 70% 的差距。这也是为什么”量化后一定更快”是一个需要用数据检验的假设,而不是定理。

八、并发:N=1→16 的访存比

把 batch 从 1 扫到 16,观察算存比和吞吐怎么走:

算存比 vs 并发

聚合吞吐 vs 并发

理论屋顶 vs 实测等效带宽

N=16 时的明细:

路径 N=16 AI 占 ridge(HBM 下界) 占 ridge(IF 上界) 聚合 tok/s N=16 等效带宽 batch 效率 vs N=1
FP16 16.00 12.5% 26.0% 525.7 465 GB/s 0.56
GPTQ-INT4 50.44 19.7% 41.0% 602.4 169 GB/s 0.41
AWQ-INT4 50.49 19.7% 41.0% 527.7 148 GB/s 0.60
GPTQ-INT8 29.11 22.7% 47.3% 124.1 60 GB/s 0.66

三个观察:

  1. 并发把 AI 线性拉高(权重被批量共享),但到 N=16 也够不到 ridge。这里的”占 ridge”必须给区间:按 HBM 960 GB/s 当带宽屋顶,只到 12.5%~22.7%;若假设算子权重全命中 IF(2 TB/s,ridge 相应更低),上界抬到 **26%47%**。给单个数字(无论 12% 还是 47%)都是错的,因为 7B 的权重流量在 IF 与 HBM 之间是混合的。
  2. batch 效率从 N=8 开始明显塌方(N=8→16 的效率掉到 0.41~0.66)。权重共享的收益被 attention/KV、调度和固定开销吃掉了。
  3. 等效带宽随 N 增大反而下降:FP16 从 N=1 的 835 GB/s 掉到 N=16 的 465 GB/s。因为权重读一次就够,N 越大,单位 token 分摊到的权重读越少——“带宽”这个指标在 batch 化之后就不再是瓶颈的主语了。补充的 kernel 扫描也印证了这点:n=16 时 f16/q8_0/q4_K 的权重带宽整体更低更平(f16 峰值从 n=1 的 1617 掉到 979),说明 N=16 的算子已经转向计算受限,拿带宽 ridge 去衡量它本身就是错的标尺。

第 3 张图(理论屋顶 vs 实测等效带宽)最直白:FP16 能摸到屋顶的 87%,GPTQ-INT4 只有 43%,AWQ 26%,GPTQ-INT8 9%。精度越低,等效带宽越”低”——不是硬件变弱了,而是每 token 要搬的权重字节少了,同样的绝对带宽能撑起更多 token。

九、跨尺寸:0.5B / 4B / 7B,模型是不是太小了?

这才是这次实验的起点。最初的怀疑是:用小模型测这张卡,是不是根本测不出它的带宽?

7B vs 4B 的算存比

4B vs 0.5B 的算存比

把三个尺寸放在同一把尺子下(vLLM FP16,N=1):

尺寸 每 token 权重 N=1 等效读带宽 N=16 聚合 tok/s
Qwen2.5-0.5B 0.92 GiB 90.8 GB/s 1061
Qwen3-4B 7.49 GiB 491.4 GB/s 560
Qwen2.5-7B 13.17 GiB 834.6 GB/s 526

三个结论,方向不同但都成立:

结论一:模型确实不能太小。 0.5B 的等效带宽只有 90.8 GB/s——连这张卡读带宽的 11% 都摸不到。小模型里,kernel 启动、logits、attention、采样、KV 这些固定开销占比过高,权重还没喂饱卡,别的开销先到顶了。4B 提升到 491 GB/s(明显偏小),7B 才到 834 GB/s(进入权重流主导区)。“用小模型测带宽”在这张卡上是行不通的。

结论二:算存比本身不随模型变大而升高。 看两张图——不同尺寸的曲线几乎完全重合。这不是数据出错,而是数学必然:AI = 2 / bytes_per_param,分子分母同比例增长,模型尺寸被约掉了。FP16 在任何尺寸下算存比都是 1.0。

结论三:小模型”测不出带宽”还有一层 IF 解释。 0.5B / 4B 的算子权重小到能整块驻留 IF(见 §5.3),它们本该享受到 IF 的 ~2 TB/s,实测却只有 90.8 / 491.4 GB/s。所以这不是”HBM 不够快”,而是并行度不足 + kernel 效率低:权重喂不满 48 个 CU,IF 的高带宽根本发挥不出来。拿 HBM 峰值去衡量小模型,方向就错了;真正卡住小模型的是并行度与固定开销,不是显存带宽。

所以真正随模型变大而改善的,是带宽利用率(从 11% → 56% → 87%),而不是算存比。也正因为如此,大模型的绝对吞吐反而更低(7B N=16 ≈ 526 tok/s,只有 0.5B 的一半)——单位算力要喂的字节更多了。

一句话记法:想让 GPU”进入 roofline 的带宽分支”是大模型的事;想让吞吐绝对值高是小模型的事。 这两件事用的是不同的杠杆。

十、两个”如实失败”的样本

实验里有两条路径压根跑不起来,它们同样是结论:

FP32 在 7B 上必然 OOM。 7B 的 FP32 权重是 28.28 GB(GGUF 文件 30.47 GB),直接超过 24 GiB 显存。llama.cpp 与 vLLM 全部在加载阶段失败。在消费级 24G 卡上,FP32 7B 不是一个可选档位。

FP8 在 gfx1100 上无路可走。 vLLM 的 FP8-dynamic 在加载期调用 torch._scaled_mm,直接报错:该算子只支持 CUDA SM 8.9/9.0 或 ROCm MI300+。RDNA3 没有原生 FP8 matrix 单元,也没有可用的软件 fallback。7900 XTX 想跑 FP8,现阶段没有可用的高效路径。

这两条我不会填任何编造的实测数字——失败就是失败,记下来比凑一个好看的数字有用。

十一、结论

把上面所有东西收束成几句话:

  1. decode 天然带宽受限。 单请求权重 AI 只有 0.50~3.24,离理论 ridge(64/128/256)差一到两个数量级。这不是引擎没调好,是 batch=1 的数学必然。
  2. 7B 是让这张卡”吃饱”的合适量级——但要分清它吃饱的是哪一档带宽。 FP16 单请求端到端等效读带宽 797.6 GB/s = 实测 HBM 读带宽的 91% / 官方 960 GB/s 的 84%,这是 HBM 主导的结论。同时 7900 XTX 的带宽屋顶其实有两档:工作集 ≤ 96 MiB 时是 IF 的 ~2 TB/s,超出后才是 HBM 的 ~874 GB/s;单算子(尤其 4B / Q8_0)经常落在 IF 那一档。0.5B 完全测不出带宽,4B 偏小——它们卡在并行度和 kernel 效率,不是 HBM 不够快。
  3. 算存比与模型尺寸无关,只与每参数位数有关。 AI = 2 / bytes_per_param。变大的是带宽利用率。
  4. 量化提升算存比,但收益要 kernel 兑现。 同为 4 bit,GPTQ(融合 W4A16)比 AWQ(Triton 反量化)快 70%。
  5. 并发能拉高算存比,但 N=16 仍然够不到 ridge。 按 HBM 下界算是 12.5%22.7%,按 IF 上界算是 26%47%——这个区间本身就是”IF 与 HBM 混合”的体现。而且 N=16 的算子已转向计算受限(kernel 扫描里 n=16 的权重带宽整体更低更平),带宽 ridge 不再是衡量它的好标尺。batch 效率也已从 0.41~0.66 一路下滑。
  6. FP32 7B 必然 OOM;FP8 在 gfx1100 无可用路径。 两个档位在 7900 XTX 上直接划掉。
  7. 带宽必须给两档口径。 96 MiB Infinity Cache 不是”大一点的 L2”,而是一条独立的高带宽层:≤96 MiB 是 ~2 TB/s(IF ridge = 算力 ÷ 2 TB/s),超出后是 ~874 GB/s(HBM ridge = 算力 ÷ 960 GB/s)。任何”等效带宽”在引用前都要说清测的是哪一档——在 96 MiB 这个容量点附近,换口径会带来 2 倍以上的结论差。

最后补两句方法论上的克制:本文所有”带宽”都是等效口径(吞吐反推),没有采集硬件 DRAM 计数器;并且由于本机 rocprofv3 的 GL2C 块计数器恒返回 0,“IF 命中率”同样没有直读——IF 的结论全部由”跨 96 MiB 的带宽断崖”这一直接观测量推出。如果您要引用这里的数字,请连同这个口径一起引用——把等效带宽说成”实测显存流量”是这类分析里最常见、也最误导的错误。

十二、复现

三组实验(0.5B / 4B / 7B)各自独立成目录,包含:

  • 原始结果:results/{llamacpp,vllm,vllm_batch1,vllm_concurrency}/*.json
  • 汇总表:results/common/*.csv
  • 可视化:results/**/figures/*.png
  • 脚本:scripts/(HBM microbench、引擎跑分、分析与一致性校验)

分析链路(HBM microbench → 模型级分析 → 并发分析 → 数值一致性校验)全部可一键复跑,报告里的每一个数字都与 CSV 逐项对齐。若您在自己的卡上复现,唯一需要改的就是峰值算力与标称带宽这两个常量,其余口径完全通用。

IF Cache 补实验单独成目录 experiments/ifcache_arith_7900xtx_20260924/:工作集扫描(实验 A)、llama.cpp 真实 MUL_MAT 权重体量扫描(实验 B)、算子 footprint 映射(实验 C),外加完整报告 REPORT.md 与三张图。§四的断点表、§5.2 的 kernel 扫描、§5.3 的 footprint 表全部出自这里。硬件局限已如实记录:本机 rocprofv3 的 GL2C 块计数器恒返回 0、perf_event_paranoid=4 且无免密 root,因此 IF 命中率是推断而非直读,所有 IF 结论都建立在”跨 96 MiB 的带宽断崖”这一直接观测量上。