启用arch:SSE2会使程序变慢

3
在 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会导致更长的执行时间?


3
你是否查看了生成的汇编代码,以确定其是否使用了任何SSE指令? - Retired Ninja
你是用调试版本还是发布版本来做这个? - Paul R
@RetiredNinja 我不是很熟悉汇编语言,但我可以确认只有在启用SSE的版本中才会使用所需的寄存器(确切地说是xmm1和xmm0)。 - contrapsych
new float[SIZE];会提供适当对齐的数据吗(我是指SSE对齐)? - R. Martinho Fernandes
1
@R.MartinhoFernandes 这并不重要。MSVC不会自动向量化。我以前遇到过这种情况。由于MSVC不进行向量化,SSE并不比x87 FPU更好。因此,微小的差异可能使其中任何一个略微快一点。 - Mysticial
这些结果与您的处理器有一定的紧密耦合。它在所有测试过的处理器上都比较慢,还是只有在您自己的处理器上?(顺便问一下,您用的是什么处理器?)对于某些SSE指令(特别是预缓存),我会在AMD和Intel之间获得巨大的差异。 - BatchyX
2个回答

2

在SSE代码中,将值移入和移出SSE寄存器存在额外开销,如果你只进行非常少量的简单计算(例如你的例子),这种开销可能会抵消SSE带来的性能优势。

此外,请注意,如果你的数据没有16字节对齐,这种开销会显著增加。


2
这在这种情况下并不相关,因为MSVC不进行向量化。因此,它只是使用SSE寄存器代替x87 FPU。没有“移动”。同样,对齐仅适用于矢量SSE - 这是MSVC本身不会生成的。 - Mysticial
我之前使用过 SSE 编译器内置函数,并注意到了速度的提升,所以如果必须显式地使用 SSE 才能使用 SSE,那么一开始使用 arch:SSE 编译器选项有什么意义呢? - contrapsych
@Mystical:说得好,我其实不知道MSVC根本不进行向量化。文档中提到,它可能使用x87和SSE2代码的混合体,这可能会导致一些移动(尽管我几乎无法想象编译器在如此简单的示例中搞砸这个问题)。当然,确保的唯一方法是检查汇编代码。 - ComicSansMS
@JAKE6459 在 x64 上,你可以获得额外的 8 个寄存器的好处。至于 x86,我想代码会更简单,因为 SSE 比 x87 更灵活(不需要 xchg 和类似的垃圾)。但它是否产生任何加速取决于具体情况。 - Mysticial

2

在我看来,依靠编译器进行优化并不是一个好主意。除非编译器已经自动对你的代码进行了优化,但这似乎并不是情况。我建议:

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) ) );
}

如果这不能产生更快的代码,那么加载和存储会为单个乘法运算产生太多的开销。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接