我有一些奇怪的问题,一些SSE2和AVX代码我一直在努力.我使用GCC构建我的应用程序,哪个运行时cpu功能检测.目标文件是用每个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,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,++out) *out = (int16_t)lrint(*in * ratio); }
我也通过valgrind运行它,检测没有错误.
解决方法
混合AVX代码和旧版SSE代码会导致性能损失.最合理的解决方案是在AVX段代码之后执行VZEROALL指令,特别是在执行SSE代码之前.
根据英特尔的图表,转换到或退出状态C(保留了AVX寄存器的上半部分的传统SSE)的转换时间为100个时钟周期.其他转换只有1个周期:
参考文献:
> Intel: Avoiding AVX-SSE Transition Penalties
> Intel® AVX State Transitions: Migrating SSE Code to AVX