У меня странная проблема с некоторыми SSE2 и кодом AVX, над которыми я работал. Я создаю свое приложение, используя 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 все тесты примерно на 80-130% быстрее, чем математика FPU, как можно видеть здесь, после выполнения процедуры 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, который не обнаруживает ошибок.