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