启用 arch:SSE2 使程序变慢
Posted
技术标签:
【中文标题】启用 arch:SSE2 使程序变慢【英文标题】:Enabling arch:SSE2 makes program slower 【发布时间】:2012-03-13 21:49:13 【问题描述】:在 Visual Studio 2010 上,当我在以下代码上启用增强指令集时,实际上会增加执行时间。
void add(float * input1, float * input2, float * output, int size)
for(int iter = 0; iter < size; iter++)
output[iter] = input1[iter] * input2[iter];
int main()
const int SIZE = 10000000;
float *in1 = new float[SIZE];
float *in2 = new float[SIZE];
float *out = new float[SIZE];
for(int iter = 0; iter < SIZE; iter++)
in1[iter] = std::rand();
in2[iter] = std::rand();
out[iter] = std::rand();
clock_t start = clock();
for(int iter = 0; iter < 100; iter++)
add(in1, in2, out, SIZE);
clock_t end = clock();
double time = difftime(end,start)/(double)CLOCKS_PER_SEC;
system("PAUSE");
return 0;
在启用 SSE2 的情况下,time
变量我一直得到大约 2.0
秒,但当它是“未设置”时大约是 1.7
秒。我正在构建 Windows 7 64 位,VS 2010 专业版,发布配置,优化速度。
是否有任何解释为什么启用 SSE 会导致执行时间更长?
【问题讨论】:
您是否查看过生成的程序集,看看它是否使用了任何 SSE 指令? 您是使用调试版本还是发布版本? @RetiredNinja 我不太了解汇编,但我可以确认它仅在启用 SSE 的版本上使用 SSE 所需的寄存器(确切地说是 xmm1 和 xmm0)。new float[SIZE];
会提供正确对齐的数据(我的意思是与 SSE 对齐)吗?
@R.MartinhoFernandes 没关系。 MSVC 不会自动矢量化。这种情况我以前见过几次。由于 MSVC 不进行矢量化,因此 SSE 并不比 x87 FPU 好。因此,微小的差异可以使任何一个都快一点。
【参考方案1】:
在 SSE 代码中将值移入和移出 SSE 寄存器会产生开销,如果您只进行很少的简单计算(如您的示例所示),这可能会超过 SSE 的性能优势。
另请注意,如果您的数据不是 16 字节对齐的,则此开销会显着增加。
【讨论】:
在这种情况下这无关紧要,因为 MSVC 不进行矢量化。所以它只是使用 SSE 寄存器代替 x87 FPU。没有“四处走动”。同样,对齐只适用于向量 SSE - MSVC 不会自行生成。 我以前使用过 SSE 编译器内部函数并注意到它的加速,所以如果你必须明确地使用 SSE,那么首先使用 arch:SSE 编译器选项有什么意义? @Mystical:好点,我实际上并不知道 MSVC 根本不矢量化。不过文档说,它可能会混合使用 x87 和 SSE2 代码,这可能会导致一些移动(尽管我很难想象编译器会在这样一个简单的示例中搞砸)。唯一确定的方法当然是检查程序集。 @JAKE6459 在 x64 上,您可以获得 8 个额外寄存器的好处。至于 x86,我认为代码稍微简单一些,因为 SSE 比 x87 更灵活(不需要xchg
和类似的垃圾)。但它是否产生任何加速是非常有条件的。【参考方案2】:
IMO,依靠编译器进行这些优化通常不是一个好主意。您的代码应该运行得更快(除非编译器已经为您执行此操作,但似乎并非如此)。我建议
1 确保您的数组是 16 字节对齐的
2 在您的内联添加函数中使用 SSE 内在函数:
#include <xmmintrin.h>
inline void add(const float * input1, const float * input2, float * output, int size)
// assuming here that
// - all 3 arrays are 16-byte aligned
// - size is a multiple of 4
for(int iter = 0; iter < size; iter += 4)
_mm_store_ps( output+iter, _mm_mul_ps( _mm_load_ps(input1+iter),
_mm_load_ps(input2+iter) ) );
如果这不能产生更快的代码,那么加载和存储确实会为单个乘法运算产生过多的开销。
【讨论】:
以上是关于启用 arch:SSE2 使程序变慢的主要内容,如果未能解决你的问题,请参考以下文章