在使用OpenMPI时将C模块链接到Fortran程序:malloc会导致段错误而不是null



我有一个使用MPI的古老而混乱的Fortran程序。它有一个用C编写的小模块,它试图通过迭代调用malloc()来确定内存中最大的可分配块,直到它返回null,然后将最大的成功分配大小返回给Fortran程序。

当我使用 gfortran 编译它时,它运行良好,但是当我尝试使用 mpif90 时,最后一个malloc()会导致段错误而不是返回null

下面是没有实际 MPI 代码的最小说明性示例。文件main.f

program test
    complex(8) :: sig(256000000) ! Just allocating some big array in fortran
    sig(1) = 0.d0                ! and now wondering how much space is left?
    call bigalloc
end

文件bigalloc.c

#include <stdlib.h>
#include <stdio.h>
void bigalloc_() {
    size_t step = 0x80000000;
    size_t size = 0;
    int failed = 0;
    void* p;
    do {
        size += step;
        p = malloc(size);
        if (p) {
            free(p);
            printf("Allocated %zd...n", size);
        } else {
            printf("So, that's our limitn");
            failed = 1;
        }
    } while (!failed);
}

仅使用gfortran编译和运行(按预期工作(:

~$ gcc -c bigalloc.c -o bigalloc.o && gfortran -o main main.f bigalloc.o && ./main
Allocated 2147483648...
Allocated 4294967296...
So, that's our limit

使用 MPI 编译并运行(失败(:

~$ gcc -c bigalloc.c -o bigalloc.o && mpif90 -o main main.f bigalloc.o && ./main
Allocated 2147483648...
Allocated 4294967296...
Segmentation fault

mpicc替换gcc在这里没有任何变化。当main也是用 C 编写并使用 mpicc 编译时,一切也正常。所以问题只出在Fortran上。

mpif90 -show的输出在这里。问题完全取决于-lopen-pal选项的存在。

$ mpif90 -show
gfortran -I/usr/include/openmpi/1.2.4-gcc/64 -I/usr/include/openmpi/1.2.4-gcc -m64 -pthread -I/usr/lib64/openmpi/1.2.4-gcc -L/usr/lib64/openmpi/1.2.4-gcc -lmpi_f90 -lmpi_f77 -lmpi -lopen-rte -lopen-pal -ldl -Wl,--export-dynamic -lnsl -lutil -lm -ldl

似乎在链接 MPI 时,将标准malloc替换为 PAL 中自己的标准,这在异常情况下无法正常工作。有没有办法绕过它(例如,以某种方式将我的bigalloc.c与静态glibc联系起来(?

Open MPI 通过glibc提供的挂钩机制拦截malloc()free()调用,以便它可以跟踪动态分配和解除分配的缓冲区。这样做是因为基于RDMA的网络(如InfiniBand(要求将通信缓冲区固定在物理内存中(即不可移动(,以便硬件可以访问它们。注册和取消注册内存(固定和取消固定它的过程(需要相当长的时间,这就是为什么库根本不取消固定已经固定的内存,希望它会被重用(这就是为什么动态分配每个通信缓冲区不仅仅是非常糟糕的主意(。但是,如果动态分配内存,然后注册然后解除分配,这可能会导致问题。这就是 Open MPI 挂钩malloc/free API 并跟踪动态分配的原因。Open MPI 还可以使用 MMU 通知跟踪内存,前提是硬件支持内存并且库已相应地构建。

内存挂钩,至少在较新的 Open MPI 版本中,可以通过将 memory_linux_disable MCA 参数设置为 1 来禁用。与所有其他MCA变量不同,这个变量只能通过环境设置,例如,必须设置环境变量OMPI_MCA_memory_linux_disable才能1并导出它。如果程序将在具有InfiniBand或其他基于RDMA的网络的集群上运行,请不要这样做!不幸的是,您正在运行无法识别此 MCA 参数的古老版本的 Open MPI,并且memory_hooks模块似乎没有提供可以禁用它的机制。您确实应该在Open MPI用户邮件列表中询问。

另请注意,Linux 内核默认过度使用内存,即它们允许超过物理内存大小的虚拟内存分配。最终结果是,malloc()使用比可用物理内存大小大得多的内存大小会成功,但是如果您(或任何 Open MPI 挂钩过程(尝试使用该内存,则在某些时候物理内存将耗尽,并且进程将收到SIGSEGV

相关内容

  • 没有找到相关文章

最新更新