FMA3 w GCC: jak włączyć

Mam i5-4250U, który ma AVX2 i FMA3. Testuję kod mnożenia macierzy w GCC 4.8.1 na Linuksie, który napisałem. Poniżej znajduje się lista trzech różnych sposobów kompilacji.

SSE2:     gcc matrix.cpp -o matrix_gcc -O3 -msse2 -fopenmp
AVX:      gcc matrix.cpp -o matrix_gcc -O3 -mavx  -fopenmp
AVX2+FMA: gcc matrix.cpp -o matrix_gcc -O3 -march=native -fopenmp -ffast-math

Wersja SSE2 i AVX wyraźnie różnią się wydajnością. Jednak AVX2 + FMA nie jest lepszy niż wersja AVX. Nie rozumiem tego. Dostaję ponad 80% szczytowych flopów procesora zakładając, że nie ma FMA, ale myślę, że powinienem być w stanie zrobić dużo lepiej z FMA. Matrix Mnożenie powinno korzystać bezpośrednio z FMA. Zasadniczo robię osiem produktów dot na raz w AVX. Kiedy sprawdzam march=native daje:

cc -march=native -E -v - </dev/null 2>&1 | grep cc1 | grep fma 
...-march=core-avx2 -mavx -mavx2 -mfma -mno-fma4 -msse4.2 -msse4.1 ...

Więc widzę, że jest włączona (dla pewności dodałem -mfma ale to nie robi różnicy). ffast-math powinien pozwolić na relaksujący model zmiennoprzecinkowy Jak używać instrukcji Fused Multiply-Add (FMA) z SSE / AVX

Edit:

Na podstawie komentarzy Mysticiala poszedłem dalej i użyłem _mm256_fmadd_ps, a teraz AVX2 + FMA wersja jest szybsza. nie jestem pewien, dlaczego kompilator nie zrobi tego za mnie.[[17]} otrzymuję teraz około 80 GFLOPS (110% szczytowych flopów bez FMA) dla ponad matryc 1000x1000. W przypadku, gdy ktoś nie ufa mój szczyt flop obliczenia tutaj jest to, co zrobiłem.

peak flops (no FMA) = frequency * simd_width * ILP * cores
                    = 2.3GHZ    * 8          * 2   * 2     =  73.2 GFLOPS
peak flops (with FMA) = 2 * peak flops (no FMA)            = 146.2 GFLOPS

Mój procesor w trybie turbo podczas korzystania z obu rdzeni wynosi 2,3 GHz. Ja dostaję 2 za ILP bo Ivy Bridge potrafi robić jedno mnożenie AVX i jedno dodawanie AVX w tym samym czasie (a ja kilka razy rozwijałem pętlę aby zapewnić to).

Mam tylko około 55% szczytowych flopów (z FMA). Nie wiem dlaczego, ale przynajmniej teraz coś widzę.

Jednym z efektów ubocznych jest to, że teraz dostaję mały błąd, gdy porównuję do prostego algorytmu mnożenia macierzy, któremu ufam. Myślę, że wynika to z faktu, że FMA ma tylko jeden tryb zaokrąglania zamiast tego, co normalnie byłoby dwa (co ironicznie łamie reguły zmiennoprzecinkowe IEEE, mimo że prawdopodobnie lepiej).

Edit:

Ktoś musi przerobić Jak osiągnąć teoretyczne maksimum 4 flopów na cykl? ale zrób 8 podwójnych flopów zmiennoprzecinkowych na cykl z Haswellem.

Edit

Mysticial zaktualizował swój projekt, aby wspierać FMA3 (zobacz jego odpowiedź w linku powyżej). Uruchomiłem jego kod w Windows8 z MSVC2012 (ponieważ wersja Linuksa nie skompilowała się z obsługą FMA). Oto wyniki.
Testing AVX Mul + Add:
Seconds = 22.7417
FP Ops  = 768000000000
FLOPs   = 3.37705e+010
sum = 17.8122

Testing FMA3 FMA:
Seconds = 22.1389
FP Ops  = 1536000000000
FLOPs   = 6.938e+010
sum = 333.309

To 69.38 GFLOPS dla FMA3 dla podwójnego zmiennoprzecinkowego. Dla pojedynczego zmiennoprzecinkowego muszę go podwoić, więc jest to 138.76 SP GFLOPS. Obliczam, że mój szczyt to 146.2 SP GFLOPS. To 95% szczytu! innymi słowy, powinienem być w stanie poprawić mój kod GEMM całkiem sporo (chociaż jest już trochę szybszy niż Eigen).

Author: Community, 2014-01-08

2 answers

Odpowiadam tylko na bardzo małą część pytania. Jeśli napiszesz _mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0), gcc-4.9 obsługuje go prawie jak wbudowany asm i nie optymalizuje go zbytnio. Jeśli zastąpisz ją areg0*breg0+tmp0, składnią obsługiwaną zarówno przez gcc, jak i clang, gcc rozpocznie optymalizację i może używać FMA, jeśli jest dostępna. I poprawiłem, że dla gcc-5, _mm256_add_ps jest teraz zaimplementowana jako funkcja wbudowana, która po prostu używa +, więc kod z wewnętrznymi elementami może być również zoptymalizowany.

 7
Author: Marc Glisse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-26 09:37:05

Następujące opcje kompilatora są wystarczające, aby zawrzeć _mm256_add_ps(_mm256_mul_ps(a, b), c) pojedynczą instrukcję fma (np. vfmadd213ps):

GCC 5.3:   -O2 -mavx2 -mfma
Clang 3.7: -O1 -mavx2 -mfma -ffp-contract=fast
ICC 13:    -O1 -march=core-avx2

Próbowałem /O2 /arch:AVX2 /fp:fast z MSVC, ale nadal nie kontraktuje (niespodzianka niespodzianka). MSVC zleci operacje skalarne .

GCC zaczęło to robić od co najmniej GCC 5.1.

 3
Author: Z boson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:33