Fortran OpenMP+OpenACC混合并行出现Segmentation Fault问题求助
问题详情
使用NVIDIA HPC SDK编译器将CAMB(宇宙学玻尔兹曼代码)移植为OpenMP+OpenACC混合CPU+GPU并行版本时,出现以下异常:
- 单独使用OpenMP、单独使用OpenACC或不添加任何并行编译选项时,代码运行正常;
- 同时启用OpenMP和OpenACC编译时,在特定
!$OMP PARALLEL SECTIONS代码块触发Segmentation Fault。
崩溃代码块结构:
[A lot of code] !$OMP PARALLEL SECTIONS DEFAULT(SHARED) !$OMP SECTION call CP%Recomb%Init(State, WantTSpin=CP%Do21cm) !$OMP SECTION ! Other background calculations ! Additional work... !$OMP END PARALLEL SECTIONS [A lot of code]
崩溃位置固定在调用链 dtauda() <-- ion() <-- dverk() <-- trecfast_init() 中,随机触发于以下两行之一:
grhoa2 = this%grho_no_de(a) + grhov_t * a**2
或
CAMBdata_TimeOfz = this%DeltaTime(0._dl, 1._dl/(z+1._dl), tol)
环境信息
- 硬件:12th Gen Intel(R) Core(TM) i9-12900KF、NVIDIA T400 4GB
- 编译器:NVIDIA HPC SDK
已尝试的排查动作
- 调整OMP并行区域的位置
- 使用OMP
CRITICAL/TASK指令替代SECTIONS - 减少OMP并发线程数
排查建议
检查OpenACC数据环境与OpenMP线程的冲突
OpenACC会管理设备(GPU)和主机(CPU)的数据区域,当OpenMP线程进入被OpenACC修饰的函数时,可能存在数据作用域冲突。比如CP%Recomb对象的成员变量是否被OpenACC标记为copyin/copyout,但在OpenMP并行线程中被跨线程访问?可以尝试:- 在
CP%Recomb%Init调用前,用!$ACC ENTER DATA或!$ACC UPDATE显式同步相关数据; - 在OMP SECTION中用
!$ACC SERIAL包裹CP%Recomb%Init调用,强制该段在CPU执行,排除GPU数据交互的影响。
- 在
定位隐式共享数据的竞态条件
当前OMP区域使用DEFAULT(SHARED),会让所有变量默认在线程间共享。检查CP、State等全局/模块变量,尤其是this%grho_no_de、this%DeltaTime依赖的成员,是否在另一个OMP SECTION的后台计算中被修改?建议将DEFAULT(SHARED)改为DEFAULT(NONE),显式声明每个变量的作用域,强制排查未显式声明的共享变量,避免隐式竞态。排查编译选项的交互冲突
同时启用OpenMP和OpenACC时,编译器的激进优化可能引发问题。尝试:- 拆分优化选项,比如用
-O2 -mp -acc替代-fast这类复合优化选项; - 添加
-gpu=debug开启GPU调试信息,查看是否有数据越界、未初始化设备内存的提示; - 测试
-acc=host选项(强制OpenACC在CPU执行),对比混合编译时的行为差异。
- 拆分优化选项,比如用
用调试工具定位内存问题
- 结合
gdb与cuda-gdb调试:在OMP并行区域设置断点,崩溃时查看当前线程的调用栈,以及this指针的有效性——若this为野指针,说明CP%Recomb对象在并行线程中被错误访问; - 用
valgrind检查CPU内存是否存在越界、非法访问(需设置OMP_PROC_BIND=false避免绑定冲突); - 用
nvprof分析GPU内存的访问情况,排查设备端的内存问题。
- 结合
隔离OpenACC代码路径
暂时注释掉CP%Recomb%Init中所有OpenACC指令,只保留CPU逻辑,验证混合编译是否仍崩溃。若不再崩溃,说明问题出在OpenACC数据管理与OpenMP线程的交互上,再逐步恢复OpenACC指令,定位具体冲突点。
内容的提问来源于stack exchange,提问作者Sbomba Sbomba

