使用小程序应用程序增强应用程序性能:混合并行编程范式的比较
加里·劳森,迈克尔·波塔特,玛莎·索松金娜,罗伯特·鲍尔勒
摘 要
在许多领域中,高性能计算的实际应用已经被开发出来。为了使这些应用程序保持最新状态,必须探索新的并行策略以获得最佳性能;然而,根据代码的大小,重构或修改真实世界的应用程序可能是艰巨的。在这种情况下,可以使用迷你小程序来快速浏览这些选项,而无需修改整个代码。在这项工作中,已经创建了几个迷你小程序,以增强真实应用程序的性能,即NASA兰利研究中心开发的用于复杂流分析的VULCAN代码。这些迷你小程序探索了用于分布式内存访问的消息传递接口(MPI)和用于共享内存访问的共享MPI(SMPI)或OpenMP的混合并行编程范例。性能测试表明,MPI + SMPI产生最佳执行性能,同时需要最大数量的代码更改。测量MPI + SMPI的最大加速度为23,但对于MPI + OpenMP,最大加速度为10。
关键字:小应用程序,性能,VULCAN,共享内存,MPI,OpenMP
1引言
在很多领域,现实世界的应用已经被开发出来。对于建立的应用程序保持最新,必须探索新的并行策略,以确定哪一个可以产生最好的性能,尤其是随着计算硬件的进步。但是,重构或修改现实世界的应用程序会导致成本的增加,这取决于代码的大小和所做的更改。可能会创建一个迷你小程序来快速浏览这些选项,而无需修改整个代码。迷你小程序减少了应用新策略的开销,因此可以实施和比较各种策略。这项工作介绍了作者的经验,当遵循这个战略为美国航空航天局开发的现实世界的应用程序。
VULCAN(用于复杂流动分析的粘性迎风算法)是一种湍流,无平衡,有限速率的化学动力学,由结构化的,以细胞为中心的多块网格的Navier-Stokes流动求解器,由超音速空气呼吸推进分支NASA兰利研究中心(NASA 2016)。在这项工作中开发的迷你小程序使用Householder Reflector内核来求解线性方程组。这个内核经常被不同的工作负载使用,而且是决定应用于VULCAN的策略类型的一个很好的选择。 VULCAN建立在单层MPI上,代码已经过优化以获得完美的矢量化,因此目前使用两级并行。这项工作研究了两种共享内存并行机制,OpenMP和Shared MPI,它们将为应用程序提供第三级并行机制。并行性的第三级提高了性能,这减少了解决方案的时间。 MPI已经将该标准扩展到MPI 3.0版本,其中包括共享内存(SHM)模型(Mikhail B.(Intel)2015,Message Passing Interface Forum 2012),在本文中称为Shared MPI(SMPI)。该扩展允许MPI创建在同一物理节点上的MPI任务之间共享的内存窗口。这样,MPI任务就等同于线程,除了Shared MPI对程序员来说更难实现。 OpenMP是迄今为止最常用的共享内存库,因为它的易用性(OpenMP 2016)。
在大多数情况下,并行化一个循环只需要几个OpenMP编译指示;但是,OpenMP的开销会增加,如果调整不当,可能会降低性能。 早在2000年,(Cappello and Etiemble 2000)的作者发现,对于时延敏感的代码似乎从纯MPI实现中受益,而对带宽敏感的代码从混合MPI + OpenMP中受益。另外,作者还发现,如果数据移动不是压倒性的瓶颈(Cappello and Etiemble 2000),更快的处理器将使混合MPI + OpenMP代码受益。
从那时起,混合MPI + OpenMP实现已经改进,但并非没有困难。
在(Drosios和Koziris 2004,Chorley and Walker 2010)中,发现OpenMP引起了许多性能下降,包括开销(fork / join,atomics等),错误共享,消息传递不平衡以及对处理器的敏感性映射。但是,使用更多线程时可能会隐藏OpenMP开销。在(Rabenseifner,Hager和Jost 2009)中,作者发现,简单地使用OpenMP可能会导致性能损失,因为编译器避免了优化OpenMP循环 - 验证到10.1版本。尽管编译器从此以后已经有了相当的进步,但如果使用OpenMP,那么仍旧使用旧版本编译的应用程序用户可能会面临风险。在(Drosinos and Koziris 2004,Chorley and Walker 2010)中,作者发现混合MPI + OpenMP方法优于纯MPI方法,因为混合策略将多样化的路径并行执行。 最近,MPI将其标准扩展到包含SHM模型(Mikhail B.(Intel)2015)。作者(Hoefler,Dinan,Thakur,Barrett,Balaji,Gropp和Underwood,2015)介绍了MPI RMA理论和实例,这是SHM模型的基础。在(Gerstenberger,Besta和Hoefler 2013)中,作者对MPI RMA进行了全面的性能评估,包括调查了不同的内存窗口同步技术。
在(Hoefler,Dinan,Buntinas,Balaji,Barrett,Brightwell,Gropp,Kale和Thakur 2013)中,作者研究了MPI + SMPI执行的可行性,并将其与MPI + OpenMP执行进行了比较。发现OpenMP的基本限制是内存默认共享模型,由于内存模型是默认的私有模式,所以与MPI不能很好地耦合。由于这个原因,MPI + SMPI代码预计执行得更好,因为共享内存是显式的,整个代码的内存模型是默认的私有的。 最近,在Gropp,Olson和Samfass 2016中引入了一种新的MPI通信模型,它更好地捕获了多节点通信性能,并提供了一个开源的基准测试工具来捕获给定系统的模型参数。 独立于共享内存层,MPI是节点之间数据移动的事实标准,这种模式可以帮助任何MPI程序。
本文的其余部分分为以下几部分:2介绍Householder迷你小程序,3介绍所考虑的迷你小程序的性能测试结果,4总结本文。 2 Householder小程序 迷你小程序使用来自VULCAN的户主计算内核,用于求解线性方程组。 householder例程是一种算法,用于将方阵转换为三角形,而不增加每个元素的大小(Hansen 1992)。 Householder程序在数值上是稳定的,因为在计算中使用非常小的或非常大的中间值,所以它不会失去大量的精度。
2介绍Householder迷你小程序
迷你小程序旨在执行特定的功能。在这项工作中,重要特点如下: 接受通用输入,验证优化例程的数字结果,测量原始和优化例程的性能,调整优化。
通用输入是从文件中读入的,文件必须包含至少一个矩阵A和结果向量b。如果只提供一个矩阵和向量,输入将被复制到所有m的实例。优化程序的验证是通过对原始程序和优化程序的输出的差异进行的。迷你小程序将首先使用原始程序计算输入的解,然后再优化程序。这样可以直接比较输出,也可以使用执行时间来测量相对性能。
如果优化的例行程序具有一个或多个可能变化的参数,则要对其进行研究,使得可以将优化调整到硬件。在这项工作中,总是至少有一个可调参数。
本来应该考虑到迷你小程序设计的一个功能是模块化Householder例程的不同版本。在这项工作中,设计了两个迷你小程序,因为它们都实现了不同版本的并行Householder例程;但是,设计一个使用模块来包含其他版本的并行Householder内核的单个迷你应用会更好。有了这个功能,在每个版本的内核上工作起来都不那么麻烦。 为了并行化Householder例程,m被分解成单独的,但是相等的块,然后由每个线程解决 - 共享的MPI任务相当于这个工作中的线程。然而,最原始的程序在最内部的计算循环(一个有利于向量化和缓存的优化)内的m之间变化,但是为了获得最佳性能,并行循环必须是最外面的循环。因此,对代码的并行部分调用了循环阻塞。循环阻塞是一种通常用于减少计算的内存占用的技术,以使其适合于给定硬件的缓存内部。因此,并行Householder例程至少有一个可调参数,块大小。
在这项工作中,研究了两种共享内存模型:OpenMP和SMPI。 OpenMP和SMPI的区别在于如何管理内存。 OpenMP使用公共内存模型,默认情况下,所有数据都可用于所有线程。公共内存可以很容易地添加并行语句,因为线程将共享这些数据,但是线程容易受到虚假共享的影响,在这种情况下,变量本应是私有的,这些变量是无意中共享的。共享MPI使用私有内存模型,其中数据必须在线程之间显式共享,并且所有数据在默认情况下都是私有的。私有内存使得任何并行实现更复杂,因为线程必须被指示访问特定的内存进行计算。
而且,OpenMP在内部处理的执行过程中创建并销毁线程,并且性能很高。 SMPI线程在执行开始时创建,并始终保持不变。这使得管理SMPI线程更加困难,因为每个并行阶段必须由程序员明确管理。然而,程序员额外的工作可能会在性能方面得到回报,因为SMPI会带来更少的开销。
3性能评估
本节介绍MPI + OpenMP和MPI +共享MPI Householder Reflector内核优化的性能测试过程和结果。对于性能测试,改变用于计算的节点数是有意义的,因为在用真实世界的模拟执行VULCAN时经常使用许多节点。在一个多节点HPC集群上,最多有四个节点进行了调查。 MPI任务和OpenMP线程的数量以及并行部分中的环路阻塞的块大小不同。
3.1并行Householder
为了并行化Householder例程,m被分解成单独的,但是相等的块,然后由每个线程解决 - 共享的MPI任务相当于这个工作中的线程。然而,最原始的程序在最内部的计算循环(一个有利于向量化和缓存的优化)内的m之间变化,但是为了获得最佳性能,并行循环必须是最外面的循环。因此,对代码的并行部分调用了循环阻塞。循环阻塞是一种通常用于减少计算的内存占用的技术,以使其适合于给定硬件的缓存内部。因此,并行Householder例程至少有一个可调参数,块大小。
在这项工作中,研究了两种共享内存模型:OpenMP和SMPI。 OpenMP和SMPI的区别在于如何管理内存。 OpenMP使用公共内存模型,默认情况下,所有数据都可用于所有线程。公共内存可以很容易地添加并行语句,因为线程将共享这些数据,但是线程容易受到虚假共享的影响,在这种情况下,变量本应是私有的,这些变量是无意中共享的。共享MPI使用私有内存模型,其中数据必须在线程之间显式共享,并且所有数据在默认情况下都是私有的。私有内存使得任何并行实现更复杂,因为线程必须被指示访问特定的内存进行计算。
而且,OpenMP在内部处理的执行过程中创建并销毁线程,并且性能很高。 SMPI线程在执行开始时创建,并始终保持不变。这使得管理SMPI线程更加困难,因为每个并行阶段必须由程序员明确管理。然而,程序员额外的工作可能会在性能方面得到回报,因为SMPI会带来更少的开销。
3.2性能评估
本节介绍MPI + OpenMP和MPI +共享MPI Householder Reflector内核优化的性能测试过程和结果。对于性能测试,改变用于计算的节点数是有意义的,因为在用真实世界的模拟执行VULCAN时经常使用许多节点。在一个多节点HPC集群上,最多有四个节点进行了调查。 MPI任务和OpenMP线程的数量以及并行部分中的环路阻塞的块大小不同。
4结论
在这项工作中,微型应用程序的开发是为了优化NASA真实应用程序VULCAN中的Householder Reflector内核。研究了两种用于共享内存并行的编程范例,OpenMP和Shared MPI,并且在多节点系统Turing上进行了多达四个节点的性能测试。 Householder mini-app的Shared MPI版本比OpenMP版本的性能提高了一倍。具体来说,SMPI的加速比率高达OpenMP的1.9倍。随着线程的最大数量,SMPI在足够大的工作量(m = 50m)下获得完美的加速。 OpenMP只能达到10的加速,这是基于所使用的线程数量的预期加速的一半。