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

Имам следния код на Fortran

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

Този цикъл отнема 14.00s с 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 s.

Защо е по-бавен и как мога да подобря кода (без да променям опцията на компилатора)?

Благодаря ти,

Самуил


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. Мислите ли, че е възможно да се подобри производителността чрез модифициране на кода (използвайки или не 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 относно fortran, но за 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