16.1.9 执行单元的影响

CPU 由多个部分组成。每条汇编指令都会被分为多阶段执行,每个阶段会由 CPU 的不同部件去完成操作。例如,第一阶段一般被称为指令获取,该阶段需要从内存中加载指令,且不考虑任何语义上的问题。

CPU 中执行操作和计算的部件被称为执行单元。该单元实现了 CPU 想要完成的不同类型的操作:指令获取,算术逻辑运算,地址翻译,指令解码等等。实际上 CPU 某种程度上可以单独使用这个组件了。不同的汇编指令所需要的执行阶段数也是不一样的,每一个阶段都可能会被不同的执行单元所执行。这样就允许一些比较有意思的电路运用了,例如:

  • 在获取到另一条指令完成但还没开始执行时,马上去取下一条指令。
  • 即使在汇编代码中,按先后顺序描述的算术运算,也会同时执行。

奔腾 IV 家族的 CPU 已经能够在正确的前提下同时执行四个算术指令了。

知道了执行单元的存在之后,我们怎么发挥这样的知识呢?先来看看列表 16-17 中的例子。

Listing 16-17.cycle_nonpar_arith.asm

looper:
    mov      rax,[rsi]
    ; The next instruction depends on the previous one.
    ; It means that we can not swap them because
    ; the program behavior will change.
    xor     rax, 0x1

    ; One more dependency here
    add     [rdi],rax
    add     rsi,8
    add     rdi,8
    dec     rcx
    jnz     looper

能让这段代码更快么?我们可以分析出影响 CPU 微执行优化器的指令之间的依赖关系。我们展开这个循环,这样老的循环的两次叠代就可以变成新的一次叠代,列表 16-18 展示优化后的结果。

Listing 16-18.cycle_par_arith.asm

looper:
mov      rax,  [rsi]
mov      rdx,  [rsi + 8]
xor      rax,  0x1
xor      rdx,  0x1
add      [rdi], rax
add      [rdi+8], rdx
add      rsi, 16

add      rdi, 16
sub      rcx, 2
jnz      looper

现在依赖被干掉了,两次叠代的指令没有任何混合了。这样执行起来就可以更快,因为这样的代码能够使 CPU 同时使用不同的执行单元去并发执行两次叠代。指令的依赖应该尽量被优化掉使指令能够同时执行。


■Question 333 什么是指令流水线和超标量体系架构?


我们没法告诉你 CPU 中有哪些执行单元,因为这是和 CPU 的模型相关的。想要获得这些信息只能去阅读特定 CPU 的优化手册,例如 [16]。另一些资源可能也会有一些帮助;例如 Haswell 处理器在 [17] 中有不错的解读。

results matching ""

    No results matching ""