You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断哪段x86汇编代码的执行速度更快?

判断x86汇编执行速度的通用准则及代码对比分析

我知道不同编译器针对不同机器生成的x86汇编代码不一样,同一段x86汇编在不同机器上运行的时钟周期数也存在差异。想问问判断x86汇编代码执行速度的通用准则有哪些?

比如我现在有下面两段代码,希望实现「零开销抽象」,但没法验证作为bar抽象的foo是不是真的比bar慢,以及具体慢多少:

foo(ComputeArray<double, 4ul>&, double):
        mov     rax, QWORD PTR [rdi]
        movapd  xmm1, xmm0
        addsd   xmm0, xmm0
        unpcklpd        xmm1, xmm1
        mov     rax, QWORD PTR [rax]
        unpcklpd        xmm0, xmm0
        movupd  xmm3, XMMWORD PTR [rax+224]
        movupd  xmm2, XMMWORD PTR [rax+240]
        movupd  xmm4, XMMWORD PTR [rax+272]
        mulpd   xmm3, xmm1
        mulpd   xmm2, xmm1
        movupd  xmm1, XMMWORD PTR [rax+256]
        mulpd   xmm1, xmm0
        mulpd   xmm0, xmm4
        addpd   xmm1, xmm3
        addpd   xmm0, xmm2
        movups  XMMWORD PTR [rax+192], xmm1
        movups  XMMWORD PTR [rax+208], xmm0
        ret
bar(double (*) [4], double):
        movapd  xmm2, xmm0
        movupd  xmm1, XMMWORD PTR [rdi+256]
        movupd  xmm0, XMMWORD PTR [rdi+272]
        movupd  xmm4, XMMWORD PTR [rdi+224]
        movupd  xmm6, XMMWORD PTR [rdi+240]
        unpcklpd        xmm2, xmm2
        addpd   xmm1, xmm1
        addpd   xmm0, xmm0
        addpd   xmm1, xmm4
        addpd   xmm0, xmm6
        mulpd   xmm1, xmm2
        mulpd   xmm0, xmm2
        movups  XMMWORD PTR [rdi+192], xmm1
        movups  XMMWORD PTR [rdi+208], xmm0
        ret

通用判断准则

  • 内存访问效率:重点看内存操作的次数、寻址方式和缓存命中率。比如避免不必要的间接寻址,优先用对齐内存访问(movapd在内存对齐时比movupd效率更高),减少缓存未命中的情况。
  • 指令并行度:观察指令是否能被CPU的超标量流水线并行执行。尽量缩短关键数据依赖链,把无依赖的指令放在一起,让CPU能同时执行多条指令。
  • 指令延迟与吞吐量:区分指令的延迟(指令执行完成到结果可用的时钟周期)和吞吐量(CPU每周期能执行的该类指令数量)。比如乘法指令延迟高于加法,要尽量减少关键路径上的高延迟指令。
  • 寄存器使用效率:减少不必要的寄存器拷贝,避免寄存器数据溢出到内存。让常用数据尽可能留在寄存器中,降低内存往返的开销。
  • 指令选择合理性:优先使用高效的SIMD指令批量处理数据(比如mulpd、addpd这类打包指令),避免用标量指令重复处理相同逻辑。

针对foo和bar的代码分析

  1. 内存寻址差异:
    foo多了两次间接寻址操作:mov rax, QWORD PTR [rdi]和mov rax, QWORD PTR [rax],这意味着要多两次内存读取操作。如果这两次访问的内存没命中缓存,开销会显著增加。而bar直接用rdi作为基地址做直接寻址,少了这两次额外的内存访问。
  2. 指令逻辑效率:
    foo里先用标量加法addsd xmm0, xmm0,再通过unpcklpd扩展成打包数据;而bar直接用addpd对打包数据执行加法,一步完成批量操作,避免了标量转打包的额外指令,减少了延迟。
  3. 流水线调度差异:
    foo中后续的内存加载指令依赖前面间接寻址得到的rax值,导致这些加载指令不能提前进入流水线执行;而bar的内存加载指令可以更早被CPU调度,提升了并行执行的可能性。

如果要量化两者的速度差异,可以:

  • 用性能分析工具统计两段代码的执行周期数、缓存命中率、指令吞吐量等指标。
  • 编写循环调用foo和bar的测试程序,统计大量迭代下的总执行时间,计算单次调用的平均耗时差。

内容的提问来源于stack exchange,提问作者user22056011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:05:19