准确预报各种天气:英特尔五步框架帮助实现代码现代化

天气预报是现代生活的一个重要方面,它可在出现恶劣天气状况时即时发出警报,从而帮助有效制定计划和安排物流,并可保护生命财产安全。 但是,准确预测长期的天气情况非常复杂,通常涉及到大量数据集,并且要求对代码进行优化以利用最高级的计算机硬件功能。

创建高性能现代代码的部分挑战来自于全面收集问题域的信息和相关数据集,进而实现并行优化。 开发人员还需要检验现有应用流程和代码,以充分利用系统内的并行硬件资源。

以此为目标,英特尔定义了一个包含五个阶段的多层并行代码现代化框架,为软件开发人员提高应用性能提供了一个系统的方法。 在本案例研究中,我们重点介绍了与矢量化、线程并行性和 I/O 吞吐量最大化相关的代码优化,以及将其应用到“天气研究和预报”模型中的情况,并突出介绍了英特尔® VTune™ 放大器、英特尔® Advisor XE 和英特尔® 至强™ 处理器的重要功能。

从“天气研究和预测”模型中获得的经验教训

现代天气预报主要依赖于数值天气预报系统,这些系统可对大气和海洋的数学模型进行计算机模拟操作。 其中一个主要系统是天气研究和预报 (WRF) 模型,该模型是一款开源解决方案,为全球广泛采用,可用来进行大气研究和日常作业预报。 WRF 模型始建于 20 世纪 90 年代末,随后历经更新,现为全球 150 多个国家的 30,000 个注册用户提供服务。

WRF 模型依据物理学、流体力学和化学定律使用偏微分方程系统进行计算,并将地球划分为三维网格。 这让系统模型与大气条件的交互范围从几十米扩大到数千公里。

问题域的性质使得数值天气预报成为通过并行性和使用其他高级技术实现代码现代化的理想选择。 在本文中,我们重点介绍了英特尔技术如何帮助将最常见的现代化方法应用到 WRF 模型中,并阐释了软件开发人员如何使用类似的方法更广泛地优化更多软件应用。

明确潜在优化

现代高性能处理器采用多种资源,包括多核架构、矢量处理功能、高速缓存和高带宽 I/O 通信。 构建可充分利用这些特性的软件能够让应用更高效地运行,从而能够处理更大的数据集。 这使得之前费用过高或甚至不可能实现的操作和分析得以实现。

英特尔五步代码现代化框架建议开发人员:

  • 使用高级优化工具来描述代码和确认矢量化和线程机会。 在找到潜在热点后,使用一流的编译器和优化的函数库来生成最高效的代码。
  • 确保代码使用足够的精度、类型常量和最佳配置设置,以优化标量和串行操作。
  • 尽可能使用矢量,即在处理器架构中使用多数据 (SIMD) 特性。
  • 执行线程并行化和分析线程扩展可帮助发现线程同步问题或低效的内存访问。
  • 使用分布式内存队列并行化将应用从多核扩展为众核,尤其在应用添加到高度并行的实施中时更应如此操作。

注:关于该五步框架的详细信息,请参阅什么是代码现代化?

应用分析

代码现代化的第一步是分析工作负载,确认要优化代码的候选位置。 借助英特尔® VTune™ 放大器,您可以查看 CPU 性能、线程性能、带宽利用率、高速缓存效率等。 该工具能够以更高级的线程模型来展示信息,从而能够更轻松地阐释结果。

当您准备好进行矢量化和线程化操作时,英特尔® Advisor XE 可帮助确认需要特别关注的循环。 研究表明,进行了矢量化线程化的代码的性能是传统代码的 175 倍或更高,约为仅进行线程化矢量化的代码的 7 倍。

英特尔® Advisor XE 还可帮助发现可能会对矢量化产生影响的内存访问模式,以及包含对矢量化产生阻拦作用的依赖性的循环。

WRF 的模块化架构可帮助进行高级分析,提供自然边界,帮助发现更重要的代码段。 借助手动检查源代码、汇编代码和编译器报告的功能,开发人员可以进一步确定无法自动矢量化并需要更新至原始指令才能够获益的代码段。

利用矢量化

分析完应用后,代码现代化的下一步是对代码进行矢量化处理。 代码进行矢量化后,单个计算指令可以在一维数据数组(即矢量)上同时运行。 一般情况下,这些标量数据通常包括整数和单精度和双精度浮点值。

矢量计算尤其适合应用需要在大型数据集上执行统一运算的情况。 这可显著提升英特尔® 集成众核架构处理器(如英特尔® 至强融核™ 协处理器)的性能。 在 WRF 模型中,矢量化允许将相同的指令同时运用到多个数据元素上,这对于以 stepwise 的方式处理不断变化的大气状况至关重要。

循环是开始进行矢量化的合适位置,英特尔编译器非常擅长内部循环自动矢量化。 但是,您可以让编译器生成矢量化报告。 这可以帮助确认应用中编译器无法进行自动矢量化的位置。 此时,编译器的编译指示和指令可以帮助编译器进行矢量化。

在整个过程中,您还需要确保应用内的控制流不发生意外偏离。 控制数据调整对于优化数据访问和 SIMD 处理器而言都非常重要。

例如,考虑 WRF 模型中的以下代码段:

#pragma simd
DO i=i_start, i_end
   ph_low = ...
   flux_out =   max(0.,fqx (i+1,k,j))-min(0.,fqx (i  ,k,j)) )...
   IF( flux_out .gt. ph_low ) THEN
      scale = max(0.,ph_low/(flux_out+eps))
      IF( fqx (i+1,k,j) .gt. 0.) fqx(i+1,k,j) = scale*fqx(i+1,k,j)
      IF( fqx (i  ,k,j) .lt. 0.) fqx(i  ,k,j) = scale*fqx(i  ,k,j)
   END IF
ENDDO

在本案例中,循环会建议使用能够防止自动矢量化的流和输出依赖性。 这是一个容易证明的实践,事实上,IF 条件意味着没有依赖性,添加 simd 编译提示支持编译器对循环进行矢量化,从而提高矢量化的性能。

WRF 模型可进一步采用以下优化:

优化总结
runscripts至强融核上的亲和性优化,可极大改进负载平衡,并支持大幅减少队列数量。
advect_scalar_pd ysu2d通过添加 SIMD 编译提示和调整指令显著提升矢量化性能。
w_damp删除了异常情况下的某些信息,但仍然对异常状况进行标记,从而提升了矢量化。 通过循环外提 (un-switching) 可能能够获得更出色的矢量化。
WSM5通过调用到 WSM5 中复制到 statically-sized thread-local 贴图阵列内外并进行安排,以便对值进行调整,并使其以 SIMD 宽度(16 字)的数据块组合。 此外,由于条件表达式的原因,重新构建的循环未进行矢量化。
编译指示WRF 代码中的许多循环都从 SIMD/IVDEP 和其他编译指示中获得了优势。

下表展示了采用优化代码前后,面向至强融核进行调整的配置文件:

英特尔® 至强融核™ 协处理器(优化前)
函数应用百分比
OMPTB::TreeBarrierNGO::exitBarrier0.00%
advect_scalar_pd_21.43%
w_damp_13.04%
ysu2d_5.18%
nislfv_rain_plm_5.15%
advance_uv_3.84%
wsm52d_3.62%
advect_scalar_3.29%
set_physical_bc3d_3.19%
advance_w_2.91%
advance_mu_t_2.37%
advect_w_2.02%
OMPTB::TreeBarrier::enterBarrier0.00%
pbl_driver_1.81%
rk_update_scalar_1.55%
horizontal_pressure_gradient_1.46%
rrtm_1.44%
cal_deform_and_div_1.27%
英特尔® 至强融核™ 协处理器(优化后)
函数应用百分比
OMPTB::TreeBarrierNGO::exitBarrier0.00%
advect_scalar_pd7.73%
advance_uv5.81%
advect_scalar5.40%
advance_w4.50%
ysu2d4.03%
advance_mu_t3.64%
nislfv_rain_plm3.14%
rk_update_scalar2.97%
zero_tend2.63%
calc_p_rho2.35%
Rtrn2.32%
wsm52d2.29%
pbl_driver2.28%
cal_deform_and_div2.27%
[vmlinux]0.00%
small_step_prep2.18%
phy_prep2.15%

通过线程并行化进行优化

WRF 模型包含多个模块、功能和程序,它们分别关注天气预报的不同方面,包括风、热传递、太阳辐射、相对湿度和地表水文学等。 这支持使用其他层的优化,即线程并行化,将一个线程的特定任务上的线程作业进行整合,并通过共享内存进行通信。

由于阿姆达尔定律(即并行程序的加速受连续部分的限制),线程并行化最适合用于外层。 这表示,每个线程需要尽可能多地处理任务。 它还表示,您需要让线程并行化程度与目标硬件的内核数匹配,使用过多或过少并行化都可能由于开销问题而影响性能提升。

对于 WRF 模型,OpenMP* (共享存储并行程序)可提供有效的方法。 OpenMP 是一个应用编程接口 (API),支持使用 FORTRAN* 和其他语言进行多平台、共享内存多处理。 OpenMP 的工作原理是使用一个主线程,叉接一系列从线程,然后这些从线程在多个处理器上并行、独立运行。

OpenMP 包括一系列编译器指令、函数库程序和环境变量。 在 WRF 模型中,使用预处理器指令来确认要并行运行的代码段。 当代码并行化完成后,线程会返回主线程,继续像往常一样运行。 借助 OpenMP 模型,WRF 模型能够以最低的开销实现任务和数据的并行化。

WRF 模型还可使用消息传递接口 (MPI)/ OpenMP* 分解,在两个层面:补丁和贴图上运行。 对于补丁而言,Conus12 包含一个 425x300 的范围,划分为多个长方形的块,再分配给 MPI 进程。 补丁可以进一步划分为贴图,这些贴图可以分配给进程内的共享内存线程 (OpenMP)。 贴图在整个 X 维度扩展,然后从 Y 维度上再次划分。 例如,如果采用每补丁 80 x 50 的网格点,那么 X 便是 80,Y 是 50。 对于每队列 3 个 OpenMP,补丁将会再次划分为 3 个贴图: 80x17、80x17、80x16。

这些贴图可在 namelist.inut 指定为 “numtiles” 或使用环境变量(WRF_NUM_TIMES、WRF_NUM_TILES_X 和 WRF_NUM_TILES_Y)。 下图展示了分解的 WRF 模型:

这导致英特尔® 至强融核™ / 英特尔® 至强™ 上呈现如下 WRF.conus12km 布局:

WRF 模型中的 OpenMP 开销(即执行 OpenMP 任务耗费的运行时)可忽略不计,原因如下:

  • 有近 20000 个 fork-join,未使用其他 OpenMP
  • 每 fork-join 有近 50000 个时钟(高)
  • 总共不到 1 秒钟的时间内仅使用 10e8 时钟,不到 1%

请注意,如果添加其他的 MPI 队列,开销可能将会显著增加,其可转换为较小的每队列工作负载。

另一个并行性优化集中在 surface_driver。 考虑一下下面的 init 代码:

! 3d arrays
v_phytmp = 0.
u_phytmp = 0.
! Some 2d arrays

This code was parallelized to the following:

!$OMP PARALLEL DO &
!$OMP PRIVATE (ij, i, j, k)  
DO ij = 1,num_tiles    
   do j = j_start(ij),j_end(ij)    
   do k = kms,kme    
   do i = i_start(ij),i_end(ij)      
   v_phytmp(i, k, j) = 0      
   u_phytmp(i, k, j) = 0

实施这些变更可将串行时间减少到低于采样分辨率(效果为 0)。

数据带宽注意事项

对于数据密集型问题(如 WRF 模型),如果应用尝试使用的带宽高于可提供的量,那么系统就会受到带宽的影响。 当使用高带宽处理器(如英特尔至强融核协处理器)时,其受到的影响较小,但是仍然值得开发人员注意。

另一个要注意的方面是确保数据符合处理器的二级高速缓存,最大限度减少访问主内存的需求,因为这一需求会对性能产生很大的影响。 这可能需要您使用高速缓存分块技术,将较大数据集的子集加载到高速缓存中,并充分利用应用内在的数据重复使用操作。

通过配置实现最佳性能

大家经常会忽略要正确设置相关配置文件和环境变量的需求,但是这一需求对于实现最佳应用性能而言非常有必要。 这可能包括为英特尔® MPI 函数库和英特尔® 编译器提供环境,启动较大文件 I/O 支持,以及将英特尔® 至强融核™ 协处理器堆栈尺寸设置为足够大的值,以防止出现分段故障。

设置正确的编译器选项对于应用性能而言同样至关重要。 面向英特尔至强处理器和英特尔至强融核协处理器构建 WRF 模型,例如,添加以下选项:

  • -mmic: 构建一个可以在英特尔® 至强融核协处理器本地运行的应用程序
  • –openmp: 支持编译器根据 OpenMP* 指令生成多线程代码(与 -fopenmp 相同)
  • -O3: 支持强制优化编译器
  • -opt-streaming-stores always: 生成流存储
  • -fimf-precision=low: 通过低精度实现更高的性能
  • -fimf-domain-exclusion=15: 为单精度和双精度提供最低的精度序列
  • -opt-streaming-cache-evict=0: 关闭所有的高速缓存块清除

英特尔使用英特尔至强融核协处理器通过以下运行时参数发现了更多优化:

  • 据测定,在英特尔至强融核上使用平衡的亲和性可以达到最好的效果。
  • 最佳的贴图方式是内核在 Y 轴上,线程在 X 轴上。
  • 让内核分布在 X 轴上可以提高高速缓存的命中率。
  • 使用新的环境变量,如 WRF_NUM_TILES_X (每核线程数)和 WRF_NUM_TILES_Y (内核数)。 例如,60 个内核,每内核 3 个线程: X=3,Y=60。

下图展示了英特尔至强融核协处理器上的紧凑 (compact)、分散 (scatter) 和平衡 (balanced) 亲和性之间的区别:

结论

一流的高性能处理器,如英特尔至强和英特尔至强融核协处理器,可提供多种功能帮助实现多层并行代码现代化。 这可为开发人员提供多种选项,助其交付出色的应用性能,并支持应用进行扩展和提供强大能力。

如 WRF 模型所示,使用分步实施的方法逐步分析应用,并解决矢量、线程并行化和数据带宽等主要领域的问题可确保为当今和未来提供最佳效果。

更多信息

了解关于“天气研究和预报模型”的更多信息:www.wrf-model.org

阅读什么是代码现代化?一文:software.intel.com/zh-cn/articles/what-is-code-modernization

阅读关于矢量化要素的更多信息: software.intel.com/zh-cn/articles/vectorization-essential

英特尔® 至强融核™ 协处理器和英特尔® 至强™ 处理器上的 WRF Conus12km 中了解更多信息:software.intel.com/zh-cn/articles/wrf-conus12km-on-intel-xeon-phi-coprocessors-and-intel-xeon-processors

对称模式下英特尔® 至强融核™ 协处理器和英特尔® 至强™ 处理器上的 WRF Conus2.5km 中了解更多信息: software.intel.com/zh-cn/articles/wrf-conus25km-on-intel-xeon-phi-coprocessors-and-intel-xeon-processors-in-symmetric-mode

关于英特尔® VTune™ 放大器的更多信息,请参阅:software.intel.com/zh-cn/intel-vtune-amplifier-xe

关于英特尔® Advisor XE 的更多信息,请参阅:software.intel.com/zh-cn/intel-advisor-xe

*其他的名称和品牌可能是其他所有者的资产。

有关编译器优化的更完整信息,请参阅优化通知