阅读branch predication后,我试图了解它是如何运作的。
我写了一个基本测试(下面)。
我认为在第一个循环之后,php知道数组是如何构造的并且预测条件($items[$i] <= 150000)
的结果,但是第二个循环的时间与第一个循环相同,并且似乎没有从分支预测中受益
有些问题:
我的测试:
$count = 300000;
$items = array();
$found = 0;
// build array
for ($i = 0; $i <= $count; $i++) {
array_push($items, rand(0, $i));
}
// first loop with no predication benefit
// ------------------------------------
$time_start = microtime(true);
for($i = 0; $i <= $count; $i++) {
$found = ($items[$i] <= 150000) ? $found+1 : $found;
}
$time_end = microtime(true);
$time = $time_end - $time_start;
// ------------------------------------
echo "first loop\r\n";
echo 'Found:'. $found . "\r\n";
echo 'End:' . $time . "\r\n";
// reset counter
$found = 0;
// second loop with predication benefit
// ------------------------------------
$time_start = microtime(true);
for($i = 0; $i <= $count; $i++) {
$found = ($items[$i] <= 150000) ? $found+1 : $found;
}
$time_end = microtime(true);
$time = $time_end - $time_start;
// ------------------------------------
echo "second loop\r\n";
echo 'Found:'. $found . "\r\n";
echo 'End:' . $time . "\r\n";
输出
first loop
Found:254052
End:0.093052864074707
second loop
Found:254052
End:0.092923879623413
答案 0 :(得分:4)
<强> TL; TR 强>
分支预测是硬件功能。
在这种情况下,受益于硬件功能的编程语言是C. (PHP用C语言编写)。或者真正说出了从PHP的C源代码编译的机器代码。所以是的,你已经从分支预测中受益了,但不是你想象的那样。
受益于分支预测发生在更低的水平上。基本上你需要知道后续的机器(!)命令在执行之前被加载到CPU的管道中。但加载命令需要时间。
如果要执行条件跳转命令,如果条件求值为true,则管道中的后续命令可能不再是最新的,因为跳转命令告诉CPU继续从完整加载命令(机器(!))代码中的不同位置 - 跳转目标 - 在这种情况下。
这意味着CPU需要刷新现有管道并使用启动跳转目标位置的命令重新填充它。如果在该位置存在另一个跳跃目标,则会再次发生相同的跳跃目标。请注意,条件跳转是最常见的机器代码命令之一。
也就是说,命令管道的性能基本上是不够的。
如果CPU可能很聪明并猜测条件评估为真,即使在之前得到评估,该怎么办?它可以在将跳转命令加载到管道中后立即从该跳转目标加载命令。请注意,加载不等于执行!同样,CPU在评估条件之前尝试猜测。如果猜测错误,CPU当然仍然需要刷新管道并用正确的命令重新填充它。但是,与不猜测相比,冲洗的可能性要好得多。
有多种算法可以实现猜测,从静态方法到动态方法,考虑到目前代码所做的工作。它们非常复杂,成功率非常高。回到维基百科,解释算法:
https://en.wikipedia.org/wiki/Branch_predictor
返回PHP代码;即使第一个循环也可能从分支预测中受益。
是的,显然两个循环都是相同的,因此只需要执行一次。但是,PHP作为一种解释性编程语言,对于分析这些硬件功能来说是一个太高的层次,因为幕后发生的事情太多了。 (甚至可能在循环之间切换任务)。
顺便说一句,如果您在C中编写可比较的代码,C编译器可能会选择这样做。例如gcc可以检测到很多这样的情况。 (太棒了!)但是,这已经发生在编译时,甚至在运行时之前。
如果您愿意分析分支预测,使用汇编语言和GDB调试器可以显示它在实践中工作。