【发布时间】:2023-03-12 06:44:01
【问题描述】:
考虑以下两段代码:
备选方案 1:
if (variable != new_val) // (1)
variable = new_val;
f(); // This function reads `variable`.
备选方案 2:
variable = new_val; // (2)
f(); // This function reads `variable`.
哪个选项“统计上”更快?假设variable 在 (1) 或 (2) 之前位于缓存 L1 中。
我猜即使分支误预测率很高,替代方案 (1) 也会更快,但我真的不知道“ifs”的成本。我的猜测是基于缓存未命中比分支错误预测更昂贵的假设,但我真的不知道。
如果variable 在 (1) 或 (2) 之前不在缓存中怎么办?是不是改变的太多了?
注意:由于不同 CPU 之间的情况可能会发生很大变化,因此您可以根据自己熟悉的架构来回答,尽管像任何现代 Intel 架构这样广泛使用的 CPU 是首选。我的问题的目标实际上是更多地了解 CPU 的工作原理。
【问题讨论】:
-
没有基准测试就无法判断。
-
Alt 1 可以包括替代 2,作为乱序执行,在这种情况下,当谓词不成立时,结果将被丢弃。基于此,我会说备选方案 2 几乎总是更有效。即使使用微基准测试,也很难精确定位效率,因为您还必须考虑对程序其余部分的副作用,例如,仅预取的行为就会为预取器分配更多的工作量。另一点是,在进行比较时,您已经将变量放在寄存器中,这将是分配替代方案的重要组成部分
-
(1) 取决于
new_val的先前值,如果需要,这将需要从缓存中获取它,而编译器可以完全忽略 (2) 中的先前值。如果 (1) 更快,我会感到惊讶,除非variable的类型有很大的sizeof()或者有一些产生副作用的赋值操作。但一如既往:不要假设,基准测试。 -
@Peregring-lk 错误预测的成本可能非常高。考虑管道冲洗。
-
请记住,
variable可以放入寄存器,从而影响 变量 是否被缓存。据我了解,寄存器不涉及使用缓存,除了加载和存储值。因此f()有可能不使用缓存,因为该值仍在寄存器中。取决于何时variable在f()中使用以及编译器如何生成指令。
标签: c++ c performance cpu-architecture branch-prediction