我有一个使用OpenMPI库编译时可以正常运行的程序,但是当使用MPICH 3.2.1编译时,在MPI_Allreduce()
中出现错误而失败。在Linux和MacOS上都会发生这种情况。
相关代码是
typedef struct reduction_packet {
double sig; /* logev */
double s_width; /* starting width */
double s_nsites; /* starting nsites */
double width; // width of motif
double nsites_dis; // final number of sites
double llr; // LLR of motif
double classic; // true if Classic objective function
double ID; /* Use a double so the MPI type handle is simple. */
} REDUCE_PACKET;
REDUCE_PACKET a_packet, best_packet;
...
MPI_Allreduce((void *)&a_packet, (void *)&best_packet, 1,
reduction_packet_type, max_packets_op, MPI_COMM_WORLD);
MPI堆栈上的根本错误是
MPIR_Localcopy(100)......: memcpy arguments alias each other, dst=0x7ffeeadd2f80 src=0x7ffeeadd2fc0 len=72
我的解释是MPICH MPI告诉我变量a_packet和best_packet重叠,因为要复制的变量的长度为72个字节,但是两个变量仅偏移了64个字节。
每个缓冲区实际上是一个由8个double组成的结构,占64个字节。我可以想象可能会有一些填充来处理对齐方式,但是编译器似乎很乐意在堆栈上分配这两个变量而无需填充。我已经记录了a_packet
和best_packet
的地址,它们与来自MPIR_Localcopy()
的错误消息中报告的地址匹配。
如果我将两个变量的声明更改为
REDUCE_PACKET a_packet;
char foo[2];
REDUCE_PACKET best_packet;
程序在MPICH和OpenMPI上运行时没有错误。
为什么MPICH认为此变量需要72个字节而不是64个字节?我是否在MPI / MPICH文档中缺少某些信息,可以告知我我负责这种手动填充?
答案 0 :(得分:0)
如果遇到此类错误,请仔细检查作为第3个参数传递给MPI_Allreduce()的MPI_datatype
的定义:
MPI_Allreduce((void *)&a_packet, (void *)&best_packet, 1,
reduction_packet_type, max_packets_op, MPI_COMM_WORLD);
事实证明,我们已经更改了基础C数据类型REDUCE_PACKET
的定义,但没有将调用更新为MPI_Type_contiguous()
,而是建立了MPI_datatype
,{{ 1}}。
显然,与OpenMPI相比,MPICH更加关注可能重叠的内存副本。