我有一个可能很简单的问题,但是看着我,我找不到任何提出相同问题的问题。我的问题是:下面的OpenMP代码中的collapse
子句是否会正确处理内部循环?或者只会在第一个内部循环中崩溃?
!$omp parallel do collapse(2) private(iy, ix, iz)
do iy = 1, ny
do ix = 1, nx
! stuff
enddo
do iz = 1, nz
! different stuff
enddo
enddo
!$omp end parallel do
这段代码为我编译,显然显示了并行化的好处。但是,我知道标准说:
与循环结构相关的所有循环必须完全嵌套;也就是说,任何两个循环之间都不得有干预代码或任何OpenMP指令。
所以我的直觉反应是OpenMP只折叠了第一个内部循环(ix
)。但那么它如何处理第二个内循环(iz
)?
我显然正在尝试代码执行以下操作,但以这种方式编写代码更加丑陋和冗长:
!$omp parallel private(iy, ix, iz)
!$omp do collapse(2)
do iy = 1, ny
do ix = 1, nx
! stuff
enddo
enddo
!$omp end do nowait
!$omp do collapse(2)
do iy = 1, ny
do iz = 1, nz
! different stuff
enddo
enddo
!$omp end do nowait
!$omp end parallel do
答案 0 :(得分:4)
第一个内部循环是介于外部循环和第二个内部循环之间的代码(据我所知)。如果nz
≠nx
,则您没有矩形循环。在任何情况下,程序语义都是第一个内循环必须在第二个内循环开始之前完成;它可能执行第二个循环使用的中间计算。 OpenMP 的给定实现可能会执行您想要的操作 - 我没有尝试过这样做。
请注意,第二个示例更改了程序的语义:执行所有ix
循环,然后执行所有iz
循环,而不是每个ix
循环后跟每个iz
循环1}}循环使用相同的iy
值。如果您可以并行化ix
循环,那么这应该是安全的,因为如果ix
计算都不依赖于任何iz
计算,那么您只能这样做,但如果iz
循环将重用相同的数据。因此,正确的语义将取决于在给定循环可以运行之前需要发生什么。 iz
循环是否需要ix
循环首先运行iy
的相同值?如果没有,您可以使用嵌套并行性。
关于循环折叠的注意事项:循环折叠通常意味着您采用嵌套的循环对,例如,
for (i=0;i<100;++i)
for (j=0;j<50;++j)
将它们变成一个循环,如:
for (ij=0;ij<5000;++ij)
如果您有两个不同索引的内部循环,则无法执行此操作,此外,编译器无法自动更改建议的执行顺序,因为这会更改程序语义。我不确定每个OpenMP实现对这段代码的作用,但我很确定它不会像你希望的那样工作。