【发布时间】:2019-06-22 16:21:24
【问题描述】:
我有一个手卷矩阵算法,它可以找到方阵右下平方的最大数(因此在迭代时,某些部分被“跳过”) - 存储为密集矩阵。在从 vs2010 更新到 vs2017 之后,它似乎要慢得多——总体下降了大约 50%。经过一番调查,这位于找到绝对最大值的函数的内部循环中。查看assembler 输出,这似乎是由于在紧密循环中插入了一些额外的mov 指令。以不同的方式重新设计循环似乎可以解决或部分解决问题。 相比之下,gcc 似乎没有这个“问题”。
简化示例(fabs 并不总是需要重现):
#include <cmath>
#include <iostream>
int f_slow(double *A, size_t from, size_t w)
{
double biga_absval = *A;
size_t ir = 0,ic=0;
for ( size_t j = 0; j < w; j++ ) {
size_t n = j*w;
for ( ; n < j*w+w; n++ ) {
if ( fabs(A[n]) <= biga_absval ) {
biga_absval = fabs( A[n] );
ir = j;
ic = n;
}
n++;
}
}
std::cout << ir <<ic;
return 0;
}
int f_fast(double *A, size_t from, size_t w)
{
double* biga = A;
double biga_absval = *biga;
double* n_begin = A + from;
double* n_end = A + w;
for (double* A_n = n_begin; A_n < n_end; ++A_n) {
if (fabs(*A_n) > biga_absval) {
biga_absval = fabs(*A_n);
biga = A_n;
}
}
std::cout << biga;
return 0;
}
int f_faster(double *A, size_t from, size_t w)
{
double biga_absval = *A;
size_t ir = 0,ic=0;
for ( size_t j = 0; j < w; j++ ) {
size_t n = j;
for ( ; n < j*w+w; n++ ) {
if ( fabs(A[n]) > biga_absval ) {
biga_absval = fabs( A[n] );
ir = j;
ic = n - j*w;
}
n++;
}
}
std::cout << ir <<ic;
return 0;
}
请注意:创建示例仅用于查看输出(索引等不一定有意义):
所以我的问题是:这只是一个(已知的?)优化器错误(?)还是在这种情况下似乎是明显的优化失误背后有一些逻辑?
使用最新稳定版vs201715.9.5
更新:我看到的额外movs 在跳转代码之前 - 在编译器资源管理器中找到的最简单方法是右键单击if,然后“滚动到”。
【问题讨论】:
-
f_fast正在检查 A 的每个元素(1x++A_n),f_faster仅每秒检查一次(2xn++在内部循环中)......这是故意的吗? -
这个问题可以从一些清理中受益。共有三个功能,但尚不清楚这三个功能中哪一个受到 VS2017 减速的影响。这些功能根本不一样。 3 个中的 2 个甚至忽略了
from参数。 -
@MatthieuBrucher:MSVC 没有
/O3选项。它会忽略它,您会得到默认的调试模式未优化代码。cl : Command line warning D9002 : ignoring unknown option '/O3'。这与 gcc/clang 不同,其中-O3启用完全优化,包括使用 gcc 进行自动矢量化。 (clang 在 -O2 处启用 auto-vec,但 gcc 仅在 -O3 处启用)。 -
我在stackoverflow.com/questions/32511862/… 中处理了类似的问题,原因是 Visual Studio ~2013 中 C++ 编译器的默认安全设置发生了变化。缓冲区溢出处理已更改,但我想这与您正在处理的问题不完全相同。
-
可能是 Spectre 缓解措施减缓了速度
标签: vs2010 vs2017 assembler mov gcc vs2017 mov c++ assembly visual-c++ visual-studio-2017 compiler-optimization