[英]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.