2015-10-15 31 views
10

Çalıştığım bazı SSE2 ve AVX kodlarıyla ilgili garip bir sorun var. Uygulamamı cpu özelliği algılaması olan GCC'yi kullanarak uygulamamı yapıyorum. nesne dosyaları örneğin, her işlemci özelliği için ayrı bayraklarıyla inşa edilir: İlk program başlatmak zamanSSE, AVX'yi kullandıktan sonra yavaş çalışıyor

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 

, ben SSE2 rutinleri olmayan SSE rutinleri üzerinde güzel bir hız artışı ile normal başına olduğunu fark (yaklaşık% 100 daha hızlı). Herhangi bir AVX rutinini çalıştırdıktan sonra, tam olarak aynı SSE2 yordamı çok daha yavaş çalışır.

Birisi bunun nedeninin ne olduğunu açıklayabilir mi?

AVX yordamını çalıştırmadan önce, tüm testler yaklaşık olarak% 80-130 daha hızlı ve ardından FPU matematiği, burada görüldüğü gibi AVX yordamından sonra, SSE yordamları çok daha yavaştır.

AVX sınama yordamlarını atlarsam, bu performans kaybını asla göremiyorum.

İşte benim rutin 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); 
} 

Ve aynı AVX versiyonudur.

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); 
} 

Ayrıca bunu hatasız algılayan valgrind ile çalıştırıyorum.

+1

ölçülür diğer geçişler sadece 1 döngü vardır? – Gilles

+0

@Gilles, clock_gettime (CLOCK_MONOTONIC, & start); 'önce ve sonra, sonra farkı hesaplayarak. – Geoffrey

+0

Karışık SSEX ve AVX kodu ile meraklı sorunlarla karşılaşıyorum ... çoğunlukla Link Time code generation/etc. sorunları. Montaj dosyalarınızı arayın (ve belki de gönderin). – Christopher

cevap

15

AVX kodunu ve eski SSE kodunu karıştırmak bir performans cezası gerektirir. En mantıklı çözüm, özellikle de SSE kodunu çalıştırmadan önce bir AVX segmenti kodundan sonra VZEROALL komutunun yürütülmesidir. Intel'in şemasına göre, C'ye (C) giriş veya çıkış sırasında (kaydedilen AVX kayıtlarının üst yarısı olan eski SSE) kaydedilen ceza, 100 saat döngüsünde gerçekleşir.

Kaynaklar: Zaman nasıl

+2

Bu sorun, bu ceza ile tamamen alakasız görünen etkileyici etkileri etkileyebilir. OP'nin sadece sekiz hiper-dişi olan bir sistemde 500'den fazla iş parçacığı ile bir hızda görüldüğü [bu soru] bölümüne bakın (http://stackoverflow.com/q/21960229/2542702). –