У меня i5-4250U с AVX2 и FMA3. Я тестирую код умножения плотных матриц в GCC 4.8.1 на Linux, который я написал. Ниже приведен список из трех разных способов компиляции.
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
Версия SSE2 и AVX явно отличается по производительности. Однако AVX2 + FMA ничем не лучше версии AVX. Я этого не понимаю. Я получаю более 80% пиковых провалов процессора при условии, что FMA нет, но я думаю, что смогу добиться большего с FMA. Умножение матриц должно напрямую извлекать выгоду из FMA. По сути, я делаю восемь точечных продуктов одновременно в AVX. Когда я проверяю march=native
, он дает:
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 ...
Итак, я вижу, что он включен (просто чтобы убедиться, что я добавил -mfma
, но это не имеет значения). ffast-math
должен позволять расслабленную модель с плавающей запятой. Как используйте инструкции Fused Multiply-Add (FMA) с SSE / AVX
Изменить:
Основываясь на комментариях Mysticial, я пошел дальше и использовал _mm256_fmadd_ps, и теперь версия AVX2 + FMA работает быстрее. Я не уверен, почему компилятор не сделает этого за меня. Сейчас я получаю около 80 GFLOPS (110% пиковых флопов без FMA) для матриц размером более 1000x1000. Если кто-то не доверяет моему расчету пикового флопа, вот что я сделал.
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
Мой процессор в турбо-режиме при использовании обоих ядер составляет 2,3 ГГц. Я получаю 2 для ILP, потому что Ivy Bridge может одновременно выполнять одно умножение AVX и одно сложение AVX (и я развернул цикл несколько раз, чтобы убедиться в этом).
Я получаю только около 55% пиковых флопов (с FMA). Я не знаю почему, но, по крайней мере, сейчас я кое-что вижу.
Одним из побочных эффектов является то, что теперь я получаю небольшую ошибку при сравнении с простым алгоритмом умножения матриц, которому я доверяю. Я думаю, это связано с тем, что FMA имеет только один режим округления вместо двух (что по иронии судьбы нарушает правила с плавающей запятой IEEE, хотя, вероятно, это лучше).
Изменить:
Кому-то нужно повторить Как мне достичь теоретического максимума в 4 FLOP за цикл? но делать 8 двойных FLOPS с плавающей запятой за цикл с Haswell.
Изменить
Собственно, Mysticial обновил свой проект для поддержки FMA3 (см. Его ответ по ссылке выше). Я запустил его код в Windows8 с MSVC2012 (потому что версия для Linux не компилировалась с поддержкой FMA). Вот результаты.
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
Это 69,38 GFLOPS для FMA3 с двойной плавающей запятой. Для одиночной плавающей запятой мне нужно удвоить ее, чтобы получить 138,76 SP GFLOPS. Я подсчитал, что мой пик составляет 146,2 SP GFLOPS. Это 95% от пика! Другими словами, я смогу немного улучшить свой код GEMM (хотя он и так уже немного быстрее, чем Eigen).
-ffast-math
), тогда ваш единственный вариант - использовать встроенные функции вручную. (или просто используйте библиотеку, которая его использует) Другими словами, компилятор может быть недостаточно умен, чтобы генерировать FMA, даже если вы укажете-mfma
и-ffast-math
. - person Mysticial   schedule 08.01.2014_mm256_fmadd_ps
, и теперь я получаю более 110% пиковых флопов (рассчитанных без FMA). Я получаю более 80 GFLOPS на моем маленьком 15-ваттном процессоре (в Intel NUC). Но я получаю небольшую ошибку при сравнении с моим базовым расчетом. Я предполагаю, что это связано с новым режимом округления FMA. Мне придется изменить то, с чем я сравниваю. Не знаю, как это сделать. С другой стороны, я не получаю почти такого большого прироста, как я ожидал (раньше я получал 80% пиковых флопов). - person Z boson   schedule 08.01.2014_mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0)
. Если я хочу, чтобы GCC выполнял fma, когда a и b являются регистрами AVX, как мне это сделать? Вы знаете об этом больше, чем я. Почему бы тебе не написать ответ? - person Z boson   schedule 08.02.2014