1717import numpy as np
1818
1919from devito .mpi import MPI
20- from devito .tools import dtype_to_mpidtype
20+ from devito .tools import mpi4py_mapper
2121
2222__all__ = ['sparse_exchange' ]
2323
@@ -53,7 +53,15 @@ def sparse_exchange(comm, sendbufs, dtype, tag=0):
5353 """
5454 rank = comm .Get_rank ()
5555 nprocs = comm .Get_size ()
56- mpitype = dtype_to_mpidtype (dtype )
56+
57+ # Some MPI builds lack a native datatype for `dtype` (e.g. `float16`); send
58+ # over a same-size byte-equivalent wire type and view back on receipt, just
59+ # as the halo exchange does via `comm_dtype`. A no-op for mapped-to-self
60+ # types. The MPI datatype is left for mpi4py to infer from each buffer (as
61+ # the halo exchange's `Sendrecv` does): passing an explicit datatype forces
62+ # the `Type_get_extent` count path, which segfaults under some CUDA-aware MPI
63+ # builds, whereas buffer-protocol typing is portable.
64+ wire = np .dtype (mpi4py_mapper .get (np .dtype (dtype ).type , dtype ))
5765
5866 recvd = {}
5967
@@ -79,19 +87,21 @@ def sparse_exchange(comm, sendbufs, dtype, tag=0):
7987 for peer , buf in sendbufs .items ():
8088 if peer == rank or buf .size == 0 :
8189 continue
82- buf = np .ascontiguousarray (buf )
90+ buf = np .ascontiguousarray (buf ). view ( wire )
8391 live_bufs .append (buf )
84- sends .append (comm .Isend ([ buf , mpitype ] , dest = peer , tag = tag ))
92+ sends .append (comm .Isend (buf , dest = peer , tag = tag ))
8593
86- # Receive exactly the expected number of messages, sizing each from its probe
94+ # Receive exactly the expected number of messages, sizing each from its
95+ # probe. The byte count (a probe against `MPI.BYTE`) divides by the wire
96+ # item size to give the element count.
8797 status = MPI .Status ()
8898 for _ in range (int (incoming [0 ])):
8999 comm .Probe (source = MPI .ANY_SOURCE , tag = tag , status = status )
90100 src = status .Get_source ()
91- count = status .Get_count (mpitype )
92- buf = np .empty (count , dtype = dtype )
93- comm .Recv ([ buf , mpitype ] , source = src , tag = tag )
94- recvd [src ] = buf
101+ count = status .Get_count (MPI . BYTE ) // wire . itemsize
102+ buf = np .empty (count , dtype = wire )
103+ comm .Recv (buf , source = src , tag = tag )
104+ recvd [src ] = buf . view ( dtype )
95105
96106 MPI .Request .Waitall (sends )
97107 return recvd
0 commit comments