PHP:了解分支预测的工作原理

时间:2015-10-04 08:36:26

标签: php performance

阅读branch predication后,我试图了解它是如何运作的。

我写了一个基本测试(下面)。

我认为在第一个循环之后,php知道数组是如何构造的并且预测条件($items[$i] <= 150000)的结果,但是第二个循环的时间与第一个循环相同,并且似乎没有从分支预测中受益

有些问题:

  1. 也许php不支持分支预测?
  2. 也许我不明白分支预测?
  3. 我的测试错误/有其他性能问题?
  4. 我的测试:

    $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
    

    http://codepad.org/Zni0b5rS

1 个答案:

答案 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调试器可以显示它在实践中工作。