繁体   English   中英

为什么局部可变长度的for循环更快? 分支预测不会减少查找时间的影响吗?

[英]Why are local variable length for-loops faster? Doesn't branch prediction reduce the effect of lookup times?

前阵子,当我来的时候,我正在阅读一些Android性能提示

Foo[] mArray = ...

public void zero() {
    int sum = 0;
    for (int i = 0; i < mArray.length; ++i) {
        sum += mArray[i].mSplat;
    }
}

public void one() {
    int sum = 0;
    Foo[] localArray = mArray;
    int len = localArray.length;

    for (int i = 0; i < len; ++i) {
        sum += localArray[i].mSplat;
    }
}

Google说:

zero()最慢,因为JIT尚无法优化循环中每次迭代一次获取数组长度的成本。

one()更快。 它将所有内容提取到局部变量中,从而避免了查找。 只有阵列长度才能提供性能优势。

完全有意义。 但是对我的计算机体系结构考试考虑得太多之后,我想起了Branch Predictors

分支预测器是一种数字电路,它试图猜测在确定之前知道分支(例如,if-then-else结构)将走哪条路。 分支预测器的目的是改善指令管道中的流程。

计算机是否不是假设 i < mArray.length true ,从而并行计算循环条件和循环主体 (并且仅预测最后一个循环的错误分支) ,从而有效地消除了性能损失?

我也在考虑投机执行

推测执行是一种优化技术,其中计算机系统执行某些实际上可能不需要的任务……目标是提供更多的并发性……

在这种情况下, 计算机将同时执行代码,就好像循环已经完成,并且好像仍在并发进行一样 ,再次有效地消除了与该条件相关的任何计算成本 (因为计算机已经为将来执行了计算)它计算条件)?

从本质上讲,我试图得出的事实是,即使zero()的条件要比one()花费更长的时间进行计算,计算机通常也会在等待检索时计算出正确的代码分支无论如何,都是对条件语句的答案,因此对myAray.length的查找中的性能损失不重要(无论如何,这就是我的想法)。

这里有我没有意识到的东西吗?


很抱歉问题的长度。

提前致谢。

您链接到的站点注释:

zero()最慢,因为JIT尚无法优化循环中每次迭代一次获取数组长度的成本。

我尚未在Android上进行过测试,但现在我认为这是对的。 这意味着,对于循环的每次迭代,CPU必须执行从内存加载mArray.length值的代码。 原因是数组的长度可能会更改,因此编译器无法将其视为静态值。

而在one()选项中,程序员根据对数组长度不变的认识来显式设置len变量。 由于这是一个局部变量,因此编译器可以将其存储在寄存器中,而不必在每次循环迭代中从内存中加载它。 因此,这将减少循环中执行的指令数量,并使分支更容易预测。

没错,分支预测有助于减少与循环条件检查相关的开销。 但是仍然有可能进行多少推测,因此在每个循环迭代中执行更多的指令会产生额外的开销。 同样,许多移动处理器的分支预测器也不那么先进,并且不支持那么多的推测。

我的猜测是,在使用像HotSpot这样的高级Java JIT的现代台式机处理器上,您不会看到3倍的性能差异。 但是我不确定,尝试尝试可能是一个有趣的实验。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM