Оптимизация Fortran с использованием Blas или нет

У меня есть следующий код Fortran

DO ir = 1, N
     cfac = exp( ci*B ) / dble( degen(ir) )
     C(:,:) = C(:,:) + cfac*D(:,:, ir )
ENDDO

Этот цикл занимает 14.00 с gcc -02.

Я хотел бы оптимизировать его. Я попытался использовать процедуру BLAS, которая выполняет умножение матрицы на вектор:

DO ir = 1, N
   cfac(ir) = exp( ci*B ) / dble( degen(ir) )
ENDDO

DO j = 1, M
  CALL zgemv ('n', M, N, cone, D(j,:,:), M,cfac(:),1,czero, C(j,:), 1 )
ENDDO

Оказывается, я получаю тот же результат, но за ... 17,67 с.

Почему это медленнее и как я могу улучшить код (без изменения опции компилятора)?

Спасибо,

Самуэль


person sponce    schedule 01.10.2015    source источник
comment
Насколько велики N и M? вполне возможно, что эти подпрограммы BLAS просто не могут вам помочь, и вы просто добавляете накладные расходы. Какую реализацию BLAS вы пробовали? Компиляторы хороши для оптимизации самих циклов, я нигде не использую GEMV.   -  person Vladimir F    schedule 01.10.2015
comment
Вы также, вероятно, копируете/копируете, когда вызываете zgemv, поскольку элементы, к которым вы хотите получить доступ в C и D, не являются смежными в памяти. В частности, копия D, вероятно, убьет вашу производительность. О, и это подпрограммы BLAS - этот вопрос не имеет ничего общего с ScaLAPACK, который, хотя и связан, сильно отличается от BLAS.   -  person Ian Bush    schedule 01.10.2015
comment
Спасибо Ян! Я изменил название на Блас. Как вы думаете, можно ли улучшить производительность, изменив код (используя или не используя Blas)? Обычно N большое, а M не очень. Я засекал две петли. Первый - 4 секунды, а второй - 13,67 секунды, в результате чего получается 17,67 секунды.   -  person sponce    schedule 01.10.2015
comment
Я так не думаю. Но вы так и не ответили, каковы значения N и M. Было бы полезно увидеть вывод -fdump-tree-optimized, если вы используете gfortran. Кроме того, попробуйте -fopt-info узнать, какую оптимизацию (например, векторизацию) выполняет компилятор. Вы можете попробовать -O2, который разворачивает цикл по-другому, это может помочь, но также и навредить. В целом, я довольно скептически отношусь к тому, что если компилятор уже векторизует его, то не будет много возможностей для улучшения.   -  person Vladimir F    schedule 01.10.2015
comment
Кроме того, не рекомендуется использовать C(:,:), так как это может запутать оптимизатора, см. software.intel.com/en-us/blogs/2008/03/31/   -  person Vladimir F    schedule 01.10.2015
comment
Привет, Владимир, Тусклый цвет N и M меняется в зависимости от проблемы, но N обычно составляет около 1000+, а M около 50. Я пытался поставить C (1: M, 1: M), но это не помогает.   -  person sponce    schedule 01.10.2015
comment
@sponce Я полагаю, что предложение состояло в том, чтобы использовать только C и отбросить (:,:), который указывает раздел массива (весь массив в вашем случае). (См. сообщение в блоге.)   -  person Raul Laasner    schedule 01.10.2015
comment
@VladimirF: IDK о фортране, но для C -funroll-loops не является частью -O2 или -O3 gcc. Это часть -fprofile-use. Автовекторизация обычно происходит только в -O3. Так что для OP -O3 -march=native -mtune=native -funroll-loops может быть хорошим выбором. (Пропустите -ffast-math / -Ofast, если вам нужно, чтобы округление происходило в порядке исходного кода и/или для обработки бесконечности и NaN так, как это сделал бы источник.)   -  person Peter Cordes    schedule 02.10.2015
comment
@PeterCordes Вы правы, я перепутал несколько разных аспектов. Здесь предлагают ограничить развертывание --param max-unroll-times=2 или 4 groups.google.com/d/msg/comp.lang.fortran/dcGPDgo1-w0/   -  person Vladimir F    schedule 02.10.2015
comment
@VladimirF: для циклов с переносимой циклом зависимостью (например, найти максимальное значение в массиве, скалярное произведение или сумму массива) полезно использовать несколько аккумуляторов в исходном коде с некоторым развертыванием исходного уровня. Это скрывает задержку операций FP за счет наличия 4 независимых операций в полете. (После цикла сложите четыре аккумулятора вместе.) К сожалению, при развертывании компилятора не используются несколько аккумуляторов (помимо ширины вектора при автовекторизации: т. е. в цикле суммирования массивов будет только один векторный аккумулятор)). IDK, если какие-либо компиляторы используют несколько аккумуляторов.   -  person Peter Cordes    schedule 02.10.2015


Ответы (1)


Способ улучшить его следующий

DO ir = 1, N
     cfac = exp( ci*B ) / dble( degen(ir) )
     CALL zaxpy(M**2,cfac, D(1,1, ir ),1, C (1,1),1)
ENDDO

С этим я иду примерно с 15s до 13s.

person sponce    schedule 01.10.2015