Будут ли компиляторы gfortran или ifort разумно использовать инструкции SIMD при суммировании произведения двух массивов?
-
22-12-2019 - |
Вопрос
У меня есть код, написанный с помощью numpy, и я подумываю о его портировании на Фортран для повышения производительности.
Одна операция, которую я делаю несколько раз, — это суммирование поэлементного произведения двух массивов:
sum(A*B)
Похоже, в этом помогут объединенные инструкции умножения-сложения.Мой нынешний процессор не поддерживает эти инструкции, поэтому я пока не могу что-то протестировать.Однако я могу перейти на новый процессор, поддерживающий FMA3 (процессор Intel Haswell).
Кто-нибудь знает, будет ли достаточно компиляции программы с "-march=native" (или эквивалентом ifort), чтобы компилятор (gfortran или ifort) разумно использовал инструкции SIMD для оптимизации этого кода, или вы думаете, что я это сделаю? придется возиться с компиляторами или кодом?
Решение 3
Благодаря совету Сяолея Чжу я теперь знаю, что gfortran будет использовать объединенное умножение-сложение для оптимизации. sum(A*B)
.Например, с помощью этого кода:
Программный тест неявный
реальный, размерность(7) ::а, б
а = (/2,0, 3,0, 5,0, 7,0, 11,0, 13,0, 17,0/)
б = (/4,0, 6,0, 8,0, 10,0, 12,0, 14,0, 16,0/)
напечатать *, сумма(а*б)
конечная программа
Я могу скомпилировать его с помощью f95 sum.f95 -o sum -O3 -march=core-avx2
, и objdump -d sum | grep vfmadd
дисплеи
40088б:c4 e2 71 99 44 24 30 vfmadd132ss 0x30(%rsp),%xmm1,%xmm0
400892:c4 e2 69 b9 44 24 34 vfmadd231ss 0x34(%rsp),%xmm2,%xmm0
400899:c4 e2 61 b9 44 24 38 vfmadd231ss 0x38(%rsp),%xmm3,%xmm0
4008а0:c4 e2 59 b9 44 24 3c vfmadd231ss 0x3c(%rsp),%xmm4,%xmm0
4008a7:c4 e2 51 b9 44 24 40 vfmadd231ss 0x40(%rsp),%xmm5,%xmm0
4008ае:c4 e2 49 b9 44 24 44 vfmadd231ss 0x44(%rsp),%xmm6,%xmm0
4008b5:c4 e2 41 b9 44 24 48 vfmadd231ss 0x48(%rsp),%xmm7,%xmm0
Итак, gfortran развернул цикл и вставил 7 объединенных инструкций умножения-сложения.Если я создаю более крупные, случайные, многомерные массивы, я все равно вижу всплывающее окно vfmadd231ss один раз (поэтому он не разворачивает цикл).
Другие советы
Если вы используете -march=native
на машине с SIMD компилятор должен генерировать инструкции SIMD, хотя я всегда использовал -xHost
отметьте вместо этого ifort.
Но я не совсем уверен, как заставить их сделать это "с умом".У меня такое чувство, что в -O3
level ifort и gfortran, как правило, чрезмерно агрессивны в отношении векторизации (то есть они используют функциональность SIMD чаще, чем следовало бы).Очень часто мне приходится отключать векторизацию, чтобы получить наиболее эффективный код.Это, конечно, может быть правдой, а может и не быть правдой для вас.
Обычно лучше использовать векторные библиотеки, оптимизированные для этой задачи.Вы можете использовать vdmul
в МКЛ или gsl_vector_mul
в GSL для этого есть.
Используя -march=NEWARCH
в результате будет создан код, настроенный для новой архитектуры, но не может быть запущен на более ранней архитектуре.Вы можете использовать -mtune=NEWARCH
отметьте, где NEWARCH - это архитектура вашего нового процессора.Это сгенерирует код, настроенный для новой архитектуры, но все еще исполняемый на старой.Поскольку у вас еще нет новой машины, -mtune
вероятно, это то, что вам нужно в данный момент.
С помощью ifort вы можете использовать флаги отчета о векторизации, чтобы показать, какая часть программы была векторизована.Например, ifort
Отметить -vec-report=1
мы предоставим вам такую информацию во время компиляции.Я уверен, что в gfortran найдется эквивалентный флаг.
версии gfortran, где sum(a*b)
дал лучшую векторизацию, чем dot_product(a,b)
давно устарели.Код, который вы показываете, использует последовательные инструкции AVX2 fma.
В реализации dot_product
без косвенной индексации или других осложнений (сам по себе простой цикл) fma, вероятно, будет медленнее, чем комбинация инструкций параллельного умножения и сложения simd, поскольку умножение может быть выполнено вне критического пути задержки.gfortran использование параллельного simd fma для dot_product может быть весьма эффективным в более сложных случаях.
Вам понадобится либо -O2 -ftree-vectorize -ffast-math -march=native or -O3 -ffast-math -march=native
(а также подходящие длины векторов) для векторизации, и gfortran может не выполнить векторизацию внутри параллельной области OpenMP.
В gfortran 4.9, похоже, удалена опция -ftree-vectorizer-verbose.-fdump-tree-vect записывает детали проходов векторизации в файл .vect с разными именами, выбранными для разных основных версий gcc.