问题
当我们有分支频率数据时,有什么有趣的技巧可以做吗?什么是条件移动?
基础知识
如果您需要在来自一个分支的两个结果之间进行选择,那么您可以在 ISA 级别做两件不同的事情。
首先,你可以创建一个分支:
# %r = (%rCond == 1) ? $v1 : $v2
cmp %rCond, $1
jne A
mov %r, $v1
jmp E
A: mov %r, $v2
E:
其次,您可以执行依赖于比较结果的预测指令 。在 x86 中,这采用条件移动 (CMOV) 的形式,当选定条件成立时执行操作:
# %r = (%rCond == 1) ? $v1 : $v2
mov %r, $v1 ; put $v1 to %r
cmp %rCond, ...
cmovne %r, $v2 ; put $v2 to %r if condition is false
执行条件移动的优点是它有时会生成更紧凑的代码,就像在这个例子中一样,并且它不会受到可能的分支预测错误惩罚。缺点是它需要在选择返回哪一边之前计算两边,这可能会花费过多的 CPU 周期,增加寄存器压力等。在分支情况下,我们可以选择在检查条件后不计算内容。预测良好的分支将优于条件移动。
因此,是否执行条件移动的选择在很大程度上取决于其成本预测。这就是分支分析可以帮助我们的地方:它可以说出哪些分支可能没有被完美预测,因此适合 CMOV 替换。当然, 实际成本模型还包括我们正在处理的参数类型、两个计算分支的相对深度等。
实验
源码-用例1
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class BranchFrequency {
@Benchmark
public void fair() {
doCall(true);
doCall(false);