llvm-mca通过静态调度模型模拟指令流水线执行,读取汇编文件(如test.s)而非可执行目标文件,依赖-mcpu指定微架构以加载对应schedmodel,核心吞吐指标为reciprocalblockrate,其准确性取决于模型中writelatency等参数与真实硬件的一致性。

llvm-mca 怎么读取机器码做吞吐量分析
llvm-mca 不执行代码,也不依赖运行时数据,它靠的是静态调度模型 + 指令序列输入。你给它一段合法的机器码(或汇编),它就基于目标 CPU 的 SchedModel 模拟指令在流水线里的发射、执行、退役全过程,最后输出每个周期哪些资源被占、哪条指令卡在哪、瓶颈在哪。所以第一步不是写 C,而是拿到能喂给 llvm-mca 的输入——通常是 .s 汇编文件或 .o 目标文件里的反汇编片段。
常见错误是直接丢一个带符号表、重定位项、section header 的完整 .o 给它,结果报错 error: unable to find a valid instruction sequence。这是因为 llvm-mca 只关心纯指令流,不处理链接上下文。
- 推荐做法:用
llvm-objdump -d --no-show-raw-insn binary.o | grep -E '^[[:space:]]*[0-9a-f]+:' | cut -d: -f2-
- 或者更稳妥:先用
clang -S -O2 -march=native test.c -o test.s 生成汇编,再手动删掉 .text 外的伪指令(如 <code>.globl,.align,.cfi_*),只留指令行 - 必须确保所有寄存器名、立即数格式符合 LLVM 的 MC 语法;比如 AArch64 上
mov x0, #0合法,mov x0, 0就会解析失败
怎么指定目标 CPU 和调度模型
默认情况下 llvm-mca 用的是通用 x86-64 模型,跟你的实际 CPU 差很远。吞吐量误差动辄 2–3 倍,尤其在端口绑定、微融合、指令融合这些细节上。
关键参数是 -mcpu,它决定用哪个 SchedModel。不是所有 CPU 名都有效,得看 LLVM 编译时启用了哪些后端:
- x86:支持
skylake,icelake,zen2,znver3等;native通常不可用(需源码编译时加-DLLVM_USE_INTEL_JITEVENTS=ON) - AArch64:支持
tsv110,neoverse-n2,apple-m1,generic;注意armv8-a是架构名,不是微架构,不能用于-mcpu - 命令示例:
llvm-mca -mcpu=tsv110 -timeline -iterations=100 test.s,其中-timeline输出每周期指令状态,-iterations控制模拟轮数以稳定吞吐估算
怎么看吞吐量数字和瓶颈提示
输出里真正代表吞吐量的是 Throughput Bottleneck 行和最底下的 Resources: 表格。别只盯着 “Average IPC” —— 那是模拟出来的平均值,没单位;而 “ReciprocalBlockRate” 才是核心指标,单位是 cycle/instruction,倒数就是每周期能完成多少条指令(即吞吐率)。
典型陷阱是忽略资源冲突的层级关系。比如你在 Skylake 上看到:
Throughput Bottleneck: Resource 'Port0' (2.0c)
这表示 Port0 是瓶颈,理论极限是每 2 个周期发 1 条指令 → 吞吐上限为 0.5 IPC。但如果同时出现:
Resource 'FPDiv' (4.0c)<br>Resource 'Port0' (2.0c)
说明浮点除法单元比 Port0 更慢,此时真实瓶颈是 FPDiv,Port0 的 2.0c 是假性瓶颈——因为指令根本等不到发到 Port0,就在 FPDiv 队列里堵着了。
- 重点关注
ReciprocalBlockRate数字,越小越好(如 0.75 表示每 0.75 周期可完成 1 条指令,即约 1.33 IPC) -
-debug-only=mca可输出调度器内部决策日志,但信息量爆炸,只在怀疑模型本身有问题时启用 - 若发现某条指令反复被标为
Stalled,大概率是它依赖的前序指令延迟没被模型准确建模,这时候该去查llvm-exegesis测出的真实延迟
为什么用 llvm-mca 分析的结果和实测有偏差
根本原因就一条:llvm-mca 完全依赖调度模型的准确性。模型里写的 WriteLatency、WriteRes、NumMicroOps 如果和真实硬件不一致,吞吐量预测就会系统性偏移。
比如你用 -mcpu=skylake 分析一条 vaddps,模型说延迟是 4 cycle,但实测是 3 cycle,那 llvm-mca 就会多算 1 个周期的等待,导致吞吐预估偏低 10%–20%。这种偏差在向量化密集场景下会被放大。
- 最可靠的补救方式是:用
llvm-exegesis在当前机器上实测关键指令的延迟/吞吐,然后修改对应 TableGen 文件(如SkylakeSchedule.td)并重新编译 LLVM - 临时绕过办法:用
-dispatch-stats和-register-file-stats看寄存器压力和分发队列堆积情况,有时比吞吐数字更能暴露真实瓶颈 - 别拿
llvm-mca和 perf stat 对比“IPC”:前者是理想流水线下的理论吞吐,后者含 cache miss、分支误预测、TLB miss 等所有现实干扰











