diff --git a/docs/src/reference/pointtopoint.md b/docs/src/reference/pointtopoint.md index 8da05d96a..a7223a182 100644 --- a/docs/src/reference/pointtopoint.md +++ b/docs/src/reference/pointtopoint.md @@ -45,6 +45,7 @@ MPI.Sendrecv! MPI.Isend MPI.isend MPI.Irecv! +MPI.Isendrecv! ``` ### Completion diff --git a/src/pointtopoint.jl b/src/pointtopoint.jl index 76712f656..2a13ad9dc 100644 --- a/src/pointtopoint.jl +++ b/src/pointtopoint.jl @@ -245,6 +245,40 @@ function Sendrecv!(sendbuf, dest::Integer, sendtag::Integer, recvbuf, source::In return data, status[] end +""" + req = Isendrecv!(sendbuf, recvbuf, comm::Comm[, req::AbstractRequest = Request()]; + dest::Integer, sendtag::Integer=0, source::Integer=MPI.ANY_SOURCE, recvtag::Integer=MPI.ANY_TAG) + +Starts a nonblocking combined send-receive over the MPI communicator `comm`. Sends `sendbuf` to the +MPI rank `dest` using message tag `sendtag`, and receive from MPI rank `source` into the buffer `recvbuf` +using message tag `recvtag`. + +`sendbuf` can be a [`Buffer`](@ref), or any object for which `Buffer(sendbuf)` is defined (similarly for `recvbuf`). + +Returns an [`AbstractRequest`](@ref) for the combined non-blocking operation. + +# External links +$(_doc_external("MPI_Isendrecv")) +""" +Isendrecv!(sendbuf, recvbuf, comm::Comm, req::AbstractRequest=Request(); dest::Integer, sendtag::Integer=0, source::Integer=API.MPI_ANY_SOURCE[], recvtag::Integer=API.MPI_ANY_TAG[]) = + Isendrecv!(sendbuf, dest, sendtag, recvbuf, source, recvtag, comm, req) + +function Isendrecv!(sendbuf::Buffer, dest::Integer, sendtag::Integer, + recvbuf::Buffer, source::Integer, recvtag::Integer, + comm::Comm, req::AbstractRequest=Request()) + @assert isnull(req) + # int MPI_Isendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag + # const void* recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, + # MPI_Comm comm, MPI_Request *request) + API.MPI_Isendrecv(sendbuf.data, sendbuf.count, sendbuf.datatype, dest, sendtag, + recvbuf.data, recvbuf.count, recvbuf.datatype, source, recvtag, + comm, req) + setbuffer!(req, (sendbuf, recvbuf)) + return req +end +Isendrecv!(sendbuf, dest::Integer, sendtag::Integer, recvbuf, source::Integer, recvtag::Integer, comm::Comm, req::AbstractRequest=Request()) = + Isendrecv!(Buffer(sendbuf), dest, sendtag, Buffer(recvbuf), source, recvtag, comm, req) + # persistent requests """ Send_init(buf, comm::MPI.Comm[, req::AbstractRequest = Request()]; diff --git a/test/test_isendrecv.jl b/test/test_isendrecv.jl new file mode 100644 index 000000000..3b30b527d --- /dev/null +++ b/test/test_isendrecv.jl @@ -0,0 +1,39 @@ +include("common.jl") + +MPI.Init() + +# initialise communicator variables +comm = MPI.COMM_WORLD +comm_rank = MPI.Comm_rank(comm) +comm_size = MPI.Comm_size(comm) + +# cartesian comunicator topology +comm_cart = MPI.Cart_create(comm, (comm_size,); periodic=(true,), reorder=false) +src_rank, dest_rank = MPI.Cart_shift(comm_cart, 0, -1) + +# construct buffers +sendbuf = Float64[comm_rank, comm_rank, comm_rank] +recvbuf = Float64[ -1, -1, -1] + +# send entire buffer +req = MPI.Isendrecv!(sendbuf, recvbuf, comm_cart; + dest=dest_rank, sendtag=10, source=src_rank, recvtag=10) + +@test req isa MPI.Request +@test !isnothing(req.buffer) + +status = MPI.Wait(req, MPI.Status) + +# ! doesn't work with MPICH backend +@test_broken MPI.Get_source(status) == src_rank +@test_broken MPI.Get_tag(status) == 10 +@test recvbuf == [((comm_rank+1) % comm_size) for _ in 1:length(recvbuf)] + +# compare to blocking Sendrecv! +a = Float64[comm_rank, comm_rank, comm_rank] +b = Float64[ -1, -1, -1] +MPI.Sendrecv!(a, b, comm_cart; + dest=dest_rank, sendtag=11, source=src_rank, recvtag=11) +@test b == recvbuf + +MPI.Finalize()