Ho un problema strano con alcuni codici SSE2 e AVX su cui ho lavorato. Sto costruendo la mia applicazione utilizzando GCC quale rilevamento delle funzioni della cpu di runtime. I file oggetto sono costruiti con bandiere separate per ogni funzione della CPU, ad esempio:SSE funziona lentamente dopo l'utilizzo di 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
Quando ho primo avvio il programma, trovo che le routine SSE2 sono come al solito con una spinta piacevole di velocità nel corso degli routine non SSE (circa il 100% più veloce). Dopo aver eseguito qualsiasi routine AVX, la stessa routine SSE2 ora funziona molto più lentamente.
Qualcuno potrebbe spiegare quale potrebbe essere la causa?
Prima dell'esecuzione della routine AVX, tutti i test sono di circa 80-130% più veloci rispetto alla matematica FPU, come si può vedere qui, dopo l'esecuzione della routine AVX, le routine SSE sono molto più lente.
Se ignoro le routine di test AVX, non vedo mai questa perdita di prestazioni.
Qui è la mia routine di 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);
}
E la versione AVX dello stesso.
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);
}
Ho anche eseguito questo tramite valgrind che non rileva errori.
Come viene misurato il tempo? – Gilles
@Gilles utilizzando 'clock_gettime (CLOCK_MONOTONIC, & start);' prima e dopo, quindi calcola la differenza. – Geoffrey
Ho incontrato problemi curiosi con SSEX e codice AVX misti ..., principalmente perché la generazione del codice Link Time/etc. i problemi. Guarda (e forse pubblica) i tuoi file di assemblaggio. – Christopher