mod_phys_lmdz_omp_transfert

路径

LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\mod_phys_lmdz_omp_transfert.F90

职责

mod_phys_lmdz_omp_transfert 是物理侧 OpenMP 线程内 transfer 模块。它不做跨 MPI rank 通信,而是在同一个 MPI rank 内把 master 线程持有的 rank 级数据广播给各 OpenMP 线程,或在 klon_mpi rank 列和 klon_omp 线程局部列之间 scatter/gather,并提供线程内求和 reduction。

在完整物理并行层中,调用方通常使用 mod_phys_lmdz_transfert_parabcast/scatter/gather/reduce_sum 泛型;该 wrapper 先处理 MPI 层,再调用本模块完成 OMP 层分发或汇集。底层逐过程细节见 phys-transfer-omp-core

公开接口和过程清单

模块默认 PRIVATE,只公开:

PUBLIC bcast_omp, scatter_omp, gather_omp, reduce_sum_omp, omp_barrier
泛型接口 specific procedures 类型和维度 引擎
bcast_omp 22 character scalar;integer/real/logical scalar 到 6D bcast_omp_cgen, bcast_omp_igen, bcast_omp_rgen, bcast_omp_lgen
scatter_omp 12 integer/real/logical rank 列数组到 4D wrapper scatter_omp_igen, scatter_omp_rgen, scatter_omp_lgen
gather_omp 12 integer/real/logical thread 列数组到 4D wrapper gather_omp_igen, gather_omp_rgen, gather_omp_lgen
reduce_sum_omp 10 integer/real scalar 到 4D reduce_sum_omp_igen, reduce_sum_omp_rgen
omp_barrier 1 无参数同步工具 直接 !$OMP BARRIER

总计:56 个公开泛型 specific procedures、12 个内部引擎子程序、3 个 check_buffer_* helper 和 1 个 omp_barrier

模块状态

符号 类型 生命周期 用途
grow_factor=1.5 REAL, PARAMETER 编译期常量 动态 buffer 扩容比例。
size_min=1024 INTEGER, PARAMETER 编译期常量 最小 buffer 长度。
buffer_c CHARACTER(LEN=size_min), SAVE 模块级共享 character broadcast 固定缓冲。
buffer_i, buffer_r, buffer_l allocatable SAVE 数组 模块级共享 integer/real/logical transfer 和 reduction 的共享缓冲。
size_i, size_r, size_l INTEGER, SAVE 模块级共享 当前已分配 buffer 长度。

这些 buffer 不是 THREADPRIVATE。它们依赖 OpenMP barrier、master/single 和 critical 区保证所有线程看到一致的共享状态。

动态 buffer 约定

check_buffer_icheck_buffer_r 的模式是:

  1. 所有线程先进入 !$OMP BARRIER
  2. !$OMP MASTER 判断 buff_size > size_* 时释放旧 buffer。
  3. 新长度取 MAX(size_min, INT(grow_factor*buff_size))
  4. 再经过一个 !$OMP BARRIER,确保后续 transfer 引擎看到已分配 buffer。

check_buffer_l 的逻辑相同,但用 !$OMP SINGLE 替代 MASTER。源码注释说明调试中发现即便有前后 barrier,MASTER 分配 logical buffer 后仍可能被其他线程过早使用;SINGLE 行为更可靠。

character broadcast 不调用 check_buffer_*,只使用固定长度 buffer_c。因此 character 路径适合短配置字符串;若调用方传入超出固定 buffer 的字符串,需要单独确认编译器行为和实际调用长度。

数据分布依赖

scatter/gather 引擎在子程序内部使用:

来源模块 符号 作用
mod_phys_lmdz_omp_data klon_omp 当前 OpenMP 线程负责的物理列数。
mod_phys_lmdz_omp_data klon_omp_begin 当前线程在 rank 内物理列段的 1-based 起点。
mod_phys_lmdz_mpi_data klon_mpi 当前 MPI rank 持有的物理列数。

由此形成固定形状约定:

scatter_omp: VarIn(klon_mpi, dimsize) -> VarOut(klon_omp, dimsize)
gather_omp : VarIn(klon_omp, dimsize) -> VarOut(klon_mpi, dimsize)

dimsize 由 wrapper 把除第一维之外的维度展平得到。第一维必须是物理列维,不能把 level/tracer/time 维放在第一维。

运行流程

bcast_omp

bcast_omp_*gen 采用 master 写、所有线程读的两段 barrier 模式:

  1. master 线程把 Var 写入共享 buffer。
  2. barrier 后每个线程从 buffer 写回自己的 Var
  3. 第二个 barrier 确保所有线程完成读取。

integer/real/logical scalar wrapper 先用长度为 1 的临时数组包装,再进入数组引擎。5D/6D broadcast 只存在于 bcast_omp,是 COMMON transfer 高维配置广播的重要支撑。

scatter_omp

scatter 将 rank 级数组切给各线程:

  1. master 将 VarIn(1:klon_mpi, :) 拷入共享 buffer。
  2. barrier 后每个线程根据 klon_omp_begin-1+ij 读取自己的列段。
  3. 第二个 barrier 结束本次分发。

这一路径要求 Init_phys_lmdz_omp_data 已经在 OpenMP parallel 区内完成,使每个线程拥有正确的 klon_ompklon_omp_begin

gather_omp

integer/logical gather 与 scatter 对称:所有线程先把 VarIn(1:klon_omp, :) 写入 buffer 的 rank 级偏移位置,barrier 后 master 拷出到 VarOut(1:klon_mpi, :)

real gather 是例外:gather_omp_rgen 不用 buffer_r,而是让 master 把 Varout_ptr => VarOut,barrier 后所有线程通过 shared pointer 直接写入 rank 级输出数组。VarOut 因此带 TARGET 属性;Varout_ptrSAVE pointer,源码注释明确它在线程间共享且不是 THREADPRIVATE

reduce_sum_omp

reduce_sum_omp_igen/rgen 使用共享 buffer 和 !$OMP CRITICAL

  1. master 清零 Buff(:)
  2. barrier 后各线程进入 critical 区,把本线程 VarIn 累加到 buffer。
  3. barrier 后 master 把 buffer 写入 VarOut
  4. 最后一个 barrier 保证输出对所有线程同步。

该实现偏保守,保证互斥累加;代价是 reduction 阶段串行化,性能热点需要结合调用频率判断。

OMP 指令语义

指令 本模块用途
!$OMP BARRIER transfer 阶段边界、buffer 分配前后、指针关联后和输出完成后同步。
!$OMP MASTER 由 master 写 bcast/scatter buffer、读 gather buffer、清零/写回 reduce buffer。
!$OMP SINGLE logical buffer 分配,规避注释中记录的 MASTER 可见性问题。
!$OMP CRITICAL reduction 累加互斥。

非 OpenMP 编译时,指令作为注释被忽略。此时模块仍可编译,但语义等价于单线程路径;不要把非 OMP 构建下的结果误解为线程同步已被验证。

调用关系

方向 关系
上游调用 phys-transfer-para-wrapperbcast/scatter/gather/reduce_sum 在 OMP 层调用本模块;物理 getin、初始化和 physics wrapper 通常通过该上层泛型间接经过。
支撑数据 omp-data-transfer 说明 mod_phys_lmdz_omp_data 的线程列分布;本模块只使用其 klon_omp/klon_omp_begin 状态。
MPI 配合 mpi-data-transfer 处理 rank 间通信;本模块只处理 rank 内线程间搬运。
高维支持 parallel-transfer-6d 记录 5D/6D broadcast 和 OMP buffer/race 修复。

I/O、配置和副作用

Mars 运行参与度

条件经过:Mars/COMMON 物理侧启用 OpenMP 物理并行时经过。

典型路径是 physics 初始化或物理参数读取通过 mod_phys_lmdz_transfert_para 的泛型进入本模块。calfis_p 的部分动力-物理场搬运有手写循环,不直接调用本模块;这一区别见 calfis-p-parallel-transfer

复现和排错顺序

  1. 确认是否在 OpenMP parallel 区内调用;否则 klon_omp/klon_omp_begin 可能只是单线程状态。
  2. 确认第一维是物理列维:scatter 输入首维为 klon_mpi,scatter 输出首维为 klon_omp;gather 反向。
  3. 对 buffer 问题,先查 buff_size、当前 size_* 和是否经历了 check_buffer_* 的前后 barrier。
  4. 对 logical transfer 竞态,优先确认是否使用 当前 check_buffer_l SINGLE 版本。
  5. 对 real gather 差异,查 VarOut TARGETVarout_ptr 直接写入,而不是查 buffer_r
  6. 对高维配置广播,确认 bcast_omp_i5/i6bcast_omp_r5/r6bcast_omp_l5/l6 已进入泛型接口。

待确认

相关页面