这是我的问题:我有一个带有一定数量嵌套循环的 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
,我尝试使用它们但没有成功。
是的,应该可以。但稍微重写一下代码也会很好。请注意,您始终可以根据
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)
.