6

我得到了一个代表金属板表面温度点的二维矩阵。矩阵(板)的边缘保持恒定在 20 摄氏度,并且在一个预定义的点有一个 100 摄氏度的恒定热源。所有其他网格点最初设置为 50 摄氏度。

我的目标是获取所有内部网格点并通过对周围四个网格点(i+1、i-1、j+1、j-1)进行迭代平均来计算其稳态温度,直到我达到收敛(变化迭代之间小于 0.02 摄氏度)。

据我所知,我遍历网格点的顺序无关紧要。

对我来说,这听起来是调用 FortranFORALL结构并探索并行化乐趣的好时机。

如何确保代码确实被并行化了?

例如,我可以在我的单核 PowerBook G4 上编译它,我预计并行化不会提高速度。但是如果我在双核 AMD Opteron 上编译,我会假设 FORALL 结构可以被利用。

或者,有没有办法衡量程序的有效并行化?

更新

针对 MSB 的问题,这是 gfortran 版本 4.4.0。gfortran 是否支持自动多线程?

值得注意的是,FORALL 结构已经过时了,我想,然后是自动矢量化。

也许这对于一个单独的问题是最好的,但是自动矢量化是如何工作的?编译器是否能够检测到循环中只使用了纯函数或子例程?

4

3 回答 3

7

FORALL 是一个赋值结构,而不是一个循环结构。FORALL 的语义表明,在 FORALL 中每个赋值的右侧 (RHS) 表达式在分配给左侧 (LHS) 之前已被完全评估。无论 RHS 上的操作多么复杂,包括 RHS 和 LHS 重叠的情况,都必须这样做。

大多数编译器都在优化 FORALL,这既是因为它难以优化,又因为它不常用。最简单的实现是简单地为 RHS 分配一个临时值,计算表达式并将其存储在临时值中,然后将结果复制到 LHS 中。这个临时的分配和解除分配可能会使你的代码运行得非常缓慢。编译器很难自动确定何时可以在没有临时值的情况下评估 RHS;大多数编译器不会尝试这样做。嵌套的 DO 循环更容易分析和优化。

使用某些编译器,您可以通过使用 OpenMP“workshare”指令封闭 FORALL 并使用启用 OpenMP 所需的任何标志进行编译来并行化 RHS 的评估,如下所示:

!$omp parallel workshare
FORALL (i=,j=,...)
    <assignment>
END FORALL
!$omp end parallel

gfortran -fopenmp blah.f90 -o blah

请注意,并行评估 RHS 不需要兼容的 OpenMP 实现(至少包括旧版本的 gfortran);实现评估 RHS 是可以接受的,就好像它包含在 OpenMP“单一”指令中一样。另请注意,“工作共享”可能不会消除 RHS 分配的临时资源。例如,Mac OS X 上旧版本的 IBM Fortran 编译器就是这种情况。

于 2010-09-21T19:40:12.480 回答
6

如果您使用英特尔 Fortran 编译器,则可以使用命令行开关打开/增加编译器的并行化/矢量化详细级别。这样,在编译/链接期间,您将看到如下内容:

FORALL loop at line X in file Y has been vectorized

我承认距离我上次使用它已经有几年了,所以编译器消息实际上可能看起来非常不同,但这是基本思想。

于 2010-09-20T04:22:11.817 回答
3

最好的方法是测量计算的时钟时间。尝试使用和不使用并行代码。如果时钟时间减少,那么您的并行代码正在工作。在代码块之前和之后调用的 Fortran 内部 system_clock 将为您提供时钟时间。内在的 cpu_time 将为您提供 cpu 时间,当代码在多线程中运行时由于开销可能会增加。

传说是 FORALL 并不像引入语言时想象的那么有用——它更像是一个初始化构造。编译器同样擅长优化常规循环。

Fortran 编译器实现真正的并行处理的能力各不相同,而无需明确指定,例如,使用 OpenMP 或 MPI。你用的是什么编译器?

为了获得自动多线程,我使用了 ifort。手动,我使用过 OpenMP。使用这两种方法,您可以在有和没有并行化的情况下编译程序并测量差异。

于 2010-09-05T23:10:02.503 回答