java for循环中的分支预测

gon*_*ard 8 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;
}
Run Code Online (Sandbox Code Playgroud)

我相信开发人员想要解释为什么他写了否定if.

这个优化真的有用吗?

ass*_*ias 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));
  }
}
Run Code Online (Sandbox Code Playgroud)

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


这个提交确认了这个解释,虽然我不确定他们为什么改变它 - 可能是因为当isManaged条件从来没有时它有副作用...

进一步调查,提交引用了一个错误"控件基准测试中高达50%的性能回归"(您需要登录才能访问它).

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

摘录:

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

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