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

为何添加3个随机字节能让x86-64汇编代码提速10倍?

乱序执行测试的性能疑惑

我正在阅读Agner Fog的《汇编语言子程序优化》手册第9.2节「乱序执行」,并复现其中示例测试性能:

测试案例1:无额外字节的循环

; first case = loop without extra bytes.
section .data
    ; using db instead of dd was a mistake which later led
    ; me to this question.
    mem1: db 23
    mem3: db 23
section .bss
    mem2: resd 1
    mem4: resd 1

section .text
    global _start
_start:
    mov rcx, 300000000

loop:
    ; waste time
    mov eax, dword [mem1]
    imul eax, 6
    mov [mem2], eax
    mov edx, dword [mem3]
    imul edx, 8
    mov [mem4], edx

    sub ecx, 1
    jnz loop

    mov eax, 60
    xor edi, edi
    syscall

编译运行耗时:

% nasm -f elf64 outoforder.asm && ld outoforder.o -o outoforder && time ./outoforder
./outoforder  1.46s user 0.00s system 99% cpu 1.458 total

令我困惑的是:在mem1和mem3周围添加至少3个随机字节后,代码速度提升10倍!

测试案例2:添加随机字节的循环

; second case = loop + at least three random bytes around mem1 and mem3
section .data
    db 1
    mem1: db 23
    db 1
    mem3: db 23
    db 1

编译运行耗时:

% nasm -f elf64 outoforder.asm && ld outoforder.o -o outoforder && time ./outoforder
./outoforder  0.13s user 0.00s system 99% cpu 0.130 total

无论字节位置如何,结果一致。objdump显示地址未对齐,排除对齐因素。

后续测试:

  • 使用DX替代EDX时,代码速度介于两者之间,添加字节无影响;
  • 使用AX替代DX时,代码速度与案例2一致;
  • 单独运行AX相关循环耗时0.31s,替换为EAX后耗时0.06s。

我无法理解:为何添加3个字节会带来如此大的性能提升?AX对EAX高位的依赖为何未拖慢速度?

处理器:11th Gen Intel(R) Core(TM) i7-11700F @ 2.50GHz
系统:Arch Linux 6.6.10-arch1-1
架构:x86-64


问题解析

一、添加3个字节带来10倍性能提升的原因

核心是重叠内存访问引发的加载-存储转发阻塞。

测试案例1中,mem1和mem3用db定义,内存中仅间隔1字节。执行mov eax, dword [mem1]时会读取从mem1开始的4字节,覆盖mem3所在的内存区域;同理mov edx, dword [mem3]会读取从mem3开始的4字节,覆盖mem1之后的区域。

这种重叠的内存访问会触发CPU存储缓冲区的阻塞:当CPU尝试加载mem3的数据时,发现该区域被之前mem1的4字节读操作覆盖,且后续可能存在未提交的存储操作,被迫等待存储缓冲区刷新,原本可以并行执行的两组mov+imul+mov指令只能串行执行,导致性能暴跌。

添加3个字节后,mem1和mem3的间隔足够大,两个dword加载操作的内存范围不再重叠。此时CPU的乱序执行单元可以同时调度两组指令,充分利用执行单元的并行性,性能自然大幅提升。

二、AX对EAX高位的依赖未拖慢速度的原因

现代Intel CPU的寄存器重命名机制和x86-64的寄存器规则共同导致了这个结果:

  1. 寄存器重命名的独立性:16位寄存器(如AX)和32位寄存器(如EAX)会被分配独立的物理寄存器,除非存在明确的完整寄存器读写依赖。测试中仅使用AX进行运算和存储,没有读取EAX的完整值,因此AX的操作与EAX高位无依赖关系,乱序执行单元可以独立调度AX相关指令。
  2. 16位与32位指令的效率差异:单独运行AX循环耗时更高,是因为现代CPU对32位操作的支持更完善,执行延迟和吞吐量都优于16位操作,且32位寄存器的重命名、调度开销更低,因此替换为EAX后性能进一步提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:05:33