使用 AVX 后 SSE 运行缓慢 [重复]

Posted

技术标签:

【中文标题】使用 AVX 后 SSE 运行缓慢 [重复]【英文标题】:SSE runs slow after using AVX [duplicate] 【发布时间】:2015-10-15 13:16:08 【问题描述】:

我一直在处理的一些 SSE2 和 AVX 代码有一个奇怪的问题。我正在使用运行时 cpu 功能检测的 GCC 构建我的应用程序。目标文件为每个 CPU 功能使用单独的标志构建,例如:

g++ -c -o ConvertSamples_SSE.o ConvertSamples_SSE.cpp -std=c++11 -fPIC -O0 -g -Wall -I./include -msse
g++ -c -o ConvertSamples_SSE2.o ConvertSamples_SSE2.cpp -std=c++11 -fPIC -O0 -g -Wall -I./include -msse2
g++ -c -o ConvertSamples_AVX.o ConvertSamples_AVX.cpp -std=c++11 -fPIC -O0 -g -Wall -I./include -mavx

当我第一次启动该程序时,我发现 SSE2 例程正常,与非 SSE 例程相比具有很好的速度提升(快 100% 左右)。在我运行任何 AVX 例程后,完全相同的 SSE2 例程现在运行速度要慢得多。

有人能解释一下这可能是什么原因吗?

在 AVX 例程运行之前,所有测试都比 FPU 数学快 80-130% 左右,从这里可以看出,在 AVX 例程运行之后,SSE 例程要慢得多。

如果我跳过 AVX 测试例程,我永远不会看到这种性能损失。

这是我的 SSE2 例程

void Float_S16(const float *in, int16_t *out, const unsigned int samples)

  static float  ratio = (float)Limits<int16_t>::range() / (float)Limits<float>::range();
  static __m128 mul   = _mm_set_ps1(ratio);

  unsigned int i;
  for (i = 0; i < samples - 3; i += 4, in += 4, out += 4)
  
    __m128i con = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(in), mul));
    out[0] = ((int16_t*)&con)[0];
    out[1] = ((int16_t*)&con)[2];
    out[2] = ((int16_t*)&con)[4];
    out[3] = ((int16_t*)&con)[6];
  

  for (; i < samples; ++i, ++in, ++out)
    *out = (int16_t)lrint(*in * ratio);

和AVX版本一样。

void Float_S16(const float *in, int16_t *out, const unsigned int samples)

  static float ratio = (float)Limits<int16_t>::range() / (float)Limits<float>::range();
  static __m256 mul  = _mm256_set1_ps(ratio);

  unsigned int i;
  for (i = 0; i < samples - 7; i += 8, in += 8, out += 8)
  
    __m256i con = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_load_ps(in), mul));
    out[0] = ((int16_t*)&con)[0];
    out[1] = ((int16_t*)&con)[2];
    out[2] = ((int16_t*)&con)[4];
    out[3] = ((int16_t*)&con)[6];
    out[4] = ((int16_t*)&con)[8];
    out[5] = ((int16_t*)&con)[10];
    out[6] = ((int16_t*)&con)[12];
    out[7] = ((int16_t*)&con)[14];
  

  for(; i < samples; ++i, ++in, ++out)
    *out = (int16_t)lrint(*in * ratio);

我也通过 valgrind 运行了这个,它没有检测到错误。

【问题讨论】:

时间是如何计算的? @Gilles 使用clock_gettime(CLOCK_MONOTONIC, &amp;start); 前后,然后计算差异。 你觉得和这个有关吗? Intel: Avoiding AVX-SSE Transition Penalties; Intel® AVX State Transitions: Migrating SSE Code to AVX 除了混合 AVX/SSE 问题,不要用 -O0 进行基准测试,这很愚蠢。至少使用-Og,最好使用-O3 @Geoffrey: -Og 使可调试的代码可以逐行单步执行。这显然是编辑/编译/调试周期的建议选项。使用-O0 进行基准测试有时有用,有时没有。使用 -O3 时源 A 可能比源 B 快,但使用 -O0 时更慢。我想不出任何有巨大差异的例子,但如果你要查看时间数字,请使用-Og 【参考方案1】:

混合使用 AVX 代码和旧版 SSE 代码会导致性能下降。最合理的解决方案是在一段 AVX 代码之后执行 VZEROALL 指令,尤其是在执行 SSE 代码之前。

根据 Intel 的图表,转换进入或退出状态 C(保存了上半部分 AVX 寄存器的传统 SSE)时的损失约为 100 个时钟周期。其他的转换只有1个周期:

参考资料:

Intel: Avoiding AVX-SSE Transition Penalties Intel® AVX State Transitions: Migrating SSE Code to AVX

【讨论】:

此问题可能会产生与此惩罚完全无关的剧烈效果。请参阅this question,其中 OP 在只有 8 个超线程的系统上看到了超过 500 个线程的加速。

以上是关于使用 AVX 后 SSE 运行缓慢 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Ubuntu - 如何判断 CPU 应用程序当前正在使用 AVX 还是 SSE?

如何检查编译代码是否使用SSE和AVX指令?

AVX mat4 inv 实现比 SSE 慢

如何使用 SSE4.2 和 AVX 指令编译 Tensorflow?

如何使用 SSE4.2 和 AVX 指令编译 Tensorflow?

如何使用 SSE4.2 和 AVX 指令编译 Tensorflow?