文章时间:2021年6月前
会议/期刊:TPDS 2022
作者背景: Oak Ringe
笔记时间:2022年01月13日周四
论文地址:https://ieeexplore.ieee.org/abstract/document/9501495
Abstract
美国百亿亿计算机项目(ECP)正在开发的应用程序将在即将到来的百亿亿计算机上运行,将产生前所未有的保真度和创纪录的周期时间的科学结果。其中许多代码基于粒子网格方法,并使用先进的算法,特别是动态负载平衡和网格细化,以在Exascale机器上实现高性能。然而,这些算法在提高并行应用效率的同时,由于其数据分布的不规则性和动态性,给I/O逻辑提出了新的挑战。因此,虽然Exascale模拟的巨大数据速率已经对现有的文件系统写策略提出了挑战,但对生成数据的高效读取和处理的需求,对数据布局策略引入了额外的限制,这些策略可以在将数据写入二级存储时使用。我们回顾了这些I/O挑战,并介绍了两种在线数据布局重组方法,以实现读写性能之间的良好权衡。我们演示了使用这两种方法对ECP细胞内粒子模拟WarpX的好处,WarpX可以作为大量重要的Exascale应用程序的母题。我们展示了通过理解应用程序I/O模式和仔细设计数据布局,我们可以将读取性能提高80%以上。
第一章 Intro
百亿亿次计算面临许多挑战。其中最引人注目的是存储数据足够快。由于存储设备越来越大,但速度没有快很多[1],相对于千兆级计算机,与I/O带宽[2]相比,百亿亿级系统在计算速度方面提供了更大的提高。实际上,峰值I/O带宽与峰值计算速度(以每百万浮点运算的字节数为单位)的比率,对于当前和预计的系统[3],[4]来说,正在急剧恶化。这种不断增长的差异对应用程序有着深远的影响,并推动它们走向非常高效的I/O。此外,许多exascale应用程序正在使用高级计算技术,如动态负载平衡和自适应网格细化(AMR),由于内存中数据的不规则布局,这些技术带来了新的I/O挑战。
虽然应用程序正在转向更多的在线分析和减少[3],但它们仍然生成大量的数据供自己和其他团队进行后期处理。因此,科学计算中的一个关键挑战是获得接近最佳的写性能,从而使仿真花费最少的时间执行I/O。Exascale计算项目(ECP)中的几个项目专注于优化写性能的方法。为了提高效率,这些方法通常以与内存中使用的格式和布局相同的方式将数据写入磁盘。但是,由于这些数据随后必须被读取以进行后期处理和分析,因此理想情况下,数据应该以一种既能提高模拟的立即写入性能,又能提高后续分析的读取性能的格式和布局写入磁盘。然而,对访问模式[5]、[6]的研究一般只考虑通过简单的内存数据安排生成的数据;他们还没有研究更复杂的内存布局对读取性能的影响。每个进程包含多个数据块的代码允许使用各种I/O策略,以牺牲写性能来提高读性能。由于读取可以在一个到数千个节点上执行,而在每个节点上,我们可以从不同数量的进程和线程中读取数据,因此这些权衡很复杂。每个选择都能激发新的设计。
在本文中,我们在WarpX[7]上下文中研究了这些权衡。WarpX[7]是一个基于amr的细胞粒子(PIC)加速器物理建模代码,使用了AMReX[8]框架。我们对常见的数据布局策略进行了全面的研究,特别关注WarpX使用自适应网格的挑战,以及每个进程数十个块对读取性能的影响。我们的结果揭示了科学家应该在什么时候考虑将写优化的格式转换为读优化的格式;例如,是否对写入数据的节点数进行读取优化,以及是否在写入数据后但在读取数据之前进行数据转换。WarpX使用了重要的计算模型(AMR,动态负载平衡),这使得从这项研究中获得的经验教训与更大的颗粒网格和AMR社区相关。
虽然我们希望提供包含所有可能的阅读模式的通用方法,但我们意识到不可能对所有的模式进行优化。事实上,即使对于本文中讨论的一些较简单的读取模式,数据布局优化问题也是一个挑战。因此,我们没有解决查询优化的额外复杂性,如[9]中所研究的那样。我们也不研究在并行文件系统(如工作负载感知的条带化[6]、[10]、[11])上获得良好的I/O性能通常需要的其他优化,因为Summit超级计算机上的GPFS文件系统在内部处理条带化,它不允许应用程序修改条带化策略。这些研究超出了本文的研究范围。
我们的贡献如下。1)评估WarpX的I/O性能,量化不同数据布局策略下的性能差异。2)没有一种标准的数据布局策略能够同时实现良好的读写性能。3)我们提出并实现了一种利用空间特征实时减少WarpX数据块数量的方法,这大大提高了大多数常见读模式的读性能。4)基于Summit超级计算机采集的性能数据建立模型,研究了使用分段技术将数据异步移动到少量额外分段节点的可行性,同时修改数据布局以优化读性能。我们的研究表明,与原始数据布局相比,这种方法不仅提高了高达85%的读性能,而且与事后数据布局重组相比,它在资源利用方面更高效。
第二章 常见的数据放置策略
2.1 逻辑上连续的布局
在第一种策略中,数据被线性化,然后作为逻辑上连续的块完整地存储在文件系统上。(我们之所以说逻辑上连续,是因为在一个并行文件系统上,数据可能被自动划分为“条带”,并分布在不同的存储服务器上)。
由于消息传递接口(Message Passing Interface, MPI)中的并行跨步I/O操作的支持,这种直观的数据布局策略通常在I/O库中默认使用。但是,对于大型的基于MPI的并行应用程序,它通常产生次优的写性能,因为虽然驻留在每个MPI进程中的分区数据可能是本地连续的,但生成全局连续的数据布局可能需要大量的进程间通信。例如,图1显示了一个有四个过程的MPI程序,其中每个过程持有的数据按照一定的顺序线性化(例如,行主)。为了将全局2D阵列线性化以生成逻辑连续的布局,需要对每个进程的数据进行重新排列。这种重新安排通常通过调用MPI- io函数来实现,这通常会触发一些MPI集体操作,以协调进程之间的数据移动。对于高维数据,这些重新安排的代价可能特别高,特别是当许多流程参与或需要移动的数据量很大时。
2.2 组块
由于生成逻辑连续的数据布局会产生过多的开销,I/O库通常采用一种称为分块的数据平放策略,因为它倾向于以更有效的方式组织大规模并行程序运行产生的数据。其基本思想很简单:原始数据不是序列化为一个单独的连续块,而是被分割成多个块,分别存储在文件中,每个块都是逻辑上连续的序列。例如,如图2所示,每个进程仍然在全局数组的2×2块上运行。如果我们将每个进程拥有的块设置为一个块,每个进程就会在文件中分配一个独占空间来存储它自己的数据。这样,在进程之间重新安排数据所造成的开销就大大减少了。此外,由于每个块都可以单独访问,对数据子集进行操作的性能也得到了改善。
并行HDF5为用户提供了设置不同大小的块的灵活性,只要块是规则形状。但是,如果块大小太大或每个块的形状没有被仔细选择,仍然会触发重排。例如,在图2中,如果全局数组的每一列都被设置为一个chunk,那么来自两个不同进程的数据被包含在一个chunk中。在这种情况下,重新安排导致进程间通信的增加。此外,在一般情况下,各个进程提供的数据可能不会形成一个常规的、可行的大块。为了防止重新排列减慢应用程序的执行,通常采用两阶段I/O技术[12],[13]。通常,这种技术需要额外的计算节点/核,专门用于数据重新排列。ADIOS2[14]不允许用户基于全局空间的逻辑视图设置块大小。相反,它将每个进程本地的、连续的数据块视为一个单独的块。此外,为了避免数据布局的进程间协调,ADIOS2采用了日志结构的文件格式,因此这些chunk在全局数组中的位置并没有反映在实际的数据布局中。因此,ADIOS2需要额外的元数据,不仅要跟踪实际文件中的所有chunk,还要记录chunk在全局数组中的位置。
2.3 Sub-Filing
虽然分块可以减少数据重排的开销,但由于文件锁定争用,大规模并行写操作的性能有时会大大降低。例如,我们在图3a中显示了一个512×512 2D阵列分布在四个MPI进程上的配置。每个进程上的四个128×128块在全局空间中并不总是相邻的。这种类型的数据分布模式经常出现在支持动态负载平衡和/或自适应网格细化(AMR)的科学代码中。在图2中,每个进程只向文件中写入一个连续的数据块,相比之下,现在每个进程需要发出四个单独的写操作,针对共享文件中的不同偏移量。因此,会发生文件锁定争用。
为了解决这个问题,一种叫做子文件归档的策略已经被开发出来了。如图3b所示,每个进程创建一个单独的文件来存储它的数据,而不是将所有的数据块写入一个共享的文件,它独立地将数据写入该文件,以利用并行文件系统的高带宽。这种策略面临三个挑战:1)跟踪存储在每个子文件中的数据块会增加总体I/O性能的额外开销;2)并行程序多进程启动时,会产生过多的子文件,使并行文件系统的元数据服务不堪重负,给后期数据管理带来不便;3)处理子字段数据需要找到并打开所有对应读请求的子文件,这可能会导致较大的读延迟。
由于这些问题,I/O库并没有广泛使用子文件作为它们的主要布局策略。然而,作为自定义应用程序I/O层中的简单I/O实现,它仍然很流行。ADIOS2默认使用子文件;为了缓解子文件归档引起的问题,它提供了通过MPI通信在并行进程子集上聚合数据的选项,从而减少了子文件的总数,这可以显著提高性能[15]。这种方法允许ADIOS2在一定程度上降低写性能,以换取较轻的文件系统元数据负载。PnetCDF支持子文件归档,但在默认情况下禁用它。并行HDF5计划在未来[16]支持子文件归档。
第三章 数据放置策略:一个案列研究
选择正确的数据布局策略对于并行计算程序至关重要,因为它对它们的I/O性能有巨大的影响。这对于具有复杂负载平衡模式的科学代码来说尤其具有挑战性,这些模式通常与对AMR的支持相结合。我们以WarpX[7](基于amrex的[8]particle-in-cell (PIC)模拟)为例,研究了并行I/O常用数据布局策略的优缺点。
3.1 Summit的GPFS文件系统和WarpX I/O模式
在这里,我们首先简要概述Summit的GPFS文件系统(我们在其中执行所有测试)和WarpX I/O模式。Summit安装了一个基于posix的IBM Spectrum Scale并行文件系统(以前它被称为GPFS,为了简单起见,我们在本文中使用GPFS)。该文件系统的最大容量为250pb,在FPP模式下,顺序I/O的最大性能约为2.5 TB/s,随机I/O的最大性能约为2.2 TB/s,即每个进程都写入自己的文件[17]。与Lustre不同,GPFS不允许应用程序设置条带大小和条带计数。数据分条在GPFS内部处理,不向应用程序公开。因此,在本研究中,我们只关注用户空间中的数据布局策略。
WarpX使用空间域分解和动态负载平衡来将阻塞内存结构分布到MPI进程和相关的加速设备上。物理模拟框中的域分解数据由网格(“单元”)和粒子组成,网格可以是嵌套的细化分辨率(MR)。在1到N个网格块之间动态分配给一个设备,以用户定义的块大小的倍数分布。与每个网格块相关联的是粒子数据,粒子数据的数量在每个网格块的负载中可以任意变化。由于粒子在模拟中移动,对粒子的操作比网格操作更昂贵,WarpX/AMReX为用户提供了多种动态负载平衡算法,以实现细粒度的、计算平衡的分解,这可能会导致极其复杂的并行I/O模式[18]。
3.2数据布局对写性能的影响
为了研究不同的数据布局策略对基于amr的代码写性能的影响,我们在Summit上建立了弱伸缩测试。使用并行HDF5和ADIOS2输出不同布局策略的WarpX仿真数据(并行HDF5用于逻辑上连续的和块化的数据布局,而ADIOS2用于子文件策略),因为这两个I/O库已经集成到openPMD-api[19]中,这是WarpX和其他Exascale PIC代码使用的I/O框架。特别地,我们将Parallel HDF5配置为“独立I/O”模式,因为由于某些限制,“集体I/O”模式不适用于使用负载平衡和/或网格细化的科学代码。在每次运行中,我们使用一定数量的计算节点(最多1024个)启动WarpX模拟,每个节点有6个MPI级别。根据所选的I/O库,使用不同的数据布局策略将模拟数据写入GPFS文件系统。每个计算节点在每个输出步骤中写入64gb的数据,我们测量所有节点的总体写入吞吐量。GPFS内部将大数据块分割成16mb的块,并将它们分布在所有IO服务器上。虽然块的大小不能在用户空间中更改,但我们确保在写性能测试中,每个进程写入的最小数据块为16MB,以充分利用GPFS在Summit上的现有设置。所有测量结果如图4所示。
图4显示,将WarpX数据组织成逻辑上连续的布局会显著降低写性能。在模拟执行期间,每个进程为每个网格变量操作数十个数据块(例如,在我们的测试中,每排10个块)。虽然最初在全局数组中相邻,但随着模拟的进展,由于负载平衡操作,这些块在进程之间交换。因此,每个进程最终都可能获得全局数组中任意位置的数据块。将这些不相邻的数据块重新排列成逻辑上连续的布局可能会导致相当大的开销。
启用分块可以提高写性能;进一步显著的收益也可以通过添加sub-filing策略。当进程数量增加时,这种情况尤其明显。如2.3节所述,如果所有进程并发地将所有数据块写入单个共享文件,则文件锁定争用成为瓶颈。例如,当运行一个包含1536个进程的模拟时,只启用分块的总体写吞吐量仍然比同时启用分块和子文件的写吞吐量低一个数量级。
当启用子文件策略时,修改子文件数量也会影响写性能。如图4所示,当使用少量进程时,与每个计算节点创建一个子文件(“chunking+ sub-file - fpn”)相比,每个进程创建一个子文件(“chunking+ sub-file - fpn”)总是能够获得更高的写吞吐量。随着进程数的增加,每个计算节点采用一个子文件的写性能逐渐提高。这是因为当同时创建过多的子文件时,并行文件系统需要完成大量的元数据操作,这会降低整体写性能。
3.3数据布局对读性能的影响
我们在Summit上使用2.7 TB的WarpX数据集测试读取性能,其中每个3D网格变量为256gb。我们关注这些网格变量,因为它们是进行这类模拟的科学家的主要关注点。因为所有3D网格变量都有相同的形状和大小,所以我们只显示一个变量“B”的读取结果。
为了演示分解如何影响读取性能,我们使用两个Summit节点使用三种不同的域分解方案读取所有“B”,结果如图5所示。分解1×1×2意味着3D数组沿着z维分成两半,这样两个进程都读取一半的数据。类似地,分解1×2×1和2×1×1分别沿着y和x维分割3D数组。从图5可以看出,在相同的分解方案下,读取不同布局策略产生的数据时,性能差异较大,而且对于某些数据布局策略的分解方案,读取性能也比较敏感。当我们从大量的进程中读取数据时,我们会发现这种差异会产生重大的后果。
最后,我们使用不同的进程数和不同的分解方案进行了综合测试,以衡量常用布局策略在不同读取模式下的读取性能。图6显示了读取WarpX数据中的3D mesh变量时常用的六种数据访问模式。根据读取器和分解方案的数量,每个读取器只能并发地读取所需数据的一部分。当多个进程允许多个可能的分解方案时,我们只显示获得最佳读性能的分解结果。
如图7所示的结果显示,如果只使用几个进程(8个或更少)来读取数据,逻辑上连续的布局在大多数情况下提供更好的读取性能。然而,当读取xy平面时,逻辑连续布局的这种优势消失了,因为xy平面的数据元素分散在一个逻辑连续的3D数组布局中。当进程数量增加时,读取逻辑连续布局的性能也会下降。这是因为更多的进程意味着对逻辑连续布局中的不同区域有更多的并发读请求,这增加了向底层存储设备发出的随机查找操作。
当只启用分块策略生成数据时,读性能不佳。这是因为每个进程读取的数据是由许多块组成的;因此,每个进程不仅必须在文件中找到所有需要的块,还必须将这些块线性化,以便在内存中生成一个连续数组。一般来说,较大的块大小有助于缓解这个问题,但它也会显著降低写性能,如第2.2节所示。
如果在生成数据时同时启用分块和子文件策略,则读性能会随着进程的增加而显著提高。与只使用块的情况相比,我们看到了读性能的提高。然而,使用较少的进程读取数据仍然很慢,因为每个进程仍然需要合并许多块。
第四章 数据块的聚类和合并
从上一节的性能研究中,我们发现没有一种常用的数据布局策略能够同时实现令人满意的写和读性能。在本节中,我们将研究如何利用WarpX模拟数据中的空间局地性来优化现有的数据布局策略,从而在写和读性能之间找到一个很好的平衡点。
4.1空间位置
如3.1节所述,在执行基于amr的科学代码(如WarpX)时,通常会触发负载平衡操作。一旦负载均衡操作启动,数据块就会在进程之间交换。因此,随着模拟的进行,每个进程操作的数据块可能与最初分配的数据块非常不同,并且可能无法合并在一起形成一个具有规则形状(例如,长方体)的更大的块。这就是为什么没有一种常见的数据布局策略能够很好地处理WarpX数据的根本原因。例如,如果使用逻辑上连续的布局,由于在所有进程中分布了大量的块,重新安排布局将导致大量的开销。如果启用了分块和子文件策略,尽管写性能得到了提高,但从少量进程中读取数据会变慢,因为每个读取器都需要读取和线性化许多小块。并行HDF5允许用户基于全局数据空间的逻辑视图设置更大的块以减少小块的数量,但在这种情况下,设置很难匹配数据块在进程之间的物理分布。根据用户设置,来自不同进程或节点的数据块很可能属于相同的块,从而导致昂贵的布局重新排列。
我们解决这个问题的基本想法是利用WarpX数据的空间局域性来减少数据块的数量。具体来说,我们不是从整个数据空间的逻辑视图来设置更大的块,而是关注数据块实际上是如何分布的,以及在每个进程或计算节点中合并数据块的可能性。如果进程内或节点内的块合并是可能的,我们可以减少块的数量而不会造成太多的开销,因为进程内或节点内的数据移动比节点间的数据移动要便宜。下面是一个简单的例子来演示这个想法。如图8所示,假设mesh变量为512×512×512数组,分解为64块128×128×128。经过几轮负载均衡后,不同进程拥有的数据块会呈现出不同的颜色。我们看到,虽然不可能合并每个进程拥有的所有数据块,但可以将一些数据块合并成更大的块。例如,可以合并进程0上的一些块,这将进程0上的块数量从16减少到6。此外,如果进程0和进程1运行在同一个计算节点上,并且它们拥有的数据块可以聚合在一起,则块的数量可能会进一步减少。
4.2 数据块的聚类和合并算法
我们将Berger和Rigoutsos[20]提出的算法扩展到WarpX仿真输出的数据块的聚类和合并。利用原算法对网格点进行聚类,其目标是在二维空间中找到覆盖所有网格点的最小矩形数。我们修改了原来的算法,使它可以处理3D数据,2)直到找到填充了原始数据块的长方体,它才会停止。(在原来的算法中,每个矩形内允许有空格。)
该算法的输入是一组WarpX数据块,这些数据块要么属于同一进程,要么来自运行在同一计算节点上的进程。为了表示的简单,我们假设这些数据块都有相同的形状;在实践中,这种假设可以在一定程度上放宽。如算法1所示,第一步是在全局三维空间中找到包含所有原始数据块的最小长方体。例如,图8中包含进程0所有数据块的最小长方体的形状为512×512×512。然后这个长方体被添加到FIFO队列中。如果这个队列不是空的,则开始新的while循环迭代。在这个while循环的每次迭代中,首先从FIFO队列中取出一个长方体,该队列包含一定数量的原始数据块。如果这个长方体的体积等于所有原始数据块的总量,这意味着我们已经找到了一个更大的块,所有原来的块这个长方体拥有可以合并成,然后添加这个长方体列表l。否则,还有在这个长方体空间,它需要被进一步分成较小的长方体。
该算法的关键部分是找到分割长方体的最佳位置。例如,考虑图9。为了找到分割长方体的位置,我们需要首先计算原始数据块沿每个维度的分布。例如,沿着x维,长方体可以被分成四片块。在每个片中,一些位置被原始数据块占据,而其他位置是空的。原始数据块在每个切片中的百分比构成向量Uyz=[116,516,716,316]。这个向量表示一个直方图,可以看作是一个一维的二值图像。在x维度上找到最好的分割位置与在这幅图像中检测边缘类似。因此,我们可以将拉普拉斯边缘检测器等常见的边缘检测技术应用到这个直方图中。例如,Lyz=∇2Uyz是拉普拉斯微分算子应用于Uyz的结果。为了找到这个直方图中边缘的位置,我们需要在Lyz中找到一个过零点;由于拉普拉斯算子是二阶导数,所以零交叉对应于Uyz中的拐点,这就是我们要寻找的边缘位置。类似地,我们可以分别计算y维和z维的Lxz和Lxy,并找到它们的零交叉点。在所有这些零交叉中,我们选择直方图中斜率最大的那个作为分割整个长方体的位置。在这个例子中,这个位置在y维上。
将当前长方体分成两个子长方体后,检查这两个子长方体是否为空。如果它们仍然拥有原始数据块,我们将它们添加到FIFO队列中进行进一步处理。一旦FIFO队列变为空,while循环退出,所有填充了原始数据块的长方体都在列表l中,这意味着数据块的聚类结束。现在我们需要合并这些原始数据块的实际数据。具体来说,对于列表l中的每个长方体,我们将其拥有的所有原始块的数据合并并序列化到一个更大的内存缓冲区中作为一个新的数据块。然后,所有这些新数据块将作为“块”写入并行文件系统。
4.3数据块聚类与合并评价
我们从两个方面来评估数据块聚类和合并算法:1)它提供的读性能改进,2)它引起的写开销。特别地,我们将该算法应用到真实的WarpX仿真输出中。对于使用256个计算节点和1536个进程运行的WarpX,每个进程运行在大约10个原始数据块上,每个计算节点上大约有64个数据块。如果启用了进程内块集群和合并,平均而言,每个进程操作的数据块数量将从10个减少到3个。启用节点内块集群和合并功能后,每个计算节点上的数据块数量平均由64块减少到10块。节点内集群和合并需要将运行在同一计算节点上的进程拥有的数据块聚集到一个进程中,这会导致额外的数据移动开销。
通过减少数据块数量,可以提高读性能。如图10所示,我们分别测量了进程内分块聚类和节点内分块合并后读取WarpX数据的性能,并将其与常用数据布局策略的性能进行比较。正如我们所看到的,在六种常见读模式中的四种(读取整个域、yz平面、子区域、xz平面)下,启用数据块集群和合并的读性能明显好于只启用分块和子文件。但是,由于合并后的数据块的形状和大小可能不同(如图8所示),启用块合并并不能保证在每种读模式下(如在读取xz平面和xy平面时)都能提高读性能。
我们还通过考虑性能改进和开销来评估启用块集群和合并的整体效益。当采用进程内块聚类和合并时,WarpX数据中一个3D mesh变量的聚类块开销小于0.001秒,而在内存中合并这些数据块大约需要0.19秒。如果我们启用节点内块集群和合并,这两个数字分别是0.0003和1.03秒,但是通过MPI集合操作在每个计算节点内收集数据块会有大约0.25秒的额外开销。在读取端,启用块合并所节省的秒数是通过计算不合并和合并时的读取时间之差来获得的。因此,使用块合并所节省的总时间是这样计算的:用写端所节省的时间减去读端所节省的时间。如图11a和11b所示,对于大多数场景,启用块合并可以缩短应用程序工作流的总时间。
我们还通过考虑性能改进和开销来评估启用块集群和合并的整体效益。当采用进程内块聚类和合并时,WarpX数据中一个3D mesh变量的聚类块开销小于0.001秒,而在内存中合并这些数据块大约需要0.19秒。如果我们启用节点内块集群和合并,这两个数字分别是0.0003和1.03秒,但是通过MPI集合操作在每个计算节点内收集数据块会有大约0.25秒的额外开销。在读取端,启用块合并所节省的秒数是通过计算不合并和合并时的读取时间之差来获得的。因此,使用块合并所节省的总时间是这样计算的:用写端所节省的时间减去读端所节省的时间。如图11a和11b所示,对于大多数场景,启用块合并可以缩短应用程序工作流的总时间。
如果科学家对运行在超级计算机上的作业的成本更敏感(通常通过计算节点和作业占用的时间的乘积来衡量),那么在这里,我们还计算通过启用数据块集群和合并来评估其有用性的节点秒数。如图12a所示,启用进程内块合并时,写入端每个变量的节点秒损失总是256×(0.001+0.19)=48.9。节点秒数的增加是用于读取的节点数乘以启用块合并所节省的秒数。从图中我们可以看出,如果读取器的数量小于4,那么读取器的节点秒的增益总是大于写入器的节点秒的损失,说明我们应该启用进程内的块合并。通过启用进程内块合并,我们可以节省150秒的节点时间来读写每个3D网格变量。但是,随着reader数量的增加,reader端节点秒的增益下降,使得进程内的块合并效率降低。对于节点内块合并的情况,我们做了相同的计算。如图12b所示,由于节点内的块合并开销较大,写入端通常使用较多的计算节点,只有当采用分解方案2×1×1进行读取时,节点秒的增益大于损失。我们必须指出的是,大规模长时间运行的模拟作业的输出在生成后通常会被领域科学家反复访问。因此,即使块集群和合并在生成数据时产生了一些开销,在下游数据工作流中通常也会有长期的好处。
综上所述,进程内块合并和节点内块合并都可以提高读性能,但在超级计算机上,通过动态负载均衡和/或AMR,进程内块合并可以更好地利用科学代码的资源。对于普通的科学活动,数据只被写入一次,但被多次读取,从长远来看,这些方法可以带来显著的好处。
第五章 重组数据布局
虽然第4节提出的数据块集群和合并方法相比仅启用chunk和sub file策略提高了读性能,但合并后的数据块大小和形状的调整缺乏灵活性,不利于获得更好的读性能。在本节中,我们将研究动态重组数据布局以进一步提高读取性能(如果有额外的系统资源可用)的可行性。
5.1不同的数据布局重组方式
如图13a所示,假设我们在Summit上运行一个模拟,周期性地输出数据,并启用分块和子归档功能,以达到最佳的写性能。重组数据布局最简单的方法是在模拟结束后启动具有一定数量进程的作业,该作业将读取模拟生成的数据,并将其再次写入具有新布局的并行文件系统。这就是所谓的事后数据布局重组。这种方法的优点是它不会降低模拟工作的速度。其缺点是,在模拟作业完成后,领域科学家无法立即访问重组布局中的数据,因为数据的读写可能需要很长时间,特别是在模拟输出较大的情况下。
另一种方法是动态地重新组织数据布局。具体来说,在模拟运行时,而不是让仿真输出直接写入并行文件系统,我们把数据通过MPI某些流程或其他通信协议形成我们所需要的数据布局,然后让这些过程将数据写入文件系统。现有的研究建议基于不同的技术实现这一功能,包括两阶段I/O和分期。例如,Tessier et al.[12]开发了一种高效的拓扑感知的两阶段I/O算法,在执行读写之前聚合连续的数据块。Kumar等人提出了一种两阶段的方法,利用基于mpi的数据聚合动态地重组粒子数据布局。[21],[22]中也提出了基于分段技术的解决方案。尽管这些方法对某些应用用例显示出了有希望的结果,我们仍然需要了解,对于使用动态负载平衡和/或AMR的科学应用程序来说,在运行中重新组织复杂的数据布局是否可行或有效,因为在进程之间移动大量的数据块会导致巨大的开销。
5.2数据布局重组的效率
为了研究这个,这里我们利用非阻塞分段技术强大的分期耦合器[23]异步移动计算节点的数据块的仿真运行时,几个分段节点的数据块合并为一个连续的块被写入并行文件系统之前。我们之所以选择这种技术,是因为它是ADIOS2库的一部分,WarpX可以通过openPMD-api[19]调用ADIOS2库。我们在Summit上运行测试以收集性能数字,然后构建基于这些性能数字量化的模型。我们在表1中列出了这个模型中使用的符号。
在所有这些符号中,tw()、tr()和ts()依赖于设置的规模和并行性,这意味着它们是计算节点数量、每个节点的进程数量和数据大小的函数。因此,我们首先展示了一些弱伸缩性和强伸缩性测试的结果,这些测试是用于理解在采用不同的设置时ts() (tw()和tr()在前面的部分中已经研究过)的变化。如图14所示,在我们的弱伸缩测试中,我们固定每个写入器节点的数据大小(1 GB或2 GB),并测量不同写入器和读取器数量时的数据暂存时间。在我们的强伸缩测试中,我们固定了数据的总大小(100或200 GB),并在使用不同数量的写入器和读取器时测量数据暂存时间。从结果中我们可以看到,数据暂态时间ts()不能用一个简单的公式来描述,这给这个问题增加了额外的复杂性。
现在我们来介绍一下我们的模型。如图13a所示,仿真总时间为N[tc+tw(N,p,S)],离线重组数据布局所需时间为tr(m,q,NS)+tw(m,q,NS)。因此,事后数据布局重组的资源利用率为U=nN(tc+tw(n,p,S))+m[tr(m,q,NS)+tw(m,q,NS)]。动态数据布局重组,可能有两种情况:1)如果ts (n, p m q S) + tw (m q S)≤tc,那么整个工作流的执行时间是Ntc + ts (n, p m q S) + tw (m q S),因此,资源利用率可以计算(n + m) [Ntc + ts (n, p m q S) + tw (m q S)]。2)如果ts(n,p,m,q,S)+tw(m,q,S)>tc,计算将被延迟,直到当前的模拟输出被写入文件系统。此时整个工作流的执行时间为tc+N[ts(N,p,m,q,S)+tw(m,q,S)],资源利用率为U=(N +m){tc+N[ts(N,p,m,q,S)+tw(m,q,S)]}。对于给定的模拟设置,这些公式中的一些变量是固定的,包括n,p,S。尽管我们可以使用更多的暂存节点,但由于资源有限,这个数目通常是固定的(占作业所占用的计算节点总数的1%)。如果n,p,m,q,S是固定的,tw(),tr(),ts()也是不可变的,因为它们是依赖于硬件的。用户唯一可以控制的变量是tc和N,其中tc决定了仿真数据输出的频率,N决定了仿真运行的时间。因此,我们在Summit上测量给定模拟设置的性能,以量化所有不变变量,并演示如何选择tc和N,以使动态数据布局重组在资源利用方面比事后方法更有效。
我们使用256个节点,每个节点启动6个进程来运行WarpX模拟。我们还使用两个额外的节点,并为每个节点启动32个进程进行数据暂存。每个模拟输出的大小为256gb,这是一个3D网格变量(我们可以通过staging重新组织所有变量的布局,但这里我们只输出一个变量,以与前几节中的读取性能比较一致)。我们还使用256个节点(每个节点6个进程)进行模拟,使用2个节点(每个节点32个进程)进行事后运行,测试事后数据布局重组。在重组后的布局中,将2048×4096×4096 mesh变量分解为64个块,分解方案为4×4×4。我们的测量结果如表2所示,tr(2,32,256N)=tr(2,32,256)N=11.1N, tw(2,32,256N)=tw(2,32,256)N=13.6N。
设定tc=40秒(即模拟每400步输出一次数据,在此设置下,每次模拟输出大约需要0.1秒),则ts(n=256,p=6,m=2,q=32,S=256)+tw(m=2,q=32,S=256)=19.4+13.6=33<tc。< span="">动态重组的资源利用率为Uo=(256+2)(40N+19.4+13.6)=258(40N+33)。事后重组的资源利用Up=256N(40+1.4)+2(11.1N+13.6N)=10647.8N。只有Uo<up,即258(40n+33)<10647.8n根n≥26(模拟至少需要输出26次数据),动态重组的资源利用率才会小于事后重组。< span=""></up,即258(40n+33)<10647.8n根n≥26(模拟至少需要输出26次数据),动态重组的资源利用率才会小于事后重组。<></tc。<>
如果我们固定tc=20秒(即模拟输出数据每200步),则ts(n=256,p=6,m=2,q=32,S=256)+tw(m=2,q=32,S=256)=19.4+13.6=33>tc。动态重组的资源利用率为Uo=(256+2)[20+N(19.4+13.6)]=258(33N+20)。事后重组的资源利用为Up=256N(20+1.4)+2(11.1N+13.6N)=5527.8N。因为258(33N+20)>5527.8N,我们总是有Uo>Up,这意味着当tc=20时,动态重组的资源利用率总是大于事后重组。事实上,在这种情况下,要使Uo<up,我们需要tc>8106.2N256N−258>limN→∞8106.2N256N−258=31.66。</up,我们需要tc>因此,我们需要选择31.66<tc<33的tc。< span=""></tc<33的tc。<>
如果用户想要模拟输出至少50输出(N≥50)和动态仿真不减速的重组(tc > 33),需要:tc Uo <⇒258 (Ntc + 33) < 256 N (tc + 1.4) + 49.4 N⇒tc < 407.8 N−85142 N⇒tc < 150.26,使资源利用率的动态重组不到因果的方法。
最后,我们评估了数据布局重组后的读性能,并将其与其他方法进行了比较。如图15所示,数据布局重组后,读性能明显提高,并发读器数小于16。特别是,当使用2×1×1分解进行阅读时,与其他方法相比,阅读时间减少了85%。然而,随着并发读取器数量的增加,数据布局重组所带来的性能提升降低;大于64时,数据布局重组后的读性能较其他方法差。因为重组后的数据有64个块;当并发读器超过64个时,一个块可能会被多个读器访问,从而导致争用。
第六章 相关工作
数据布局是并行计算机上I/O访问延迟和带宽的关键决定因素。安排数据访问以提高I/O系统性能,无论是针对特定情况还是作为一个总体目标,已经研究了20多年[24],[25],[26]。历史上,并行I/O中间件和文件系统是分开开发的,以简化实现并增强并行I/O组件之间的透明性。然而,最近的研究研究了数据布局感知的优化策略,这些策略促进了并行I/O中间件和文件系统的更好集成,并取得了很有希望的结果[2010-27]。
随着处理器和存储设备之间的性能差距不断扩大,越来越多的研究关注于更好地理解应用程序的I/O模式,以及以不同布局预先安排数据的潜在好处。Liu等人[28]研究了当读模式与数据的原始组织不一致时,对数据分析任务中读性能的影响。基于这些发现,作者提出了一种方法,自动重新组织以前写的数据,以符合已知的读模式。Tang等[29]人通过向该方法添加一个动态组件来扩展这项工作,使其能够识别数据使用模式,并在多个重新组织的布局中复制感兴趣的数据,从而在运行时受益于常见的读取模式。
最近的工作重点是优化大规模数据中心中当前使用的I/O库,以适应HPC应用程序中的频繁模式。[30]等人关注MPI-IO,为基于hdd或ssd的服务器上的每种访问模式创建了重新组织数据副本的方法,用于低或高I/O并发性应用程序,这取决于它们的模式。类似地,Tsujita等人的[31]研究了通过MPI-IO层进行集体通信的聚合方法的性能优势。
HDF5 I/O库的性能已经被广泛研究,并提出了多种方法来优化数据访问。Ji等人提出了几种策略来优化HDF5 I/O操作,包括块存储、并行读写、按需转储和500米口径球面射电望远镜项目的流处理。Mehta et al.[33]开发了一个新的HDF5插件,以便使用并行文件系统将单文件布局转换为一个数据布局,该数据布局经过优化,并以一种独特的方式存储数据,能够对数据进行语义后处理。Mu等人,[34],设计基于数据容器的存储接口,提供数据分块,利用多层存储。
ADIOS库使用分块进行数据访问,并且可以对科学数据集使用块范围索引技术,该技术只记录数据块[35]中所有记录的取值范围。Lofstead等人将基于ADIOS日志的BP格式与逻辑连续的NetCDF或HDF5格式进行比较,考虑到不同的模式、布局和数据大小。另一个类似的研究[36]侧重于大规模陀螺动力学环面模拟。它引入了一种新方法,可以在启用分块和子文件布局策略时减少ADIOS中的元数据开销。
除了I/O库之外,对象存储也吸引了HPC社区的大量关注。像Intel的DAOS[37]和Seagate的Cortex[38]这样的对象存储是百亿亿次应用程序面临的元数据挑战的潜在解决方案。
第七章 结论
我们对并行I/O的常见数据布局策略进行了全面的研究。我们表明,由于具有动态负载平衡和/或AMR的科学代码的复杂I/O模式,现有I/O库中使用的标准数据布局策略不能同时实现令人满意的写和读性能。
了解了现有数据布局的局限性,我们提出了两种在线数据布局重组方法,目的是在这些复杂的I/O模式的写和读性能之间实现良好的权衡。第一种方法利用数据的空间局部性,在每个进程或计算节点内聚集和合并数据块;我们表明,对于大多数常见的读模式,该策略可以显著提高读性能,同时只产生最小的写开销。这种方法的性能结果使用了实际的复杂应用程序I/O模式,无需对应用程序代码进行任何更改就可以很容易地应用。
第二种方法是充分利用现有的分段技术来重新组织数据布局。由于在重组中有更高的自由度,这种方法带来的读性能的潜在收益甚至比第一种方法更大。因为需要移动大量的数据块在在线数据布局重组过程中可能会导致重大的开销,我们建立一个模型来理解何时以及如何使用staging-based数据布局重组可以获得更好的资源利用率相比因果的方法。