提问人:H. Weirauch 提问时间:11/15/2023 更新时间:11/15/2023 访问量:73
将 FP 异常陷阱 (-ffpe-trap/-fpe0) 用于链接到 SIGFPE 不安全库 (libxml2) 的代码
Use FP exception traps (-ffpe-trap/-fpe0) for code linked against SIGFPE-unsafe library (libxml2)
问:
我有 Fortran 代码,我想为此启用浮点异常捕获(按照编译器手册页的建议)。但是当我这样做时,二进制文件将不再在 Slurm 队列中运行。
问题显然位于(Slurm 的运行时依赖项,它为 MPI 运行时提供包装器,称为 )。这会触发 FPE,因此在我自己的代码有机会运行之前,执行就停止了。libxml2
MPI_Init
理想情况下,我想告诉编译器/链接器创建二进制文件,以捕获由我自己的代码创建的 FPE,但对来自外部库的 FPE 条件不敏感。
最小示例:
program mwe
use mpi_f08
integer :: ierror
call MPI_Init(ierror)
print*,"MPI_Init returned", ierror
end program
编译方式
- gfortran 作为
mpif90 -ffpe-trap=invalid,zero,overflow mwe.F90
- ifort 作为
mpifort -fpe0 mwe.F90
给我留下了一个运行良好的二进制文件
- 直接调用时:
./a.out
- 当使用并行包装器(或任何更高的数字)调用时。
mpirun -np 1
但是,当从 Slurm 批处理脚本调用或直接通过 运行时,会从堆栈下方的某个位置触发浮点异常。ifort回溯告诉我在哪里:srun ./a.out
$ srun ./a.out
forrtl: error (65): floating invalid
Image PC Routine Line Source
libc.so.6 000014609708A520 Unknown Unknown Unknown
libxml2.so.2.9.13 000014609407C723 Unknown Unknown Unknown
libxml2.so.2.9.13 0000146094054A4F xmlCheckVersion Unknown Unknown
hwloc_xml_libxml. 0000146094A100C6 Unknown Unknown Unknown
libhwloc.so.15.6. 00001460967BBF33 Unknown Unknown Unknown
libhwloc.so.15.6. 00001460967A83A9 Unknown Unknown Unknown
libopen-pal.so.40 0000146096D538FA opal_hwloc_base_g Unknown Unknown
libopen-rte.so.40 0000146096E4C630 orte_ess_base_pro Unknown Unknown
libopen-rte.so.40 0000146096E53705 Unknown Unknown Unknown
libopen-rte.so.40 0000146096EE05AD orte_init Unknown Unknown
libmpi.so.40.30.4 00001460975F2125 ompi_mpi_init Unknown Unknown
libmpi.so.40.30.4 0000146097414200 MPI_Init Unknown Unknown
libmpi_mpifh.so.4 00001460976F0D38 PMPI_Init_f08 Unknown Unknown
libmpi_usempif08. 0000146097734242 mpi_init_f08_ Unknown Unknown
ifort 000000000040B1F8 Unknown Unknown Unknown
ifort 000000000040B19D Unknown Unknown Unknown
libc.so.6 0000146097071D90 Unknown Unknown Unknown
libc.so.6 0000146097071E40 __libc_start_main Unknown Unknown
ifort 000000000040B0B5 Unknown Unknown Unknown
srun: error: localhost: task 0: Aborted
罪魁祸首在(我从 gdb 获得了 gfortran 二进制文件的相同指针)。xmlCheckVersion
libxml2
我更愿意在编译和运行时控制软件的迂腐级别,而不是在此过程中收集一些随机依赖项来限制我可以选择什么和不能选择什么。但我想没有前景让编译器/链接器将标准应用于我自己的代码,而不是在运行时应用于来自共享对象的东西?
这特别烦人,因为所谓的除以零错误的来源是 libxml2,因为大约 2.9.11 版本。只要许多主要/稳定的平台仍在 2.9 版本上(这种情况将持续很长时间),浮点陷阱对于旨在与 Slurm 一起使用的项目来说基本上是无法使用的。
由于 2.10 版本大约在两年前发布,并且它的开发人员似乎已经找到了一种更聪明的方法来处理这种情况,因此它并不完全是上游错误(在积极开发/维护的分支中),有必要说服 LTS/稳定操作系统发行商介入。libxml2
操作平台:Ubuntu 22.04 LTS、x86_64、gcc 12.2.0、OpenMPI 4.1.4、libxml2 2.9.13
(这是 Fortran 中 MPI_Init() 中 SIGFPE 的后续 - 错误的算术运算。FWIW,这个问题更侧重于根本原因,并避免了像 CMake 或 Fortran 编译器的特定选择这样的干扰。
答:
正如 francescalus 和 Ian Bush 所评论的那样,自然而然的方式是 Fortran 2003 及更高版本的标准 IEEE 异常处理。我最近的问题 为 OpenMP 线程设置 IEEE FPE 停止模式中的代码实际上几乎完全相同。它最初是为了禁用某个子例程的异常而精确派生的。
在程序启动时启用异常捕获(在 FPE 异常时停止)。很有可能,您也可以改用编译器标志,但它的可移植性较差。
use ieee_exceptions
call ieee_set_halting_mode(ieee_overflow, .true.)
call ieee_set_halting_mode(ieee_invalid, .true.)
call ieee_set_halting_mode(ieee_divide_by_zero, .true.)
在调用需要禁用 FPE 异常时停止的子例程之前
logical :: saved_fpe_mode(size(ieee_all))
call ieee_get_halting_mode(ieee_all, saved_fpe_mode)
call ieee_set_halting_mode(ieee_all, .false.)
调用子例程以恢复停止后
call ieee_set_halting_mode(ieee_all, saved_fpe_mode)
如链接的问题和答案所示,如果使用多个线程,则可能需要小心,因为停止模式可以是每个线程的本地模式。
评论