跳转到内容

CPU分支预测

当执行根据判断跳转到不同区块的指令时,cpu会先预测最可能执行的分支来提升指令管线的效率,现代cpu采用动态预测方式,根据先前分支跳转的历史来预测,如果猜错的话会产生一些pipeline flush的性能成本,猜对且经常正确的话可以提升效能,写程式时基于效能考量有两种情况,使用分支和使用无分支(避免分支),以下将说明详细内容。

bigger:
mov rax, rdi ; 假設rdi大
cmp rdi, rsi
jl less
ret
less:
mov rax, rsi
ret

这是比较 rdirsi 哪一个比较大的示例,默认 rdi 大如果小则改成 rsi,cpu在分支没有历史首次执行的时候静态分支预测如下

名稱 說明 例子 行為
向前分支(forward branches) 目标地址更大的分支,代码一般在更下面 if 预测不跳转
向後分支(backward branches) 目标地址更小的分支,代码一般在更上面 loop 预测跳转

所以这种 jl 到更下方的 less 做法默认不会跳转,当rdi经常比rsi大的时候这样写
高阶语言loop一般会被编译成向后分支,if一般会被编译成向前分支

只有在以运行时内容决定的跳转语句才会需要预测接下来往哪里执行,像是cmovcc指令和setcc(根据标志位的0或1设置到目标寄存器的最低位)就不会有分支跳转语句,高级语言常见的像是根据内容简单赋值的三元运算符 (condition)? true:false,但如果true或false的选项是复杂的例如一个函数那么还是会被编译为分支跳转才能实现。

除了这些用指令可替换的方式还有一些进阶技巧请参考这篇文章

如果一个判断跳转经常是可以被cpu预测对的,使用分支预测效能高于无分支,如果一个内容随机性高经常进入不同分支的话使用无分支写法更佳。

if(error) {
return msg;
}
/* 继续运行 */

像是一般不太发生那样的情况写成if跳转,同时符合上面的cpu静态分支预测方式,而且后续不常发生在动态预测一般是正确的。