我正在运行测试性能,发现更改代码顺序可以使其更快而又不影响结果。
性能是通过使用 chrono 库执行时间来衡量的。
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)。
我更改了第一部分和第二部分的顺序,如果第二部分在第一部分之前执行,则会得到更快的结果。
这是整个程序的link。
答案 0 :(得分:5)
我会尝试使用perf stat -d <app>
运行两个版本,看看性能计数器的区别在哪里。
基准测试时,您可能希望固定CPU频率,因此它不会影响您的成绩。
在32字节边界上对齐循环通常可以将性能提高8-30%。有关更多详细信息,请参见Causes of Performance Instability due to Code Placement in X86 - Zia Ansari, Intel。
尝试使用-O3 -falign-loops=32 -falign-functions=32 -march=native -mtune=native
编译代码。
答案 1 :(得分:2)
在运行提供的程序时运行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
的下一次迭代的预取。
答案 2 :(得分:1)
更快的版本类似于在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)
我不知道这到底是哪种优化,要应用什么条件必须满足。没有explicitly listed for -O3个选项(-O2
+全部都不够)。显然,当循环计数器使用std::size_t
而不是int
时,它还没有这样做。