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

Add communication modes to specialize send routines #30

Merged
merged 35 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
60e93f2
Add `Mode` enum to specialize communication modes
dssgabriel Apr 11, 2024
f8ab244
Add Ready and Synchronous mode sends
dssgabriel Apr 11, 2024
c98b8cb
Specify communication mode in `KokkosComm::send`
dssgabriel Apr 11, 2024
a6f4a5c
Add tests for Ready and Synchronous sends
dssgabriel Apr 11, 2024
082985e
Remove `Buffered` variant & clang-format
dssgabriel Apr 11, 2024
f129486
Add Ready and Synchronous mode for non-blocking send (`isend`)
dssgabriel Apr 11, 2024
8248ff3
Add tests for Ready and Synchronous non-blocking send (isend)
dssgabriel Apr 11, 2024
9266aba
Apply suggestions from code review
dssgabriel Apr 11, 2024
5cbbe8f
Delete `KokkosComm_mode` header and move enumeration to main header
dssgabriel Apr 11, 2024
49015ef
Propagate changes to `CommMode` everywhere
dssgabriel Apr 11, 2024
d6a9146
Add documentation for communication modes on send operations
dssgabriel Apr 11, 2024
1b93f9f
Remove type specifier from `CommMode` enum
dssgabriel Apr 12, 2024
137d8dc
Add anonymous namespace around tests
dssgabriel Apr 12, 2024
31f4f01
Delete test files for Ready & Synchronous modes
dssgabriel Apr 12, 2024
3229e64
Unify communication modes tests in a single file
dssgabriel Apr 12, 2024
d439a06
docs: add hyperlink to `CommMode` & remove its type specifier
dssgabriel Apr 13, 2024
cce031b
Remove unused packing traits
dssgabriel Apr 5, 2024
75b0fb9
docs: update with new `Default` comm mode
dssgabriel Apr 17, 2024
d623552
Move `CommMode` back to its own file to avoid circular header deps
dssgabriel Apr 17, 2024
f878ba9
Move template specialization to the `Impl` namespace
dssgabriel Apr 17, 2024
1f178db
CI: use Kokkos_ROOT in CI
cwpearson Apr 9, 2024
7ec53ed
docs: explain default behavior depends on environment variable
dssgabriel Apr 18, 2024
69c16b0
docs: remove default value from prototype
dssgabriel Apr 18, 2024
8e200ba
docs: explain how `KokkosComm_FORCE_SYNCHRONOUS_SEND` shall be defined
dssgabriel Apr 18, 2024
099d8d6
replace `else` branch with an explicit `else if`
dssgabriel Apr 18, 2024
ccbec83
docs: renamed into `KOKKOSCOMM_FORCE_SYNCHRONOUS_SEND`
dssgabriel Apr 18, 2024
b627c8f
fix: apply suggestions from code review
dssgabriel Apr 18, 2024
fa23192
refactor: define a lambda to avoid logic duplication in pack vs. non-…
dssgabriel Apr 18, 2024
116774e
refactor: change lambda prototype to match MPI functions
dssgabriel Apr 19, 2024
1056f09
tests: skip ready-mode sends
dssgabriel May 2, 2024
2875426
mpi: MPI_Barrier (#40)
cwpearson Apr 30, 2024
724ea63
fix typo in job step name (#41)
cwpearson Apr 30, 2024
f2126dc
make CI fail on docs build error
cwpearson Apr 22, 2024
0c1fa44
Merge branch 'develop' into comm-modes
dssgabriel May 2, 2024
a909ef7
docs: fix recv format
dssgabriel May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions docs/api/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,60 @@ Core
* - MPI
- ``KokkosComm::``
- ``Kokkos::View``
* - MPI_Send
- send
* - ``MPI_Send``
- ``send`` or ``send<CommMode::Standard>``
- ✓
* - MPI_Recv
- recv
* - ``MPI_Rsend``
- ``send<CommMode::Ready>``
- ✓
* - MPI_Isend
- isend
* - ``MPI_Recv``
- ``recv``
- ✓
* - MPI_Reduce
- reduce
* - ``MPI_Ssend``
- ``send<CommMode::Synchronous>``
- ✓
* - ``MPI_Isend``
- ``isend`` or ``isend<CommMode::Standard>``
- ✓
* - ``MPI_Irsend``
- ``isend<CommMode::Ready>``
- ✓
* - ``MPI_Issend``
- ``isend<CommMode::Synchronous>``
- ✓
* - ``MPI_Reduce``
- ``reduce``
- ✓

Point-to-point
--------------

.. cpp:function:: template <KokkosExecutionSpace ExecSpace, KokkosView SendView> \
.. cpp:function:: template <KokkosComm::CommMode SendMode, KokkosExecutionSpace ExecSpace, KokkosView SendView> \
Req KokkosComm::isend(const ExecSpace &space, const SendView &sv, int dest, int tag, MPI_Comm comm)

MPI_Isend wrapper
Wrapper for ``MPI_Isend``, ``MPI_Irsend`` and ``MPI_Issend``.

:param space: The execution space to operate in
:param sv: The data to send
:param dest: the destination rank
:param tag: the MPI tag
:param comm: the MPI communicator
:tparam SendMode: A CommMode_ to use. If unspecified, defaults to a synchronous ``MPI_Issend`` if ``KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE`` is defined, otherwise defaults to a standard ``MPI_Isend``.
:tparam SendView: A Kokkos::View to send
:tparam ExecSpace: A Kokkos execution space to operate in
:returns: A KokkosComm::Req representing the asynchronous communication and any lifetime-extended views.

.. cpp:function:: template <KokkosExecutionSpace ExecSpace, KokkosView SendView> \
.. cpp:function:: template <KokkosComm::CommMode SendMode, KokkosExecutionSpace ExecSpace, KokkosView SendView> \
void KokkosComm::send(const ExecSpace &space, const SendView &sv, int dest, int tag, MPI_Comm comm)

MPI_Send wrapper
Wrapper for ``MPI_Send``, ``MPI_Rsend`` and ``MPI_Ssend``.

:param space: The execution space to operate in
:param sv: The data to send
:param dest: the destination rank
:param tag: the MPI tag
:param comm: the MPI communicator
:tparam SendMode: A CommMode_ to use. If unspecified, defaults to a synchronous ``MPI_Ssend`` if ``KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE`` is defined, otherwise defaults to a standard ``MPI_Send``.
:tparam SendView: A Kokkos::View to send
:tparam ExecSpace: A Kokkos execution space to operate in

Expand Down Expand Up @@ -86,6 +100,29 @@ Collective
Related Types
-------------

.. _CommMode:

.. cpp:enum-class:: KokkosComm::CommMode

A scoped enum to specify the mode of an operation. Buffered mode is not supported.

.. cpp:enumerator:: KokkosComm::CommMode::Standard

Standard mode: the MPI implementation decides whether outgoing messages will be buffered. Send operations can be started whether or not a matching receive has been started. They may complete before a matching receive is started. Standard mode is non-local: successful completion of the send operation may depend on the occurrence of a matching receive.

.. cpp:enumerator:: KokkosComm::CommMode::Ready

Ready mode: Send operations may be started only if the matching receive is already started.

.. cpp:enumerator:: KokkosComm::CommMode::Synchronous

Synchronous mode: Send operations complete successfully only if a matching receive is started, and the receive operation has started to receive the message sent.

.. cpp:enumerator:: KokkosComm::CommMode::Default

Default mode is an alias for ``Standard`` mode, but lets users override the behavior of operations at compile-time using the ``KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE`` pre-processor define. This forces ``Synchronous`` mode for all "default-mode" operations, which can be useful for debugging purposes, e.g., for asserting that the communication scheme is correct.


.. cpp:class:: KokkosComm::Req

A wrapper around an MPI_Request that can also extend the lifetime of Views.
Expand Down
11 changes: 7 additions & 4 deletions src/KokkosComm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,24 @@
#include "KokkosComm_recv.hpp"
#include "KokkosComm_send.hpp"
#include "KokkosComm_concepts.hpp"
#include "KokkosComm_comm_mode.hpp"

#include <Kokkos_Core.hpp>

namespace KokkosComm {

template <KokkosExecutionSpace ExecSpace, KokkosView SendView>
template <CommMode SendMode = CommMode::Default, KokkosExecutionSpace ExecSpace,
KokkosView SendView>
Req isend(const ExecSpace &space, const SendView &sv, int dest, int tag,
MPI_Comm comm) {
return Impl::isend(space, sv, dest, tag, comm);
return Impl::isend<SendMode>(space, sv, dest, tag, comm);
}

template <KokkosExecutionSpace ExecSpace, KokkosView SendView>
template <CommMode SendMode = CommMode::Default, KokkosExecutionSpace ExecSpace,
KokkosView SendView>
void send(const ExecSpace &space, const SendView &sv, int dest, int tag,
MPI_Comm comm) {
return Impl::send(space, sv, dest, tag, comm);
return Impl::send<SendMode>(space, sv, dest, tag, comm);
}

template <KokkosExecutionSpace ExecSpace, KokkosView RecvView>
Expand Down
43 changes: 43 additions & 0 deletions src/KokkosComm_comm_mode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//@HEADER
// ************************************************************************
//
// Kokkos v. 4.0
// Copyright (2022) National Technology & Engineering
// Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
// See https://kokkos.org/LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//@HEADER

#pragma once

namespace KokkosComm {

// Scoped enumeration to specify the communication mode of a sending operation.
// See section 3.4 of the MPI standard for a complete specification.
enum class CommMode {
// Default mode: lets the user override the send operations behavior at
// compile-time. E.g., this can be set to mode "Synchronous" for debug
// builds by defining KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE.
Default,
// Standard mode: MPI implementation decides whether outgoing messages will
// be buffered. Send operations can be started whether or not a matching
// receive has been started. They may complete before a matching receive is
// started. Standard mode is non-local: successful completion of the send
// operation may depend on the occurrence of a matching receive.
Standard,
// Ready mode: Send operations may be started only if the matching receive is
// already started.
Ready,
// Synchronous mode: Send operations complete successfully only if a matching
// receive is started, and the receive operation has started to receive the
// message sent.
Synchronous,
};

} // namespace KokkosComm
36 changes: 30 additions & 6 deletions src/impl/KokkosComm_isend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
#include "KokkosComm_pack_traits.hpp"
#include "KokkosComm_request.hpp"
#include "KokkosComm_traits.hpp"
#include "KokkosComm_comm_mode.hpp"

// impl
#include "KokkosComm_include_mpi.hpp"

namespace KokkosComm::Impl {

template <KokkosExecutionSpace ExecSpace, KokkosView SendView>
template <CommMode SendMode = CommMode::Default, KokkosExecutionSpace ExecSpace,
KokkosView SendView>
KokkosComm::Req isend(const ExecSpace &space, const SendView &sv, int dest,
int tag, MPI_Comm comm) {
Kokkos::Tools::pushRegion("KokkosComm::Impl::isend");
Expand All @@ -40,20 +42,42 @@ KokkosComm::Req isend(const ExecSpace &space, const SendView &sv, int dest,
using KCT = KokkosComm::Traits<SendView>;
using KCPT = KokkosComm::PackTraits<SendView>;

auto mpi_isend_fn = [](void *mpi_view, int mpi_count,
MPI_Datatype mpi_datatype, int mpi_dest, int mpi_tag,
MPI_Comm mpi_comm, MPI_Request *mpi_req) {
if constexpr (SendMode == CommMode::Standard) {
MPI_Isend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm,
mpi_req);
} else if constexpr (SendMode == CommMode::Ready) {
MPI_Irsend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm,
mpi_req);
} else if constexpr (SendMode == CommMode::Synchronous) {
MPI_Issend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm,
mpi_req);
} else if constexpr (SendMode == CommMode::Default) {
#ifdef KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE
MPI_Issend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm,
mpi_req);
#else
MPI_Isend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm,
mpi_req);
#endif
}
};

if (KCPT::needs_pack(sv)) {
using Packer = typename KCPT::packer_type;
using MpiArgs = typename Packer::args_type;

MpiArgs args = Packer::pack(space, sv);
space.fence();

MPI_Isend(KCT::data_handle(args.view), args.count, args.datatype, dest, tag,
comm, &req.mpi_req());
mpi_isend_fn(KCT::data_handle(args.view), args.count, args.datatype, dest,
tag, comm, &req.mpi_req());
req.keep_until_wait(args.view);
} else {
using SendScalar = typename SendView::value_type;
MPI_Isend(KCT::data_handle(sv), KCT::span(sv), mpi_type_v<SendScalar>, dest,
tag, comm, &req.mpi_req());
mpi_isend_fn(KCT::data_handle(sv), KCT::span(sv), mpi_type_v<SendScalar>,
dest, tag, comm, &req.mpi_req());
if (KCT::is_reference_counted()) {
req.keep_until_wait(sv);
}
Expand Down
28 changes: 25 additions & 3 deletions src/impl/KokkosComm_send.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,49 @@
#include <Kokkos_Core.hpp>

#include "KokkosComm_pack_traits.hpp"
#include "KokkosComm_comm_mode.hpp"

// impl
#include "KokkosComm_include_mpi.hpp"

namespace KokkosComm::Impl {
template <KokkosExecutionSpace ExecSpace, KokkosView SendView>

template <CommMode SendMode = CommMode::Default, KokkosExecutionSpace ExecSpace,
KokkosView SendView>
void send(const ExecSpace &space, const SendView &sv, int dest, int tag,
MPI_Comm comm) {
Kokkos::Tools::pushRegion("KokkosComm::Impl::send");

using Packer = typename KokkosComm::PackTraits<SendView>::packer_type;

auto mpi_send_fn = [](void *mpi_view, int mpi_count,
MPI_Datatype mpi_datatype, int mpi_dest, int mpi_tag,
MPI_Comm mpi_comm) {
if constexpr (SendMode == CommMode::Standard) {
MPI_Send(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm);
} else if constexpr (SendMode == CommMode::Ready) {
MPI_Rsend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm);
} else if constexpr (SendMode == CommMode::Synchronous) {
MPI_Ssend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm);
} else if constexpr (SendMode == CommMode::Default) {
#ifdef KOKKOSCOMM_FORCE_SYNCHRONOUS_MODE
MPI_Ssend(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm);
#else
MPI_Send(mpi_view, mpi_count, mpi_datatype, mpi_dest, mpi_tag, mpi_comm);
#endif
}
};

if (KokkosComm::PackTraits<SendView>::needs_pack(sv)) {
auto args = Packer::pack(space, sv);
space.fence();
MPI_Send(args.view.data(), args.count, args.datatype, dest, tag, comm);
mpi_send_fn(args.view.data(), args.count, args.datatype, dest, tag, comm);
} else {
using SendScalar = typename SendView::value_type;
MPI_Send(sv.data(), sv.span(), mpi_type_v<SendScalar>, dest, tag, comm);
mpi_send_fn(sv.data(), sv.span(), mpi_type_v<SendScalar>, dest, tag, comm);
}

Kokkos::Tools::popRegion();
}

} // namespace KokkosComm::Impl
Loading