MPI 共享内存和四精度的分段错误
Segmentation fault with MPI shared memory and quad precision
当四倍精度 (__float128
) 与 GCC(但不是英特尔 C 编译器)一起使用时,一个使用 MPI 共享内存的非常简单的 C 程序对我来说崩溃了。该程序为每个 MPI 进程分配一个一个元素长的共享实数组(分配由主进程完成,然后由其他进程访问)。每个进程写入一个元素并将另一个元素打印到标准输出。当使用标准内置类型 float
和 double
(或只是单个进程)时,根本没有问题。使用 __float128
(以及多个进程)时,下面突出显示的行会导致所有进程出现分段错误。
#include <mpi.h>
#include <stdio.h>
const int verbose = 0;
/* typedef float real; */
/* typedef double real; */
typedef __float128 real;
#define _(FUN, ARGS) \
{ \
int status = FUN ARGS; \
if (verbose) printf(#FUN " exit code: %d\n", status); \
}
int main (int argc, char* argv[])
{
int nprocs, rank, assert = 0, disp = 1, master = 0, bytesize = sizeof(real);
void* baseptr = NULL;
real* arr;
MPI_Win win;
printf("Data type byte size: %d\n", bytesize);
_(MPI_Init, (&argc, &argv))
_(MPI_Comm_size, (MPI_COMM_WORLD, &nprocs))
_(MPI_Comm_rank, (MPI_COMM_WORLD, &rank))
MPI_Aint totsize = rank == 0 ? bytesize * nprocs : 0;
_(MPI_Win_allocate_shared, (totsize, disp, MPI_INFO_NULL, MPI_COMM_WORLD, &baseptr, &win))
_(MPI_Win_shared_query, (win, master, &totsize, &disp, &arr))
_(MPI_Win_fence, (assert, win))
arr[rank] = rank + 1; /* <-- Segmentation fault here when using __float128 */
_(MPI_Win_fence, (assert, win))
printf("Element %d: %g\n", (rank + 1) % nprocs, (double)arr[(rank + 1) % nprocs]);
_(MPI_Win_fence, (assert, win))
_(MPI_Win_free, (&win));
_(MPI_Finalize, ());
return 0;
}
该程序在某些配置下有效,但在其他配置下无效。以下是我能够检查的那些:
Compiler
Open MPI 4.1.0
Intel MPI (oneAPI 2021)
Intel oneAPI 2021 mpiicc
OK for all types
OK for all types
GCC 9.3 mpicc
FAILS with __float128
N/A
GCC 10.2 mpicc
FAILS with __float128
N/A
我用的是 openSUSE Tumbleweed 20210319.
乍一看,这似乎是 GCC 中的一个问题。还是我在代码中遗漏了什么?
这里发生的是 MPI_Win_allocate_shared()
returns 一个按 8 字节对齐的内存区域,但是 GCC 假设 arr
按 16 字节对齐,如果 arr
未按 16 字节对齐。
您可以通过手动重新对齐数据来解决此问题。
#define REALIGN(a, type) \
((a) + sizeof(type) - 1 & ~(sizeof(type) - 1))
然后
MPI_Aint totsize = rank == 0 ? (bytesize * (nprocs+1)) : 0;
最后
arr = (real *)REALIGN((unsigned long)arr, real);
FWIW,在最近的英特尔处理器上,对齐和非对齐指令 运行 在数据对齐时以相同的速度,这可能是英特尔编译器不再生成对齐指令的原因。
当四倍精度 (__float128
) 与 GCC(但不是英特尔 C 编译器)一起使用时,一个使用 MPI 共享内存的非常简单的 C 程序对我来说崩溃了。该程序为每个 MPI 进程分配一个一个元素长的共享实数组(分配由主进程完成,然后由其他进程访问)。每个进程写入一个元素并将另一个元素打印到标准输出。当使用标准内置类型 float
和 double
(或只是单个进程)时,根本没有问题。使用 __float128
(以及多个进程)时,下面突出显示的行会导致所有进程出现分段错误。
#include <mpi.h>
#include <stdio.h>
const int verbose = 0;
/* typedef float real; */
/* typedef double real; */
typedef __float128 real;
#define _(FUN, ARGS) \
{ \
int status = FUN ARGS; \
if (verbose) printf(#FUN " exit code: %d\n", status); \
}
int main (int argc, char* argv[])
{
int nprocs, rank, assert = 0, disp = 1, master = 0, bytesize = sizeof(real);
void* baseptr = NULL;
real* arr;
MPI_Win win;
printf("Data type byte size: %d\n", bytesize);
_(MPI_Init, (&argc, &argv))
_(MPI_Comm_size, (MPI_COMM_WORLD, &nprocs))
_(MPI_Comm_rank, (MPI_COMM_WORLD, &rank))
MPI_Aint totsize = rank == 0 ? bytesize * nprocs : 0;
_(MPI_Win_allocate_shared, (totsize, disp, MPI_INFO_NULL, MPI_COMM_WORLD, &baseptr, &win))
_(MPI_Win_shared_query, (win, master, &totsize, &disp, &arr))
_(MPI_Win_fence, (assert, win))
arr[rank] = rank + 1; /* <-- Segmentation fault here when using __float128 */
_(MPI_Win_fence, (assert, win))
printf("Element %d: %g\n", (rank + 1) % nprocs, (double)arr[(rank + 1) % nprocs]);
_(MPI_Win_fence, (assert, win))
_(MPI_Win_free, (&win));
_(MPI_Finalize, ());
return 0;
}
该程序在某些配置下有效,但在其他配置下无效。以下是我能够检查的那些:
Compiler | Open MPI 4.1.0 | Intel MPI (oneAPI 2021) |
---|---|---|
Intel oneAPI 2021 mpiicc |
OK for all types | OK for all types |
GCC 9.3 mpicc |
FAILS with __float128 |
N/A |
GCC 10.2 mpicc |
FAILS with __float128 |
N/A |
我用的是 openSUSE Tumbleweed 20210319.
乍一看,这似乎是 GCC 中的一个问题。还是我在代码中遗漏了什么?
这里发生的是 MPI_Win_allocate_shared()
returns 一个按 8 字节对齐的内存区域,但是 GCC 假设 arr
按 16 字节对齐,如果 arr
未按 16 字节对齐。
您可以通过手动重新对齐数据来解决此问题。
#define REALIGN(a, type) \
((a) + sizeof(type) - 1 & ~(sizeof(type) - 1))
然后
MPI_Aint totsize = rank == 0 ? (bytesize * (nprocs+1)) : 0;
最后
arr = (real *)REALIGN((unsigned long)arr, real);
FWIW,在最近的英特尔处理器上,对齐和非对齐指令 运行 在数据对齐时以相同的速度,这可能是英特尔编译器不再生成对齐指令的原因。