【问题标题】:How can I ensure that my Fortran FORALL construct is being parallelized?如何确保我的 Fortran FORALL 构造被并行化?
【发布时间】:2011-04-08 13:15:55
【问题描述】:

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

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

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

对我来说,现在是调用 Fortran FORALL 构造并探索并行化乐趣的好时机。

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

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

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

更新

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

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

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

【问题讨论】:

  • 通常“向量化”和“并行化”用于不同的优化。矢量化适用于诸如 SSE 到 SSE4 SIMD Intel 指令之类的指令,这些指令可以在单个处理器上并行执行少量操作。并行化导致在多个处理器或内核上运行的多线程代码,从两个到多个。对于自动向量化或并行化,编译器检查的代码有很多限制。使用 OpenMP,程序员必须确保不违反限制。

标签: parallel-processing fortran forall


【解决方案1】:

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

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

使用某些编译器,您可以通过将 FORALL 包含在 OpenMP“workshare”指令中并使用启用 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 编译器就是这种情况。

【讨论】:

  • 嗯。我从未考虑过 RHS 的复杂性会影响并行化的可能性。那么,您的观点非常清楚,为什么编译器可能会强调优化 FORALL 循环。
【解决方案2】:

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

FORALL loop at line X in file Y has been vectorized

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

【讨论】:

  • 我必须亲自动手才能看到确切的信息是什么,但这种冗长正是我想要的!即使对于自动矢量化的情况,我也想知道哪些外观正在并行化,哪些没有,特别是对于我认为应该可以并行化的情况。
【解决方案3】:

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

传说是 FORALL 并不像引入语言时所认为的那么有用——它更多的是一种初始化结构。编译器同样擅长优化常规循环。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多