OPENMP F90 / 95 Вложенные циклы DO - проблемы с улучшением по сравнению с последовательной реализацией - PullRequest
3 голосов
/ 07 июня 2011

Я провел некоторый поиск, но не смог найти ничего, что могло бы быть связано с моим вопросом (извините, если мой вопрос излишний!).В любом случае, как говорится в заголовке, у меня возникают проблемы с улучшением последовательной реализации моего кода.Фрагмент кода, который мне нужно распараллелить, выглядит следующим образом (это Fortran90 с OpenMP):

do n=1,lm     
  do m=1,jm   
    do l=1,im      
      sum_u = 0
      sum_v = 0
      sum_t = 0
      do k=1,lm
       !$omp parallel do reduction (+:sum_u,sum_v,sum_t) 
        do j=1,jm  
          do i=1,im
            exp_smoother=exp(-(abs(i-l)/hzscl)-(abs(j-m)/hzscl)-(abs(k-n)/vscl))
            sum_u = sum_u + u_p(i,j,k) * exp_smoother
            sum_v = sum_v + v_p(i,j,k) * exp_smoother
            sum_t = sum_t + t_p(i,j,k) * exp_smoother

            sum_u_pert(l,m,n) = sum_u
            sum_v_pert(l,m,n) = sum_v
            sum_t_pert(l,m,n) = sum_t          

            end do
          end do
       end do      
    end do
  end do  
end do

Я сталкиваюсь с проблемами состояния гонки?Или я просто помещаю директиву не в том месте?Я довольно новичок в этом, поэтому я извиняюсь, если это слишком упрощенная проблема.

В любом случае, без распараллеливания, код мучительно медленный.Чтобы дать представление о размере проблемы, индексы lm, jm и im равны 60, 401 и 501 соответственно.Так что распараллеливание имеет решающее значение.Любая помощь или ссылки на полезные ресурсы будут очень благодарны!Я использую xlf для компиляции приведенного выше кода, если это вообще полезно.

Спасибо!-Jen

Ответы [ 2 ]

3 голосов
/ 07 июня 2011

Очевидное место для установки прагмы omp - в самом внешнем цикле.

Для каждого (l, m, n) вы вычисляете свертку между возмущенными переменными и экспоненциальным сглаживателем.Каждое вычисление (l, m, n) совершенно не зависит от других, поэтому вы можете поместить его в самый внешний цикл.Так, например, самая простая вещь

!$omp parallel do private(n,m,l,i,j,k,exp_smoother) shared(sum_u_pert,sum_v_pert,sum_t_pert,u_p,v_p,t_p), default(none)
do n=1,lm
  do m=1,jm
    do l=1,im
      do k=1,lm
        do j=1,jm
          do i=1,im
            exp_smoother=exp(-(abs(i-l)/hzscl)-(abs(j-m)/hzscl)-(abs(k-n)/vscl))
            sum_u_pert(l,m,n) = sum_u_pert(l,m,n) + u_p(i,j,k) * exp_smoother
            sum_v_pert(l,m,n) = sum_v_pert(l,m,n) + v_p(i,j,k) * exp_smoother
            sum_t_pert(l,m,n) = sum_t_pert(l,m,n) + t_p(i,j,k) * exp_smoother
          end do
        end do
      end do
    end do
  end do
end do

дает мне ~ 6-кратное ускорение на 8 ядрах (при использовании значительно уменьшенного размера задачи 20x41x41).Учитывая объем работы, которую необходимо выполнить в циклах, даже при меньшем размере, я предполагаю, что причина не в том, что ускорение в 8 раз связано с нехваткой памяти или ошибочным совместным использованием;для дальнейшей настройки производительности вы можете явно разбить массивы сумм на подблоки для каждого потока и объединить их в конце;но в зависимости от размера задачи наличие дополнительного массива im x jm x lm может быть нежелательным.

Похоже, что в этой задаче есть много структур, которые вы могли бы изучитьускорить даже серийный случай, но легче сказать это, чем найти его;играя с ручкой и бумагой, через несколько минут ничего не приходит в голову, но кто-то умнее может что-то заметить.

2 голосов
/ 07 июня 2011

То, что у вас есть, это свертка.Это можно сделать с помощью быстрого преобразования Фурье за ​​N log2 (N) времени.Ваш алгоритм N ^ 2.Если вы используете FFT, одного ядра, вероятно, будет достаточно!

...