代码优化以避免分支

Mar*_* A. 3 java performance minimum branch-prediction

我刚刚看到这篇文章:计算没有分支的两个整数的最小值或最大值

它始于"[o] n一些罕见的机器,其中分支是昂贵的......".

我曾经认为分支总是很昂贵,因为它经常迫使处理器清除并重新启动它的执行管道(例如,为什么处理排序数组比未排序数组更快?).

这给我留下了几个问题:

  • 这篇文章的作者是否错了?或者这篇文章可能是在分支出现问题之前编写的(我找不到日期).
  • 现代处理器是否有办法在(x < y) ? x : y没有性能下降的情况下完成最小的分支?
  • 或者所有现代编译器是否只是自动执行此hack?具体来说,Java做什么?特别是因为它的Math.min(...)功能就是那个三元语句......

maa*_*nus 6

这篇文章的作者是否错了?或者这篇文章可能是在分支出现问题之前编写的(我找不到日期).

最古老的评论是5岁,所以这不是热门新闻.然而,不可预测的分支总是很昂贵,5年前也是如此.与此同时,它变得更糟,因为现代CPU可以在每个周期执行更多操作,因此错误预测的分支会花费更多的工作.

但从某种意义上说,作家是对的.我们的PC和服务器中没有大多数CPU,但在情况不同的嵌入式设备中找不到.

现代处理器是否有办法完成像(x <y)中那样的最小分支?x:y没有性能下降?

是的,不是.AFAIK Math.max总是被翻译为条件移动,这意味着没有分支.您拥有max可能会或可能不会使用它,具体取决于JVM收集的统计信息.

没有银弹.通过可预测的结果,分支更快.确切地说,CPU识别出什么样的模式很难.JVM只是查看分支获取的频率,并使用大约18%的魔术阈值.有关详细信息,请参阅我自己的问答.

或者所有现代编译器是否只是自动执行此hack?具体来说,Java做什么?特别是因为它的Math.min(...)函数只是那个三元语句......

它实际上是一个编译器内在的.每当JITc看到这个方法被调用时,它就会特别处理它.复制方法时,它没有特殊处理.

在这种情况下,内在函数不是很有用,因为它无论如何都会得到大量优化.对于类似的方法Long#numberOfLeadingZeros,内在函数是必不可少的,因为代码是相当漫长而缓慢的,现代CPU可以在一个循环中完成.