有关性能可移植性在过去的几年中已经多次出现。这究竟意味着什么?我们是什么时候头一回开始担忧性能可移植性的?为什么最近一段时期要比之前更加关注?为什么有很多对于性能可移植性话题如此的唱衰?还有没有希望?在本文中,我将会对此及更多相关问题进行解答。

性能可移植性是一个新概念吗?

否。如果你在互联网上输入精确的关键词性能可移植性,你会发现,众多条目中的多数(虽然不是全部)都和HPC有关。以下是这些年的一些亮点:

· Chapel语言之性能可移植性,于并行与分布式处理国际讨论会,2012年中国上海。

· EARTH上的性能可移植性:横跨若干并行架构的案例研究,于“性能建模、评估与优化(PMEO)研讨会”,2005年丹佛IPDPS。

· 性能可移植性与天气研究及预报模型, 于HPC亚洲,昆士兰,澳大利亚2001年。

· 光谱大气模型中的并行计算机性能, 橡树岭国家实验室技术备忘 TM-12986, 1995年,刊登在当年稍晚时出版的《大气与海洋技术杂志》,并附带附件“支持(性能)可移植性”。

所以,性能可移植性作为并行计算的一个概念和一个目标已经出现了很多年。在过去的这二十年,这些论文对于这些挑战的解决很是值得一看。1995 年的光谱模型技术备忘中描述了寻找最佳算法变体以及在Cray T3D、IBM SP2 、Intel Paragon不同数量处理器平台上的变体比值实验。2001年的WRF (天气研究与预报)论文指出“性能与可移植性很重要,但有冲突之忧。”并且提出,我们需要将“数据与循环结构如何影响性能”这一问题的“理解量化”,然后所编写的代码“在运用单一源代码并跨越多种不同平台时,可对这些方面进行灵活的调整。”

2005年的EARTH 论文有如下阐述“并行程序的性能可移植性正变得越来越重要,并应当在设计并行可执行模型、API以及运行时系统软件时给予这方面的考虑。”2012年的论文建议Chapel语言增加性能可移植性。我发现这些文章将性能可移植性的边界从应用与算法逐步扩展到了程序、语言与工具。

事实上,对于以上提到的性能可移植性的解决办法全都是需要的。在一个高度并行化的目标计算机上,一个不可缩放(unscalable)的算法是不会具有良好效能的。一个不合适的数据结构对于性能的影响几乎跟一个不合适的算法一样多。我们需要一个发挥编译器、工具和运行时这类程序的方法,来发挥出各种目标系统的特性。

那么,什么是性能可移植性?

尽管不那么显著,但一个应用或算法的性能可移植性也是跨越多种目标系统时达成高性能的手段之一。高性能是相对而言,但是我们所说的高性能是对于目标系统而言的。

一个重要的问题就是各种目标系统。二十年前,光谱模型论文关注的是跨越32到1024 个节点、三个不同类型的系统,其中每个节点只使用了一个处理器(Intel Paragon在每个节点上有两个处理器,不过第二个处理器在实验中被用来当作了信息协处理器)。有趣的是,在这些系统中只有一个使用了MPI,这在现今仍然不落伍。MPI现在是管理节点间通信的标准。虽然像Fortran 集成数组(coarrays 和 HPC++ 分布数组 这样的PGAS语言特性的使用者也正在日益增多。

现代超级计算机在每个节点上全都在使用多核处理,有时每个节点是32个,有时则更多。随着基于 Intel Knights Landing Xeon Phi (KNL) 这种每节点支持超过256个硬件线程的系统的出现,这一数字还在上升。另外,我们也给系统安装上了加速器。今天,加速器一般大多都是GPU加速器,不过,在近来,另外一种可编程加速器也已出现,比如像DSP(数字信号处理器)。在一些应用领域,FPGA (现场可编程逻辑门阵列)的使用也很成功。 然而,FPGA对于一般的HPC使用目的而言有严重的局限性,包括高昂的编程成本(包括布局和布线)、高昂的动态再配置网络、相对稀少的逻辑和低时钟频率。在本文中,我们会涉及多核心、超多核心(manycore)以及GPU加速节点,我们也会将未来其他可能的可编程加速器纳入进来,但我们不会考虑FPGA。

性能可移植性还会改进吗?

如果我们看看2015年11月超级计算机 TOP500 榜单上的前四名系统, 我们会看到四个特性鲜明的节点架构:

1. 天河-2,共16000节点,每个节点使用两个12核 Intel Ivy Bridge 处理器以及三块57核Intel Knights Corner Xeon Phi 协处理器。

2. Titan,共18688节点,每个节点使用一个16核 AMD Interlagos 处理器以及一块 NVIDIA Tesla K20X GPU 。

3.. Sequoia,共98304节点,每个节点使用一个16核 IBM PowerPC A2 处理器。

4.   计算机,共88128 节点,每个节点使用一个8核 Fujitsu SPARC VIIIfx

四个系统,处理器提供商各不相同,两个使用加速大节点(fat nodes),另两个使用超过50000个小节点(thinner nodes)。

我们看到,全球所采用的稍小型的HPC变体都相似。很多系统都是围绕着单插座多核心x86 或者 POWER处理来设计;加上GPU加速器的超多核心;大量采用Intel Knights Landing Xeon Phi 处理器。还有很多可能会影响未来设计的实验尝试。

在即将问世的能源部珊瑚(DOE CORAL)超级计算机也有相似的变体。橡树岭的这台IBM+NVIDIA+Mellanox Summit 计算机将会拥有3500 个节点,使用多个IBM OpenPOWER处理器,每个节点还有多个NVIDIA Volta GPU。然而,在阿贡(Argonne - 阿贡国家实验室,亦属于美国能源部)的Intel+Cray Aurora 计算机将拥有超过50000个节点,在每个节点都配有一块高度并行的Intel Knights Hill Xeon Phi 处理器。签订了这些系统合同的还有卓越中心(Centers of Excellence - 属于劳伦斯利物莫国家实验室), 该中心为筹备新的高度并行计算机系统的现代化已经付出了很多年的努力。想像一下,如果在一开始就不忘记将性能可移植性写入这些应用,那么在将它们转移到一个新系统、跨越多个不同系统时,将会少耗费多少精力。

性能可移植性现在变得更重要了吗?

今天,性能可移植性比过去更重要了吗?也不尽然,超级计算已经经历了数个阶段。我们这些花白头发的人仍然记得,在1970年代将程序从顺序式的 Control Data(CDC - 控制资料公司) 6600 和 7600 计算机上移植到矢量式的Cray-1计算机时所付出的种种努力。最终,在十多年之后,促成了OpenMP 规格的出现。再从共享内存转到可缩放(scalable)信息传递网络,又是一场巨大的努力,它产生的MPI更加快速(标准化一个库比标准化一个语言要更容易)。

性能可移植性现在获得关注是因为节点编程模型(再一次的)发生了改变。在过去的20年,很多程序员又回到了编写由消息传递连接的顺序式节点程序。在消息的结构和隐蔽性较好时,程序员就只会考虑顺序式节点程序了。然而,今天的计算机具有非常高的并行化的节点,而且节点上的并行化并非都能被MPI有效的挖掘出来。比如,矢量或SIMD的并行化必须通过编译器才能释放出来。所以,我们回到1975年的时候,就必须要考虑一下矢量算法。随着数据在系统内存和高带宽内存之间的传递,内存层级管理应运而生,因此我们也必须对此进行优化,在1980年代,我们优化了虚拟内存和缓存的方式。对共享内存的利用可以比传递消息有更多的效率,我们也因此必须着眼于混合并行化(hybrid parallelism),M+X (此处的M通常是指MPI),这对于很多程序员和应用来说还是一个新事物。

加速器给编程的复杂度又提高了一个级别。我们拥有这样的或者那样的加速器已经超过了40年,时间至少可以追溯到IBM 2938数组处理器和浮点系统AP-120B的那个时代。今天的加速器已变得不同,它们相对更加便宜,也可以比较容易的加入到节点设计中,可以明显的提升性能。然而,尽管有着一段较长时期的历史,但依然没有一个较为突出甚或是一个实际上的加速器编程模型。

编程模型支持性能可移植性吗?
MPI 支持或者提供性能可移植性吗?对于MPI或者是任何一种语言、模型或是类型,我都不会说可以给予或者保证有性能可移植性。使用消息传递编程,如在MPI中,在程序员被动的去组织应用时做得很好,大多数到节点的计算和大多数数据访问都是本地化的,数据通信的频率和数量都降低到了最小。在大范围的跨越多种系统时,一个设计优良的程序使用MPI更可能获得一个非常好的性能。因此,是的,对于并行化方面,MPI很好的促进了性能可移植性。

那么库文件会带来性能可移植性吗?如果你发现了一个支持良好的库文件可以用来解决你的问题,那无疑是一条可行的路。当你想去使用某个人编写的、对不同系统进行了优化的库文件时,那就等于是通过专业的库文件开发人员节省了时间和精力。这是最佳的生产效率。

OpenMP 会提供性能可移植性吗?对于多处理器和多核共享内存式的工作站、服务器和节点来说,OpenMP对性能可移植性、跨越多种操作系统、处理器架构以及对编译器提供方面的支持做得非常出色。问题是,它是否能应对当今多种多样的节点架构。最近的多份文稿都并不令人感到鼓舞。在过去的(二零一五年)九月新召开的 OpenMP会议 上有一份关于近期能源部可移植性研讨会的报告文稿。

研讨会其中的一个值得注意的信息是,据一些能源部实验室的代表说,“多数人都不得不针对各种不同的平台,使用简单的#ifdef或是其他机制来获得不同的源(码)。”我觉得这非常的失望和让人沮丧。在另一份文稿的幻灯片中表达了这样的一种观点“具有通用的代码基础,以用于可移植编程环境,即便你必须要使用 if-def来填充代码或是必须有特定的内核版本架构 … 这是支持可维护性的唯一方式。”这似乎是完全站在了性能可移植性的对立面,可移植性是不可实现、也无必要也许也是不受欢迎的。

有人说, OpenCL可以提供性能可移植性。这一点值得关注,OpenCL的设计初衷和后来一直宣称的就是提供一套“有效、近金属(close-to-the-metal)的编程界面”,并“形成并行计算生态环境的基础层级。”以上摘自OpenCL规格描述(到目前为止的所有版本)。这也似乎是完全站到了性能可移植性相反的一面。这是一种更具有性能可移植性的语言,一个让你能抵达每一个目标最底层的标准语言。看一下HPCwire 的一篇有关OpenCL的文章, 文章称“是的,我们需要编写一个我们这个内核的新版本,来获得A架构的最佳性能,但是这真的是我们想要的吗?”对于这个问题的答案,在HPC的空间内,这必然是不。

现在有大量的新模型被提了出来,来解决节点级性能可移植性问题。Chapel 是Cray HPCS (High Productivity - 高生产率)努力的成果,它是作为应对整个并行计算问题的解决方案而被提出的 ,跨越了多个节点、跨越了多个核心并跨越了多个加速器。 OpenACC 开始被用作一种用于编程加速器的指令API,但也可以被设计用来支持多核并行化,而且现在也有一些证据来证明这一点。RAJA and Kokkos 是两个C++类库文件以解决编程问题,这和下一个C++修订版在标准化并行编程方面的尝试有些相似。

我对于编译器为基础的解决方案有一种强烈的偏好,一部分原因是因为我是一个编译器人,但也是因为编译器是唯一一种可以兼顾程序和目标架构的工具。C++类库文件可以提供一种和并行循环相像的、句法相似的解决方案,不过实际上,这是一种出于性能考虑而希望获取到联机“循环”主体的方式调用。高手所编写的并行循环类并没有循环主体本身的内容,也不像内存参考模式(memory reference patterns)那样有什么可以利用的东西,但我仍然深信不疑。

性能可移植性还有希望吗?

我相信还有希望,即使实在相对短的时期内。PGI正在在OpenACC编译器方面开展工作,让它们对于加速计算方面也能和多核并行一样好。和OpenMP 4的目标附件一样,OpenACC的主要元素是数据管理和并行管理。对于加速计算来说,数据管理被用来控制或者是用来优化数据在系统内存和加速器高宽带内存之间的传递的,而并行化则是用来产生用于加速器的并行代码的。对于多核目标来说,数据管理基本都会被忽略,而并行化则被用来产生多核代码,几乎等同于OpenMP并行循环。

PGI正在研究未来对于Intel Knights Landing Xeon Phi 处理器的支持,在这里,并行化将再次产生多核代码,而数据管理将会被用于控制或是优化数据在系统(远端)内存和高宽带(近端)内存的传递。OpenMP中的数据管理结构跟OpenACC中的数据管理多多少少有些同构化,从中借鉴了一些概念。在OpenMP中的计算管理要比OpenACC中的更加严格,正如在一篇去年的文章中讨论过的那样,OpenMP是线程中心型(thread-centric)的。OpenMP中的并行循环指令不会告诉编译器循环可以安全的以并行模式运行;它会告诉编译器,必须跨越OpenMP的多个线程来进行循环迭代的扩散。

在OpenACC中,并行循环指令会声明循环不能存在数据竞争(data-race free),这样迭代才能以并行方式、在目标系统中任意、可用的并行机制上运行。这可谓是不可思议的强大,我相信这是在任意一种编程模型上实现性能可移植性的关键。程序员可以去强调并行化,并去实现它,然后进一步的挖掘它。再多的编译器分析也不会创造出程序中没有的并行化,再多的程序员的努力也无法预测出未来五年甚至更长的时间内新的计算机会是什么样子。

有一点看来会逐渐明朗,那就是未来架构会越来越并行化,而我们也必须让我们所编写的应用在某种程度上能够发掘出全部的并行化。此外,无论模型所支持的粒度(granularity)怎样,我们也都应当要求我们的程序模型要具备一条通往性能可移植性的道路。当选择或是设计一个并行编程方式时,你需要从OpenACC那里学到的一课就是要让你的模型尽量的具有描述性和说明性,以用于未来的进一步开发,那样的未来是你现在所不能想象的到的。

结论

我没有说OpenACC或是任何一种编程模型就是最终的解决办法。一个应用是一个数个算法的集合,总会有另一些算法或者数据布局的出现,某一个版本在一种系统上会跑得好一些,而另一个版本在其他系统上会好一些。这些(至少)在1995 年的技术备忘中就有所提及。很多算法都有可调参数,比如比值(aspect ratios)或是块大小(tile sizes),这时运行时的自动调整可以起到很好的效果。基于任务的运行时系统打破了惯常的批量同步编程模型(bulk-synchronous programming model),允许更多的潜伏宽容通信(latency-tolerant communication)。所有这些方法都需要探索和发掘。 

关于作者
Michael Wolfe是一位在学术界、工商界从事编译器开发超过40年的开发人员,在过去的20年中一直在从事PGI编译器方面的工作。作者在本文中声称的观点不代表NVIDIA的观点。