1. 荷兰大气大涡模拟(DALES)模型概述荷兰大气大涡模拟(DALES)模型是一个高分辨率的大气数值模拟工具专门用于研究大气边界层中的湍流、对流和云物理过程。作为大气科学研究的重要工具DALES能够模拟水平分辨率10-200米、垂直分辨率10-50米尺度的大气现象这使得它能够显式地模拟云团和对流上升气流等精细结构。DALES模型采用Fortran 90编写核心架构基于MPI的域分解并行策略。整个代码库约7.5万行分为物理过程、数值计算和工具模块三大类。模型使用三维数组作为基础数据结构在初始化时一次性分配内存因为计算网格是固定的。特别值得注意的是数组的ijk索引中k方向垂直方向不是连续存储的这种内存布局对后续的GPU优化提出了挑战。提示DALES采用z-pencil垂直于地面的方向的域分解方式生成笛卡尔子域其水平方向的大小与MPI进程数成反比。每个分区在水平方向添加halo cells通常1-3层来确保跨MPI进程的数据一致性通过非阻塞的发送/接收操作进行数据交换。2. GPU加速的必要性与挑战2.1 大气模拟的计算需求大气数值模型是计算最为密集的物理模型之一。其计算复杂性来源于气流动力学的混沌特性以及与各种传输过程如降水、化学反应、太阳和热红外辐射、海洋/陆地相互作用的耦合。模拟的准确性和可靠性强烈依赖于模型离散化的空间和时间分辨率反过来又依赖于对大量计算资源的高效利用。传统上大气数值模型依赖于在强大超级计算机上的并行实现。过去十年中GPU加速器在高性能计算(HPC)中的大规模使用改变了这一格局。目前GPU占据了Top500超级计算机中四分之三的计算能力。气候学界因此探索了多种有效利用GPU的途径。2.2 GPU加速路径选择早期工作集中在将选定的计算密集型内核转换为CUDA实现了单个内核最高20倍的加速。随后的努力旨在加速整个求解器导致了NIM-CUDA、GALES或MicroHH等求解器的开发后两者引入了先前Fortran代码库的C/CUDA重写。然而这种激进的方法需要大量的代码开发投入对用户来说意味着颠覆性的改变。近年来基于指令的加速方法如OpenACC已成功应用于天气和气候Fortran代码库在实现GPU加速的同时大幅减少了代码修改量。考虑到DALES代码库的规模约7.5万行和模型参数调优与验证的长期性完全用更现代、对GPU更友好的编程语言如C重写求解器并不可行。此外DALES被研究人员和学生广泛使用后者通常计算机科学背景有限这使得Fortran的命令式编程风格成为一个合理的选择。3. OpenACC加速实现策略3.1 数据管理优化DALES中的数据容器分布在物理、数值和工具Fortran模块中每个模块管理其计算所需的多维数组的动态内存分配和释放。在早期GPU如NVIDIA Kepler及更早版本上有限的设备内存需要仔细管理加载到设备内存中的数据数据在设备和主机之间的传输被发现是影响性能的主要瓶颈。利用现代GPU更大的内存DALES采用了将整个CPU内存镜像到设备上的策略。每个模块在CPU上初始化数据后使用enter data copyin子句一次性将数据传输到设备在CPU上释放数组前使用exit data delete子句清除设备内存。这样在启动计算内核时数据总是假定已经存在于设备上只有当执行诊断或检查点操作时才发生从设备到主机内存的数据拷贝。3.2 核心移植策略DALES典型的计算子程序可分为两类嵌套的独立ijk或ijkn循环遍历三个空间维度和可能的第四个标量索引空间维度类似的嵌套循环但在对应于垂直方向的k索引上存在依赖关系考虑到DALES典型用例中ijk循环大小的广泛变化我们没有针对特定案例大小过早优化OpenACC编译指示。相反默认方法是在尽可能多的紧密嵌套循环上使用collapse子句以向GPU暴露最大程度的并行性同时保持可移植性。对于包含地表层(k1)特殊处理的ijk循环为避免设备代码中的分支和由此产生的线程发散k1的情况被分离到单独的内核中使用async子句来隐藏启动延迟。对于带有k依赖的ijk循环当依赖严格是加法性时使用原子操作如在云沉降内核中云滴在相邻k层之间转移或者引入临时数组。3.3 代码重构关键技术为了能够collapse尽可能多的循环我们对多个计算内核进行了局部重构将仅依赖k的计算移到最内层循环以重复计算为代价。在微物理和热力学部分需要更广泛的重构因为局部状态的差异会导致显著的线程发散。两个典型的重构例子雨微物理计算优化DALES中的所有雨微物理计算都使用掩码以利用雨滴通常存在于有限的k层范围内并在展向方向上阵雨中聚集的观察结果。最初的CPU实现基于k-only循环结合Fortran数组语法和exit语句在GPU上表现不佳。我们改用完全collapse的ijk循环上的归约操作但需要为CPU和GPU维护不同的代码版本因为GPU方法在CPU上被证明更昂贵。热力学饱和调整方案DALES在热力学例程中使用饱和调整方案来诊断云液态水含量。为相应调整液态水位温需要Newton-Raphson算法。每个计算单元中的局部条件可能导致达到所需精度所需的Newton迭代次数不同引入线程发散。通过展开固定数量的迭代精度足够替换迭代算法缓解了发散问题在CPU和GPU上都得到了更高效的内核。4. 外部库的GPU加速4.1 辐射传输计算辐射传输计算使用RTE-RRTMGP库执行。该库由两部分组成均用Fortran实现并通过OpenACC指令支持GPU卸载RRTMGP通过插值表格数据从大气输入状态计算分子和云的辐射特性RTE解决辐射问题并输出跨空间域辐射通量由于内存限制实际上不可能同时运行所有列计算。总列数因此被分成若干批次。最大化每批列数或最小化批次数很重要因为多次调用RRTMGP和RTE库会带来与内核启动开销相关的额外计算成本。4.2 泊松求解器的FFT为了在GPU上执行泊松求解器所需的3D FFT我们依赖cuFFT库。傅里叶变换在一个空间方向接一个方向地执行。因为傅里叶变换是非局部的它需要访问沿执行方向的整个场数据跨越域分区。这需要通过执行转置来重新组织3D场内存布局这需要密集的全通信。值得注意的是cuFFT不支持DALES中用于N大小实数到复数变换的FFTW半复数编号格式。我们采用了CaNS中使用的方法对cuFFT的输入/输出进行最小化的前/后处理步骤以及修改波数的重新排序。5. 性能评估与优化5.1 测试案例与验证我们选择Cloud Botany模拟集合中的一个案例作为GPU移植项目的测试案例。Cloud Botany是一组103个DALES模拟研究浅积云在亚热带海洋上的行为探索云及其中尺度组织在不同物理条件下的变化。模拟域在两个水平方向上宽150公里足够大以允许在更大尺度称为中尺度上的组织。为确保OpenACC实现的正确性我们比较了CPU和GPU实现的模型输出。由于系统的混沌性质舍入误差会迅速导致不同的模拟轨迹。因此我们基于空间和时间平均统计数据进行比较这些数据应该保持接近。结果显示对于一阶和二阶统计量湍流动能GPU和CPU输出表现出极好的一致性仅在降水平均液滴直径上观察到局部最大相对差异约3%。5.2 单节点性能我们在荷兰国家超级计算机Snellius上比较了不同GPU硬件的性能CPU节点192个AMD Genoa 9654核心GPU节点4个NVIDIA A100GPU节点4个NVIDIA H100测试调整了水平方向的网格点数以适应不同的MPI空间域分区确保填充GPU内存。性能测量在模型时间10分钟的短模拟中进行仅包括时间步进循环中花费的时间实验重复5次。结果显示在节点基础上DALES在A100上的整体加速比约为4倍在H100上约为11.5倍。各代码组件的耗时比例保持接近其CPU值除了A100上的泊松求解器性能低于平均水平加速比接近2。进一步测试表明这与NVHPC 24.5CUDA 12.1.1中的cuFFT求解器效率较低有关。5.3 弱扩展性分析为了评估DALES随研究需求扩展的能力A100案例从1个GPU扩展到64个GPU0.25到16个计算节点利用测试案例的周期性在水平方向复制初始数据以保持每个GPU的工作量不变。结果显示DALES的并行效率下降较快主要由泊松求解器的较差扩展性能驱动而其他组件由于几乎不需要通信保持接近1的效率。值得注意的是本研究未考虑强扩展因为加速的目标是处理更大的空间域而非缩短现有问题的计算时间。6. 内核优化与自动调优6.1 内核调优的必要性第2.3节介绍的加速策略能够快速加速整个代码库在核启动参数方面给予编译器完全自由并确保相对良好的可移植性。然而少量内核表现出低占用率(50%)需要更仔细的考虑。我们采用两种策略来提高这些内核的性能手动修改内核以改善内存访问、缓存使用和寄存器压力使用Kernel Tuner(KT)自动调整内核启动参数6.2 Kernel Tuner简介Kernel Tuner(KT)是一个通用的GPU应用程序自动调优框架用Python编写支持调优用CUDA、HIP和OpenCL编写的计算内核最近还扩展到处理基于指令的语言如OpenACC和OpenMP。KT提供了一组辅助函数允许用户从代码其余部分提取可调优内核以及所有必要的C预处理器宏并负责所用数据结构的分配和初始化。用户通过向源代码添加特定的KT编译指示来指导可调优内核的选择和数据结构的识别这些编译指示是对原始代码的唯一必要更改。6.3 目标内核优化优化的计算内核是平流和次网格尺度扩散算子中的基于模板的内核。这些内核合计占总计算时间的20%。特别是标量次网格扩散内核diffcsv类似于列表2但包括标量的外部循环和4维Fortran数组和sources内核评估交叉导数并显著重用相邻数据是优化的主要目标。手动优化diffcsv内核采用了三种策略使用cache指令将各向异性网格间距数据加载到软件管理的缓存中而非多次读取1D数组内核分裂以减少寄存器压力从108降到6256用ijk collapse循环和n sequential循环替换ijkn collapse循环结果显示结合策略1和3次网格模块的整体性能可提高近5%。而通过分裂长内核来减少寄存器压力导致性能下降因为生成的内核实际上是顺序运行的。使用KT对diffcsv内核进行自动调优在A100上实现了最高35%的性能提升n10的情况在H100上仅获得最高10%的提升。有趣的是H100上的时间分布不是A100的简单平移两台GPU的最佳参数集略有不同。然而在H100上获得最佳性能的参数在A100上也能获得接近最佳的性能差距在5%以内反之亦然。对于sources内核当仅使用collapse子句时KT未能找到比默认参数更好的启动参数。转而使用tile(tx,ty,tz)子句和手动分块两种方法。结果显示使用OpenACC tile在A100和H100上都获得了最高15%的性能提升最佳性能使用tx64、ty4和tz2获得。相比之下手动引入分块最多导致性能小幅下降大多数情况下性能更差。7. 实际应用建议7.1 移植策略选择对于类似DALES的大型传统科学计算代码我们推荐采用渐进式的GPU移植策略首先使用OpenACC指令实现基础版本利用编译器的自动优化能力通过性能分析识别热点内核对关键内核进行针对性优化包括数据局部性优化循环结构调整使用高级OpenACC特性如cache、tile等考虑使用自动调优工具如Kernel Tuner寻找最优参数7.2 性能优化技巧基于DALES项目的经验我们总结了以下性能优化建议内存管理现代GPU具有足够的内存容量建议采用镜像策略一次性将所需数据传输到GPU减少主机与设备间的数据传输循环优化优先使用collapse暴露最大并行度对于存在条件分支的循环考虑分离特殊条件到独立内核对于存在垂直依赖的循环使用原子操作或临时数组内核融合将连续独立的内核融合减少内核启动开销外部库使用优先选择已有GPU支持的库注意内存布局兼容性7.3 多GPU扩展建议对于需要多GPU扩展的应用我们建议首先优化单GPU性能确保每个GPU的计算效率最大化分析通信模式识别瓶颈如DALES中的泊松求解器考虑采用混合并行策略结合MPI和OpenACC对于弱扩展场景确保每个GPU的工作负载均衡8. 总结与展望通过OpenACC指令集实现的DALES GPU加速项目展示了传统Fortran科学计算代码在现代GPU架构上获得显著性能提升的可行路径。在不完全重写代码的情况下我们在NVIDIA A100上实现了约4倍的加速在更新的H100上实现了11.5倍的加速。这一成果使得研究人员能够在相同时间内模拟更大的空间域或更高分辨率的大气过程为大气科学研究提供了更强大的工具。特别值得注意的是自动调优工具如Kernel Tuner在优化特定内核方面表现出色特别是在较旧的A100架构上可实现最高35%的额外性能提升。然而随着GPU架构的演进如从A100到H100自动优化的收益有所降低这可能表明新一代GPU的编译器优化已经相当成熟。未来工作可以集中在以下几个方向改进多GPU扩展性能特别是泊松求解器的通信模式探索更多内核优化机会特别是内存访问模式的进一步优化将经验应用到其他大气和气候模型中评估在新一代GPU架构如NVIDIA Blackwell上的性能表现从工程实践角度看DALES项目证实了OpenACC作为传统科学代码GPU移植工具的价值它平衡了实现工作量和性能收益使研究团队能够在不完全重写代码库的情况下利用现代GPU的计算能力。这一经验对于众多类似规模和历史代码库的科学计算项目具有重要参考价值。