可以在这些 fortran 循环上使用 OpenMP 吗?

问题描述 投票:0回答:1

这是我的问题:我有一个带有一定数量嵌套循环的 Fortran 代码,我想知道是否可以使用 OpenMP 来并行化它们?

这是 fortran 代码:

  ia = 0
  do i=1,nO
    do a=nO+1,N
      ia = ia + 1

      jb = 0
      do j=1,nO
        do b=nO+1,N
          jb = jb + 1

          chi = 0d0
          do kc=1,nS
            eps = B(kc)**2 + eta**2
            chi = chi + A(i,j,kc)*A(a,b,kc)*B(kc)/eps
          enddo

          C(ia,jb) = C(ia,jb) + D(i,b,j,a) - 4d0*chi

        enddo
      enddo
    enddo
  enddo

其中 nS = nO*(N-nO)。对于数组的维度:B(nS), A(N,N,nS), C(nS,nS), D(N,N,N,N) 。不同整数的示例:nO=88、N=240、nS=13376。也许值得一提的是,我在我实验室的集群上运行它,而不是我的笔记本电脑。

我对 OpenMP 一无所知,我尝试用我找到的例子自己做,但我没有成功。我已经看到许多不同的 OpenMP 命令,如

PRIVATE
SHARED
REDUCTION
,我尝试使用它们但没有成功。

fortran openmp nested-loops do-loops
1个回答
0
投票

是的,应该可以。但稍微重写一下代码也会很好。请注意,您始终可以根据

ia
i
的已知值计算
a
的值。不需要做
ia = ia + 1
加法。同样,您始终可以从
jb
j
计算出
b

  ia = 0
  do i=1,nO
    do a=nO+1,N
      ia = a + (i-1)*(N-n0)

      do j=1,nO
        do b=nO+1,N        
          jb = b + (j-1)*(N-n0)

          chi = 0d0
          do kc=1,nS
            eps = B(kc)**2 + eta**2
            chi = chi + A(i,j,kc)*A(a,b,kc)*B(kc)/eps
          enddo

          C(ia,jb) = C(ia,jb) + D(i,b,j,a) - 4d0*chi

        enddo
      enddo
    enddo
  enddo

正如 Ian Bush 在评论中提醒我的那样,内存访问模式很糟糕。在 Fortran 中,数组元素存储的内存顺序是列优先的。这意味着第一个索引应该在最内层循环中,最后一个索引应该在最外层循环中以获得最佳效率。这可以通过声明你的数组转置或通过重构循环嵌套来实现——这可能并不总是可能的。


之后就可以应用OpenMP了

我将从一个简单的开始:

!$omp parallel do default(private) shared(A,B,C,D)

稍后,如果它运行正确,您尝试不同的

schedule
以找出更快的方法,并可能还尝试
collapse(2)
.

© www.soinside.com 2019 - 2024. All rights reserved.