Mam dziwny problem z niektórymi kodami SSE2 i AVX, nad którymi pracowałem. Buduję swoją aplikację za pomocą GCC, który wykrywa funkcje procesora runtime. Pliki wynikowe są zbudowane z oddzielnych flagi dla każdej funkcji procesora, na przykład:SSE działa wolno po użyciu AVX
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
Kiedy po raz pierwszy uruchomić program, uważam, że procedury SSE2 są za normalne z ładnym prędkości podbicia nad rutyny spoza SSE (około 100% szybciej). Po uruchomieniu dowolnej procedury AVX, ta sama procedura SSE2 działa teraz znacznie wolniej.
Czy ktoś mógłby wyjaśnić, jaka jest tego przyczyna?
Przed uruchomieniem procedury AVX wszystkie testy są około 80-130% szybsze niż matematyka FPU, jak widać tutaj, po uruchomieniu procedury AVX, procedury SSE są znacznie wolniejsze.
Jeśli pominę procedury testowe AVX, nigdy nie zobaczę utraty wydajności.
Oto moja SSE2 rutyna
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);
}
a wersja AVX tego samego.
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);
}
Uruchomiłem to również przez valgrind, który wykrywa brak błędów.
W jaki sposób mierzy się czas? – Gilles
@Gilles używając 'clock_gettime (CLOCK_MONOTONIC, & start);' przed i po, a następnie obliczając różnicę. – Geoffrey
Wpadłem w dziwne problemy z mieszanym kodem SSEX i AVX ..., głównie z powodu generowania kodu Link Time/etc. problemy. Spójrz (i być może dodaj) swoje pliki zespołu. – Christopher