java for循环中的分支预测

时间:2015-05-21 09:44:25

标签: java javafx java-8 branch-prediction

我在if条件旁边看到了这条评论:

  

// branch prediction favors most often used condition

JavaFX SkinBase类的源代码中。

protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {

    double minX = 0;
    double maxX = 0;
    boolean firstManagedChild = true;
    for (int i = 0; i < children.size(); i++) {
        Node node = children.get(i);
        if (node.isManaged()) {
            final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();
            if (!firstManagedChild) {  // branch prediction favors most often used condition
                minX = Math.min(minX, x);
                maxX = Math.max(maxX, x + node.minWidth(-1));
            } else {
                minX = x;
                maxX = x + node.minWidth(-1);
                firstManagedChild = false;
            }
        }
    }
    double minWidth = maxX - minX;
    return leftInset + minWidth + rightInset;
}

我相信开发人员想解释他为什么写negate if

这种优化真的很有用吗?

4 个答案:

答案 0 :(得分:12)

JavaFX团队的人员非常注重性能,因此他们肯定知道切换if和else对分支预测没有实质性影响。

我认为这表明重构没有显着的性能提升:

double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;

for (int i = 0; i < children.size(); i++) {
  Node node = children.get(i);
  if (node.isManaged()) {
    final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();
    minX = Math.min(minX, x);
    maxX = Math.max(maxX, x + node.minWidth(-1));
  }
}

因为分支预测基本上会将if / else变为类似的东西(给予或接受)。

This commit确认了这个解释,虽然我不确定他们为什么改变它 - 可能是因为当isManaged条件永远不真实时它有副作用...

进一步调查,提交引用a bug "up to 50% performance regression in Controls benchmarks"(您需要登录才能访问它)。

似乎他们遇到了性能问题,而且调查时发现代码中存在错误(与我上面的例子类似)。他们修复了这个错误,并添加了一条注释,以澄清该修复程序不会影响性能,这要归功于分支预测。

摘录:

  

     

[..]查看代码,我注意到在没有管理皮肤的孩子的情况下出现错误。在这种情况下,minX / Y和maxX / Y最终将为MAX / MIN_VALUE,我们真的希望它们为零。因此,此更改集修复了该问题。在测试中,我看到了一个小的(~1 fps)性能改进,所以我不认为这个改变可以解决性能问题。无论如何,代码必须是它的方式。

     

[...]请注意,使用MIN / MAX时存在一个错误 - 这些值不是Float和Double的最大值和最小值(这对于整数类型来说是有意义的,但它是不是他们指定的方式)。要对浮点值执行最小/最大操作,您需要使用NEGATIVE / POSITIVE_INFINITY值来实现您要查找的结果。

答案 1 :(得分:4)

句子“分支预测有利于最常用的条件”并未说明评估条件的价值,无论是正面还是负面。它只表示分支预测可以帮助更频繁使用的条件分支,即循环中的条件分支。所以它基本上说,在循环中使用if是可以的。

虽然结论是正确的,但你不应该担心循环中的if(除非探查器告诉你存在瓶颈,否则你不应该担心任何事情),这句话本身是毫无意义的在Java的上下文中。

分支预测是一个CPU特性,因此在解释执行中它与Java级分支无关,因为它们只是修改解释器的状态(即指针将被读取的下一条指令),但与CPU指令无关。具体到特定的分支。

一旦HotSpot开始,图片就完全不同了。如果这个代码是一个热点,优化器将应用大量的代码转换,这些代码转换可以最大限度地假设Java代码将如何执行,错误。

一个常见的优化是循环展开。不是让一个代码块表示循环的主体,而是会有多个实例跟随彼此,针对其特定迭代的不变量进行优化。此设置允许完全忽略if相关分支,因为完全可以预测firstManagedChildtruefalse的第一次转换后,它将永远不会返回,因此虽然第一次迭代总是会看到true值,但可以优化后续迭代的代码,将变量视为常量false

因此,在这种情况下,分支预测将再次没有意义,因为if语句没有分支,其结果可以提前预测。

答案 2 :(得分:3)

可以找到一篇关于分支预测的详细文章here

回答你的问题 - 根据我的理解,不。我不认为否定&#34; if&#34;会有任何不同。它会优化重复假值的条件,就像多个真值一样。

答案 3 :(得分:0)

除现有答案外:

这个评论似乎并不是&#34;否定的理由,如果&#34; (因为无论如何,这不应该在性能上有所不同)。相反,它可能是尝试&#34;优化&#34;代码并避免使用单if。这可能是这样的:

protected double computeMinWidth(double height, double topInset, 
    double rightInset, double bottomInset, double leftInset) {

    double minX = 0;
    double maxX = 0;

    // Initialize minX/maxX with the coordinate of the FIRST managed child
    int i = 0;
    for (i = 0; i < children.size(); i++) {
        Node node = children.get(i);
        if (node.isManaged()) {
            final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();
            minX = x;
            maxX = x + node.minWidth(-1);
        }
    }

    // Continue the loop at the last index, updating the
    // minX/maxX with the remaining managed children
    for (; i < children.size(); i++) {
        Node node = children.get(i);
        if (node.isManaged()) {
            final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();

            // Don't have to check whether it's the first managed child here. 
            // Just do the update.

            minX = Math.min(minX, x);
            maxX = Math.max(maxX, x + node.minWidth(-1));
        }
    }
    double minWidth = maxX - minX;
    return leftInset + minWidth + rightInset;
}

评论表明,由于保存if,这不会带来任何性能优势,因为此if实际上由于分支预测而基本上是免费的。

旁注:我认为可能有其他&#34;微优化&#34;,如the docs。但是JavaFX的人(希望)知道他们的东西,如果它可能会对他们的情况产生影响,可能会这样做)