簡體   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