簡體   English   中英

為什么代碼的位置會影響C ++的性能?

[英]Why does position of code affect performance in C++?

我正在運行測試性能,並發現更改代碼的順序使其更快,而不會影響結果。

使用計時庫通過時間執行來衡量性能。

vector< vector<float> > U(matrix_size, vector<float>(matrix_size,14));
vector< vector<float> > L(matrix_size, vector<float>(matrix_size,12));
vector< vector<float> > matrix_positive_definite(matrix_size, vector<float>(matrix_size,23));

for (i = 0; i < matrix_size; ++i) {         
   for(j= 0; j < matrix_size; ++j){
//Part II : ________________________________________
    float sum2=0;               
    for(k= 0; k <= (i-1); ++k){
      float sum2_temp=L[i][k]*U[k][j];
      sum2+=sum2_temp;
    }
//Part I : _____________________________________________
    float sum1=0;       
    for(k= 0; k <= (j-1); ++k){
      float sum1_temp=L[i][k]*U[k][j];
      sum1+=sum1_temp;
    }           
//__________________________________________
    if(i>j){
      L[i][j]=(matrix_positive_definite[i][j]-sum1)/U[j][j]; 
    }
    else{
       U[i][j]=matrix_positive_definite[i][j]-sum2;
    }   
   }
}

我用g++ -O3 (Intel i5 / Win10中的GCC 7.4.0)編譯。 如果第二部分在第一部分之前執行,我改變了第一部分和第二部分的順序並得到了更快的結果。發生了什么?

這是整個計划的鏈接

我會嘗試使用perf stat -d <app>運行這兩個版本,並查看性能計數器的不同之處。

在進行基准測試時,您可能希望修復CPU頻率,因此不會影響您的分數。


在32字節邊界上對齊循環通常會使性能提高8-30%。 有關詳細信息,請參閱X86中的代碼放置導致性能不穩定的原因 - Zia Ansari,Intel

嘗試使用-O3 -falign-loops=32 -falign-functions=32 -march=native -mtune=native編譯代碼。

在使用提供的程序播放時運行perf stat -ddd表明兩個版本之間的主要區別主要在於預取。

part II -> part I   and   part I -> part II (original program)
   73,069,502      L1-dcache-prefetch-misses

part II -> part I   and   part II -> part I (only the efficient version)
   31,719,117      L1-dcache-prefetch-misses

part I -> part II   and   part I -> part II (only the less efficient version)
  114,520,949      L1-dcache-prefetch-misses

nb:根據編譯器資源管理器, part II -> part I非常類似於第一part I -> part II

我猜想,在i上的第一次迭代中, part II幾乎沒有任何作用,但是j迭代使得第一part I根據一種模式訪問U[k][j] ,該模式將簡化對i的下一次迭代的預取。

更快的版本類似於在if (i > j)內移動循環時獲得的性能。

if (i > j) {
    float sum1 = 0;
    for (std::size_t k = 0; k < j; ++k){
        sum1 += L_series[i][k] * U_series[k][j];
    }
    L_parallel[i][j] = matrix_positive_definite[i][j] - sum1;
        L[i][j] /= U[j][j];
}
if (i <= j) {
    float sum2 = 0;
    for (std::size_t k = 0; k < i; ++k){
        sum2 += L_series[i][k] * U_series[k][j];
    }
    U_parallel[i][j] = matrix_positive_definite[i][j] - sum2;
}

所以我假設在一種情況下編譯器能夠自己進行轉換。 它只發生在-O3對我來說。 (1950X,msys2 / GCC 8.3.0,Win10)

我不知道這究竟是哪種優化以及必須滿足哪些條件才能應用。 它沒有為-O3明確列出的選項( -O2 +所有這些都不夠)。 顯然,當std::size_t而不是int用於循環計數器時,它已經不會這樣做了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM