在本文中,我们将举例介绍如何展开有限差分 (FD) 计算内核,在分布式系统上运行。 此外,我们还将介绍一项技术,展示如何处理不同节点或计算设备提供不同的计算速度时,异构分布式系统出现的负载失衡的问题。 本文提供了一个示例源代码,对我们的实施进行例证。
我们的构建模块是 FD 计算内核,是地震成像 RTM (逆时偏移)算法中经常用到的内核。 ISO-3DFD (各向同性三维有限差分)stencil 执行的计算在油气调查和勘探复杂地下结构精确成像方面起着重要作用。 在本文中,我们利用 [1] 和 [2] 中介绍的 ISO-3DFD 阐释了简单的基于 MPI 的分布式实施,支持分布式 ISO-3DFD 计算内核在包括主要的英特尔® 至强™ 处理器和附加的英特尔® 至强融核™ 协处理器的混合硬件配置上运行。 此外,我们还对英特尔® 软件工具进行了探索,以期帮助对负载均衡进行分析,提高性能和可扩展性。
分布式 ISO-3DFD
我们的说明案例是对 ISO-3DFD 计算 stencil 的一维分解。 我们设置了一个计算区域,该区域可跨所有 MPI 进程划分。 对于此示例,我们在每台计算设备(英特尔至强处理器或英特尔至强融核协处理器)上设置了一个 MPI 进程。 这一实施包括 MPI 进程之间(即处理器和协处理器之间)所需的 halo 交换。 当区域分解按照 [1, 2] 中描述的方式应用到 FD stencil 上时,应以每个算法时间步长为单位在子域内实施 halo 交换。 这是因为靠近子域边界的域的点值更新要求值在临近子域上计算:
1
for(int k=1; k<=HL; k++)
//Stencil Half-Length HL
2
u_0 += W[k]*(
3
U0(ix+k,iy ,iz ) + U0(ix-k,iy ,iz ) +
4
U0(ix ,iy+k,iz ) + U0(ix ,iy-k,iz ) +
5
U0(ix ,iy ,iz+k) + U0(ix ,iy ,iz-k));
三维 stencil 的阶由其半长 (HL) 值定义:比如,一个模板的第八阶 stencil 由其半长 HL=8/2=4 的值定义。 相邻子域之间要交换的 halo 的宽度也等于 HL。
这一示例代码使用对称执行模型:代码在主处理器和协处理器上运行。 这可通过完全对称的 MPI 执行来完成,其中英特尔至强处理器和英特尔至强融核协处理器上可以运行不同的进程。 例如,假定有一个名为hostname1 的双插座系统,其中有两个英特尔至强融核协处理器插卡(名为 hostname1-mic0 和hostname1-mic1)连接至系统的 x16 PCIe* 插槽。 同时假定有两个可执行二进制:rtm.cpu (面向处理器架构编译,如英特尔® 高级矢量扩展指令集 2(英特尔® AVX2)和 rtm.phi (面向英特尔至强融核协处理器架构编译)。 使用英特尔® MPI 库,开发人员可在 MPI+OpenMP* 对称模式执行中同时利用两个可执行二进制:
mpirun \
-n 1 -host hostname1 -env I_MPI_PIN_DOMAIN=socket -env OMP_NUM_THREADS=14 ./rtm.cpu : \
-n 1 -host hostname1 -env I_MPI_PIN_DOMAIN=socket -env OMP_NUM_THREADS=14 ./rtm.cpu : \
-n 1 -host hostname1-mic0 –env OMP_NUM_THREADS=244 ./rtm.phi : \
-n 1 -host hostname1-mic1 –env OMP_NUM_THREADS=244 ./rtm.phi
上述简化的单节点示例假定 rtm.cpu 和 rtm.phi 均按照 [1, 2] 中描述的方式通过 OpenMP 线程并行。 MPI 用来帮助在节点、处理器和协处理器之间交换和同步数据。 OpenMP 用来通过指定处理器或协处理器的内核划分 MPI 进程计算工作。 上述示例还可扩展至多个采用处理器和协处理器的节点。 请参见 [3],了解有关 MPI 对称模式执行的更多详情。
以下是简化的 MPI harness: 1) 假定每个英特尔至强融核协处理器相当于一个独立的计算节点,未使用卸载编程语法 2) 允许通过非阻塞 MPI 调用进行异步 halo 交换。 用邻近子域覆盖计算并交换 halo 需要在每个子域上考虑两种计算区域:
本地计算:随距离变化的点 > 距离邻近边界的 HL。 即,进行 stencil 计算的点仅取决于以前在同一个子域计算的值。
Halo 计算:随距离变化的点 <= 距离邻近边界的 HL。 即,进行 stencil 计算的点仅取决于以前在同一个子域计算的值。
按计划,我们应具备以下条件:
MPI 实施的风格是简单的最近邻居 halo 交换。 首先,使用缓冲区 BufferPrev 和 BufferNext 发布邻近子域所需的 halo 异步接收:
接下来,先更新 Halo 计算区域中的点,因为邻近子域将需要这些点:
halo 计算区域中的更新值异步发送至邻近域:
当进行异步 halo 交换后,本地计算区域内的点可进行更新,因为这些计算不依赖于邻近域的值:
然后,使用 MPI_Waitall 同步调用检查异步 halo 交换的完成情况。 最后将传输缓冲区 BufferPrev 和BufferNext 中接收到的值复制到子域:
实际实施可参见本文所附的示例源代码包。 它包含一个运行在 ISO-3DFD 代码(以前在 [1, 2] 中发布)上的 MPI 层。 每个 MPI 进程可通过硬件设置(如睿频加速模式、超线程和 ECC 模式(英特尔至强融核协处理器))调整性能,也可通过软件优化调整高速缓存阻塞、线程关联和数据预取距离进行调整。参考原文,了解有关单个进程优化和调整的详情。 |