Using Cray MPICH and Cray NICs' RDMA capabilities implies registering a buffer. On the host its done either via hooks to malloc or pagefaults monitors. On GPU buffers IDK how it is handled, probably similarly. The fact that call cudaMalloc instead of hipmalloc may confuse the underlying Cray logic.
// $ module purge
// $ module load cpe/24.07
// $ module load craype-accel-amd-gfx90a craype-x86-trento
// $ module load PrgEnv-gnu
// $ module load gcc/13.2.0
// $ module load amd-mixed/6.4.3
// $ module load cmake/3.27.9
// $ module list
// $ source ...../scale-1.7.2-Linux/bin/scaleenv gfx90a
// $ nvcc -lineinfo -g -std=c++17 --offload-arch=gfx90a -O3 -I /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/include -o test_scale_mpi test_scale_mpi.cu -L/opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib -lmpi --gcc-install-dir=/opt/software/gcc/13.2.0/lib/gcc/x86_64-pc-linux-gnu/13.2.0 -Wl,-rpath,/opt/software/gcc/13.2.0/lib64 -L/opt/cray/pe/mpich/8.1.30/gtl/lib -lmpi_gtl_hsa
// $ MPICH_GPU_SUPPORT_ENABLED=1 srun --ntasks=2 test_scale_mpi
// process_vm_readv: Bad address
// Assertion failed in file ../src/mpid/ch4/shm/cray_common/cray_common_memops.c at line 461: 0
// process_vm_readv: Bad address
// Assertion failed in file ../src/mpid/ch4/shm/cray_common/cray_common_memops.c at line 461: 0
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(MPL_backtrace_show+0x26) [0x14ca0b3b700b]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x1c4a214) [0x14ca0acf3214]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x214449a) [0x14ca0b1ed49a]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x216066a) [0x14ca0b20966a]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x213cc67) [0x14ca0b1e5c67]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0xd99548) [0x14ca09e42548]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0xde4411) [0x14ca09e8d411]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(MPI_Waitall+0x3cc) [0x14ca09e8dc1c]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(MPL_backtrace_show+0x26) [0x1519dea4700b]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x1c4a214) [0x1519de383214]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x214449a) [0x1519de87d49a]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x216066a) [0x1519de89966a]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0x213cc67) [0x1519de875c67]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0xd99548) [0x1519dd4d2548]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(+0xde4411) [0x1519dd51d411]
// /opt/cray/pe/mpich/8.1.30/ofi/gnu/11.2/lib/libmpi_gnu_112.so.12(MPI_Waitall+0x3cc) [0x1519dd51dc1c]
// test_scale_mpi(+0x142e) [0x55bd5df4142e]
// /lib64/libc.so.6(+0x295d0) [0x1519dc0035d0]
// /lib64/libc.so.6(__libc_start_main+0x80) [0x1519dc003680]
// test_scale_mpi(+0x11a5) [0x55bd5df411a5]
// test_scale_mpi(+0x142e) [0x55c027a8442e]
// /lib64/libc.so.6(+0x295d0) [0x14ca089735d0]
// /lib64/libc.so.6(__libc_start_main+0x80) [0x14ca08973680]
// test_scale_mpi(+0x11a5) [0x55c027a841a5]
// MPICH ERROR [Rank 0] [job id 5249618.34] [Wed Jul 29 11:15:26 2026] [g1032] - Abort(1): Internal error
// MPICH ERROR [Rank 1] [job id 5249618.34] [Wed Jul 29 11:15:26 2026] [g1032] - Abort(1): Internal error
#include <cuda_runtime.h>
#include <mpi.h>
#include <cstdio>
#include <cstdlib>
#define CHECK_MPI(cmd) \
do { \
int e = (cmd); \
if(e != MPI_SUCCESS) { \
fprintf(stderr, "MPI error\n"); \
MPI_Abort(MPI_COMM_WORLD, e); \
} \
} while(0)
#define CHECK_CUDA(cmd) \
do { \
cudaError_t e = (cmd); \
if(e != cudaSuccess) { \
fprintf(stderr, "CUDA error: %s\n", \
cudaGetErrorString(e)); \
exit(EXIT_FAILURE); \
} \
} while(0)
__global__ void init_kernel(float* buf, float value, int n) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if(i < n)
buf[i] = value;
}
int main(int argc, char** argv) {
CHECK_MPI(MPI_Init(&argc, &argv));
int rank, size;
CHECK_MPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
CHECK_MPI(MPI_Comm_size(MPI_COMM_WORLD, &size));
const int N = 1 << 20;
float* d_send;
float* d_recv;
CHECK_CUDA(cudaMalloc(&d_send, N * sizeof(float)));
CHECK_CUDA(cudaMalloc(&d_recv, N * sizeof(float)));
init_kernel<<<(N + 255) / 256, 256>>>(d_send, (float)rank, N);
CHECK_CUDA(cudaGetLastError());
CHECK_CUDA(cudaDeviceSynchronize());
int dst = (rank + 1) % size;
int src = (rank - 1 + size) % size;
MPI_Request reqs[2];
CHECK_MPI(MPI_Irecv(d_recv, N, MPI_FLOAT, src, 123, MPI_COMM_WORLD, &reqs[0]));
CHECK_MPI(MPI_Isend(d_send, N, MPI_FLOAT, dst, 123, MPI_COMM_WORLD, &reqs[1]));
CHECK_MPI(MPI_Waitall(2, reqs, MPI_STATUSES_IGNORE));
CHECK_CUDA(cudaDeviceSynchronize());
CHECK_CUDA(cudaFree(d_send));
CHECK_CUDA(cudaFree(d_recv));
CHECK_MPI(MPI_Finalize());
return 0;
}
Using Cray MPICH and Cray NICs' RDMA capabilities implies registering a buffer. On the host its done either via hooks to malloc or pagefaults monitors. On GPU buffers IDK how it is handled, probably similarly. The fact that call cudaMalloc instead of hipmalloc may confuse the underlying Cray logic.