Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-blocking version of recv (irecv) #681

Open
ClarkGuilty opened this issue Nov 30, 2022 · 6 comments
Open

Non-blocking version of recv (irecv) #681

ClarkGuilty opened this issue Nov 30, 2022 · 6 comments

Comments

@ClarkGuilty
Copy link

Hello.

I remember there being a non-blocking version of serialized Recv (irecv). Was this deprecated, if so, why? Is there an already established alternative?

Thank you.

@simonbyrne
Copy link
Member

It still exists, but has been deprecated:

MPI.jl/src/deprecated.jl

Lines 239 to 246 in 2e94c5b

@deprecate(irecv(src::Integer, tag::Integer, comm::Comm), begin
(flag, stat) = Iprobe(src, tag, comm)
flag || return (false, nothing, nothing)
count = Get_count(stat, UInt8)
buf = Array{UInt8}(undef, count)
stat = Recv!(buf, Get_source(stat), Get_tag(stat), comm)
(true, MPI.deserialize(buf), stat)
end, false)

It was undocumented, and honestly it doesn't really make sense how its defined: it's not really analogous to Irecv since it didn't return a Request object (instead you have to keep calling it). Also in a multithreaded context, there is no guarantee that the Recv will match the same operation as the Iprobe. To be done properly:

  • It should use MPI_Improbe and MPI_Mrecv
  • It should be implemented via the MPI "Generalized Request" interface.

@simonbyrne
Copy link
Member

simonbyrne commented Nov 30, 2022

If you do have need for it, we could add it back, but give it a more reasonable name (iprobe_recv?) A PR would also be welcome

@ClarkGuilty
Copy link
Author

Thank you very much! I do need the function and have been trying to implement it (for now, only in the scope of my project but with the hope of eventually making a PR), but I am finding it hard to interact with MPI.API (this is the first time I use C bindings in Julia). I cannot use the deprecated version because the syntax has changed since it was deprecated (I believe) and the signature no longer works. Thus, I have a question regarding MPI.API.Improbe

Reading the Docs, the way to use MPI.API.Improbe is very similar to MPI.API.Iprobe, the only difference being the message pointer, However I keep getting:

MethodError: no method matching unsafe_convert(::MethodError: no method matching unsafe_convert(::Type{Ptr{Ptr{Nothing}}}, ::Bas
e.RefValue{Int32})Type{Ptr{Ptr{Nothing}}}, ::Base.RefValue{Int32})
Closest candidates are:
  unsafe_convert(::Type{Ptr{T}}, !Matched::Union{NNlib.BatchedAdjoint{T, S}, NNlib.BatchedTranspose{T, S}} where S) where T at ~/.julia/packages/NNlib/c0XLe/src/bat
ched/batchedadjtrans.jl:90
  unsafe_convert(::Type{Ptr{T}}, !Matched::Base.Threads.Atomic{T}) where T at atomics.jl:328
  unsafe_convert(::Type{Ptr{T}}, !Matched::LinearAlgebra.Adjoint{<:Real, <:AbstractVecOrMat}) where T at /usr/share/julia/stdlib/v1.8/LinearAlgebra/src/adjtrans.jl:
198
  ...
Stacktrace:
 [1] MPI_Improbe(source::Int64, tag::Int64, comm::MPI.Comm, flag::Base.RefValue{Int32}, message::Base.RefValue{Int32}, status::Base.RefValue{MPI.API.MPI_Status})
   @ MPI.API ~/.julia/packages/MPI/tJjHF/src/api/generated_api.jl:2106

This is my implementation so far

irecv(source::Integer, tag::Integer, comm::MPI.Comm)
    flag = Ref{Cint}()
    mess = Ref{MPI_Message}()
    status = Ref{MPI.Status}()
    MPI.API.MPI_Improbe(source,tag,comm,flag,mess,status)
    ...

How should I initialize the pointers?

@simonbyrne
Copy link
Member

simonbyrne commented Dec 1, 2022

It's a bit hard to debug while inside mpiexec since the output gets messed up. However this should be possible to do in a single process, so you can just use the REPL. Firstly, check make sure you're on the master branch, and then can you try the following?:

using MPI, MPIPreferences
@show MPIPreferences.abi
MPI.Init()

source = 0
tag = 0
comm = MPI.COMM_WORLD
flag = Ref(Cint(0))
mess = Ref(MPI.API.MPI_MESSAGE_NULL[])
status = Ref(MPI.STATUS_ZERO)
MPI.API.MPI_Improbe(source,tag,comm,flag,mess,status)
mess[]

@ClarkGuilty
Copy link
Author

Thank you. After cheking that I am on master:
MPI.Init() = MPI.ThreadLevel(2)
flag = Ref(Cint(0)) = Base.RefValue{Int32}(0)
mess = Ref(MPI.API.MPI_MESSAGE_NULL[]) = Base.RefValue{Ptr{Nothing}}(Ptr{Nothing} @0x00007f1ea5dfd2e0)
@show MPIPreferences.abi = "OpenMPI"
MPI.API.MPI_Improbe(source,tag,comm,flag,mess,status) returned true.
mess[] = Ptr{Nothing} @0x00007f1ea5dfd2e0

@simonbyrne
Copy link
Member

Okay, that looks like it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants