HPF:轻松进行 Linux 集群编程

作者:Mike Delves

许多程序员在开发应用程序软件时选择 Linux 作为他们的首选操作系统。越来越多的人在开发应用程序的同一台 PC 上运行它。但是,如果应用程序变得太大或运行时间太长,他们该怎么办呢?

显而易见的答案是在 PC 集群上运行它,这些 PC 集群可能通过以太网连接。要做到这一点,您需要为每个处理器编写代码。原则上,每个处理器的代码都不同,但通常除了选定的一个或两个处理器之外,所有处理器都有通用代码。代码必须包括根据需要从处理器到处理器的数据传递。这种类型的编码使用“消息传递范式”,在多处理器大型机和工作站集群上很常见。存在标准的消息传递库 PVM(并行虚拟机)和 MPI(消息传递接口)以确保可移植性。

编写消息传递代码比编写串行代码要困难得多,而且很容易说明原因。大多数科学和工程编程都大量使用一维和二维数组,因此我们这样添加两个向量

DO I = 1,10000
a(i) = b(i) + c(i)
END DO

这显然是一个并行操作:bc 的所有元素都可以并行添加。为了在 PC 或工作站集群,或任何分布式内存并行系统上发生这种情况,bc 以及很可能 a 的元素必须分布在可用的处理器上。程序员必须在他的代码中安排这一点,方法是处理每个处理器上每个向量的位,并跟踪这些位。

更好的解决方案是让编译器为您完成安排。这样,您的代码仍然可以引用完整的向量或矩阵对象,从而更容易编写、理解和维护。

编译器辅助并行编程的优势已被广泛接受。在科学/工程界,这些优势促成了名为 HPF(高性能 FORTRAN)的标准并行语言以及适用于越来越广泛的体系结构的 HPF 编译器的开发。

出于充分的理由,HPF 特意基于最新、大幅升级的 FORTRAN 版本:FORTRAN95。从 FORTRAN90 开始,FORTRAN 包含丰富的数组工具,因此上面的循环变成了一行

a = b + c

这对于编译器和人类来说都更容易理解。

编译器确实难以决定如何最好地将数组分布到处理器上;因此,HPF 为程序员提供了一种提供帮助的方法。有了这种帮助,编译器就可以从单个 FORTRAN77/90/95 源代码完全自动化数据并行程序的生成。

HPF 代码可以在 SIMD、MIMD 共享内存和 MIMD 分布式内存体系结构之间移植。特别是,您可以在 Linux PC 集群上使用 HPF。

语言的风格

这是一个虚构的例子,用于演示 HPF 提供的功能

       REAL a(1000), b(1000), c(1000), &
        x(500),y(0:501)
!HPF$ PROCESSORS procs(10)
!HPF$ DISTRIBUTE(BLOCK) ONTO procs :: a, b
!HPF$ DISTRIBUTE(CYCLIC) ONTO procs :: c
!HPF$ ALIGN x(i) WITH y(i+1)
...
       a(:) = b(:)              ! Statement 1
       x(1:500) = y(2:501)      ! Statement 2
       a(:) = c(:)              ! Statement 3
...

!HPF 开头的行是 HPF 指令;其余的是标准 FORTRAN90,执行三个数组操作。这些指令在做什么?

PROCESSORS 指令指定了 10 个虚拟处理器的线性排列,这些虚拟处理器以语言未指定的方式映射到可用的物理处理器。您可能期望至少需要十个物理处理器,但大多数 HPF 编译器都可以在一个或多个(最多十个)物理处理器上愉快地运行代码。可以定义多达七个维度的处理器网格。它们应该以某种方式与正在解决的问题相匹配——也许通过帮助最小化通信成本。处理器指令是可选的;要使用的处理器数量可以在运行时指定。

DISTRIBUTE 指令告诉(实际上,建议)编译器如何分布数组的元素。数组 ab 以每个处理器 100 个连续元素的块分布,而 c 的分布方式是,例如,c(1)、c(11)、c(21)、... 在处理器 procs(1) 上,依此类推。

请注意,数组 xy 的分布未明确指定,而它们彼此对齐的方式已指定。ALIGN 语句导致 x(i) 和 y(i+1) 存储在同一处理器上,对于 i 的所有值都是如此,而与实际分布无关。

HPF 指令如何工作

在语句 1 中,ab 的相同分布确保对于所有 i,a(i) 和 b(i) 都在同一处理器上;因此,编译器不会生成任何消息传递。

在语句 2 中,再次不需要消息传递。如果 ALIGN 语句将 x(i) 与 y(i) 而不是 y(i+1) 对齐,则对于 i 的某些值,将需要通信。

语句 3 看起来很像语句 1;但是由于 ac 的分布不同,通信要求非常不同。数组元素 a(i) 和 c(i) 仅对于 10 个可能的 i 值在同一处理器上,因此对于几乎所有元素;需要在处理器之间进行数据通信。如果此语句代表了大部分工作,那么对于 c 来说,这是一个不明智的分布选择。

良好地选择分布和对齐可以大大提高效率,这就是拥有指令的意义所在。编写 FORTRAN90 代码并用 HPF 指令修饰它比编写等效的消息传递代码容易得多。

第二个例子

实际上,编写 HPF 程序的步骤是

  1. 编写 FORTRAN90 代码。您现有的 FORTRAN77 代码也可以勉强使用,但是通过使用更新的 FORTRAN 高级结构清理它,您将获得更好的效率;存在工具来帮助这种转换。

  2. 决定如何配置处理器。

  3. 声明一个或多个模板,作为分布数组的指南。

  4. 决定如何将数组分布和对齐到模板上。

代码清单 1 中所示的代码说明了此过程,该代码表示用于求解线性方程组的子例程。该子例程采用标准 FORTRAN90 编写,可以通过任何 FORTRAN90 编译器愉快地运行,这些编译器会将 HPF 指令视为注释。该代码充分利用了 FORTRAN90 数组工具,并且仅通过添加四个 HPF 指令进行了并行化。只要要解决的问题的大小足够大,值得使用并行性,则生成的 HPF 代码就可以在 Linux PC 集群上良好运行。

它真的有效吗?

HPF 通过将几乎所有事情都留给编译器来简化程序员的生活。那么,编译器能应付吗?您真的可以通过使用 HPF 获得并行效率吗?而且,您可以在具有相对高延迟通信的网络 PC 上获得有用的加速吗?

当然,没有编译器可以在不存在并行性的地方找到并行性;您需要在开始时就赋予它并行性。鉴于此,那么答案是肯定的,当前的 HPF 编译器非常高效。在使用 PVM 或 MPI 的以太网连接的 PC 集群上,消息传递延迟通常约为 0.6 毫秒;这转化为“如果可以,请使用相当粗粒度的并行性,并且不要期望使用太多的 PC。”

表 1 显示了一些计时结果,以说明可以实现的目标。它们是在具有 100Mb 以太网的四 PC Linux P100 集群上进行的。“串行”时间是使用 N. A. Software (NASL) FORTRANPlus F90 编译器版本 1.3.57 给出的时间。当代码使用 FORTRAN90 不支持的 HPF 扩展(FORALLEXTRINSIC(HPFSERIAL))时,这些时间不存在(对于某些扩展,我们计时了等效的 FORTRAN90 版本)。HPF 时间使用了 NASL HPFPlus 编译器版本 2.0。FORTRAN 和 HPF 的优化都设置为“开启”。时间单位为秒。

通过比较串行时间和 P = 1 时间,可以显示使用 HPF 而不是 FORTRAN 的固有开销。这些开销非常低——通常可以忽略不计,并且对于 Gauss 来说,甚至是负数(我们在其他平台上也看到了这一点)。通过比较串行时间和 P = 4 时间,可以显示使用 HPF 的增益。相对于串行时间实现的加速范围为 2.1 到 4.5。

资源

Mike Delves (delves@nasoftware.co.uk) 在利物浦大学担任计算数学教授和高级科学计算研究所所长二十五年。他的研究兴趣包括数值方法及其在高级语言(依次为 Algol68、Ada、FORTRAN90 和 HPF——并行性沿途逐渐增加)中的实现。他于 1978 年以爱好开始创办 N.A. Software 公司,现在担任全职董事长;该公司目前有 23 名员工。Linux 是其 FORTRAN 和 HPF 编译器的最大单一市场。

加载 Disqus 评论