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 .bcast() #192

Merged
merged 70 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
4f8b20d
Rework the Span<> class, add SingleElementModifyableBuffer, fix resiz…
Mar 25, 2022
69f7a9c
Add the collective operation broadcast (bcast).
Mar 25, 2022
8f32da0
Merge branch 'main' into feature-bcast
Mar 30, 2022
9b82c17
Move a const to the east side
Mar 31, 2022
2f83c1a
Clean up code
Apr 4, 2022
4e9d8bc
Let bcast()'s test run on a single core.
Apr 4, 2022
8cd3f4a
Add @todo's to bcast()
Apr 4, 2022
a7ff782
Merge branch 'main' into feature-bcast
Apr 4, 2022
c68cb6f
Re-add the inclusion of communicator.hpp into gather.hpp
Apr 4, 2022
0e429af
Re-order MPI-using unit tests
Apr 4, 2022
4d2df90
Adjust bcast() to use the updated MPIResult()
Apr 4, 2022
d68d556
Apply the new .clang-format to bcast() files.
Apr 4, 2022
dc3a542
Remove recursive include
Apr 4, 2022
22d3ccc
Add two useful overloads for Communicator::is_root()
Apr 4, 2022
cc282c0
Restructure KASSERTs in bcast() to avoid the shortcomings of missing …
Apr 4, 2022
a0dcd36
Add two useful overloads for Communicator::is_root()
Apr 4, 2022
837d7b2
Add unit tests for Communicator::is_root()
Apr 4, 2022
d62a532
Merge branch 'feature-communicator-is-root-overloads' into feature-bcast
Apr 4, 2022
972239f
Merge branch 'main' into feature-bcast
Apr 4, 2022
7445366
Merge branch 'main' into feature-bcast
lukashuebner May 12, 2022
6dae35b
Apply clang-format changes
lukashuebner May 12, 2022
64d87e4
Merge branch 'feature-bcast' of github.com:KIT-ITI10/kamping into fea…
lukashuebner May 12, 2022
7db0be9
squash this
lukashuebner May 16, 2022
0b1f05e
sqash this in rebase
lukashuebner May 17, 2022
75f12ca
Add MPICommpincator::is_same_on_all_pes(...) helper
lukashuebner May 17, 2022
649b3df
Merge branch 'feature-is_same_on_all_pes' into feature-bcast
lukashuebner May 17, 2022
73ef1f3
Take parameters by value
lukashuebner May 31, 2022
942b936
Merge branch 'feature-bcast' of github.com:KIT-ITI10/kamping into fea…
lukashuebner Jun 14, 2022
e451486
Merge branch 'main' into feature-bcast
lukashuebner Jun 14, 2022
462c8da
Add bcast to the Communicator
lukashuebner Jun 14, 2022
712339e
Update documentation on Communicator::bcast
lukashuebner Jun 14, 2022
4245e55
Add a parameter factory for send_recv_count
lukashuebner Jun 14, 2022
55d3465
Rewrite Communicator::bcast
lukashuebner Jun 14, 2022
1b1f566
Rewrite the tests for Communicator::bcast
lukashuebner Jun 14, 2022
8697408
Apply clang-format
lukashuebner Jun 14, 2022
0509ad2
Revert extern/gtest-mpi-listener/gtest-mpi-listener.hpp
lukashuebner Jun 14, 2022
ba1623e
Remove obsolete comments
lukashuebner Jun 14, 2022
1808c4a
Add two additional assertions in Communicator::bcast(...)
lukashuebner Jun 14, 2022
070ced0
Merge branch 'main' into feature-bcast
lukashuebner Jun 15, 2022
2c10f8b
fixup
lukashuebner Jun 15, 2022
d0ace1a
fixup
lukashuebner Jun 15, 2022
b5178f2
Remove duplicate tests for Communicator::is_same_on_all_ranks
lukashuebner Jun 15, 2022
63ef42d
Update comment
lukashuebner Jun 15, 2022
2a94723
blub
lukashuebner Jun 15, 2022
50ef63d
Add missing include to bcast.hpp
lukashuebner Jun 15, 2022
e9ca0cb
Revert send_recv_count's type in bcast() to size_t
lukashuebner Jun 15, 2022
3b6fa05
Update Communicator::bcast()'s documentation
lukashuebner Jun 15, 2022
9988bee
Remove superflous comments and rename variable for clarity in bcast()
lukashuebner Jun 15, 2022
f91e88b
Minor fixes requested by reviewer.
lukashuebner Jun 15, 2022
256280f
Merge branch 'main' into feature-bcast
lukashuebner Jun 15, 2022
29d6960
Use the new DataBuffer.get_single_element()
lukashuebner Jun 15, 2022
7e9ad69
Comments and additional assertions
lukashuebner Jun 21, 2022
47509a9
Resize send_recv_buf also on root rank
lukashuebner Jun 21, 2022
7971b24
Add test for bcast, testing a message of size 0 (should work)
lukashuebner Jun 21, 2022
4673779
Rename send_recv_count to recv_count in bcast()
lukashuebner Jun 21, 2022
5783cbe
Fix a bug where user provded recv_counts are ignored in bcast
lukashuebner Jun 21, 2022
9e11330
Add test for bcast: recv count and vector size differ
lukashuebner Jun 21, 2022
145f007
Add check that recv_count == 1 if a single element buffer is passed a…
lukashuebner Jun 21, 2022
362abd0
Enable recv_count_out in bcast
lukashuebner Jun 21, 2022
5f29ed8
Add test for partially transferred containers for bcast()
lukashuebner Jun 21, 2022
024fe11
Remove unneeded send_recv_count parameter.
lukashuebner Jun 21, 2022
140adfd
Remove unneeded send_recv_count parameter type.
lukashuebner Jun 21, 2022
afd4166
Incorporate feedback from Demian
lukashuebner Jun 22, 2022
fc546ee
Clean up
lukashuebner Jun 23, 2022
5baa5c4
Merge branch 'main' into feature-bcast
lukashuebner Jun 24, 2022
edacedd
Add some KASSERT_FAILS tests to Communicator::bcast(...)
lukashuebner Jun 24, 2022
0b99b71
Mark variable as [[maybe_unused]] in bcast test.
lukashuebner Jun 24, 2022
8eec8d0
Run clang-format
lukashuebner Jun 24, 2022
bd75106
.
lukashuebner Jun 24, 2022
2d4ab53
Reformulate comment
lukashuebner Jun 24, 2022
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
129 changes: 129 additions & 0 deletions include/kamping/collectives/bcast.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// This file is part of KaMPI.ng.
//
// Copyright 2022 The KaMPI.ng Authors
//
// KaMPI.ng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
// version. KaMPI.ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with KaMPI.ng. If not, see
// <https://www.gnu.org/licenses/>.

#pragma once

#include <kassert/kassert.hpp>
#include <mpi.h>

#include "kamping/assertion_levels.hpp"
#include "kamping/checking_casts.hpp"
#include "kamping/comm_helper/is_same_on_all_ranks.hpp"
#include "kamping/communicator.hpp"
#include "kamping/mpi_datatype.hpp"
#include "kamping/mpi_function_wrapper_helpers.hpp"
#include "kamping/named_parameter_selection.hpp"
#include "kamping/parameter_check.hpp"
#include "kamping/parameter_factories.hpp"
#include "kamping/parameter_objects.hpp"
#include "kamping/parameter_type_definitions.hpp"

/// @brief Wrapper for \c MPI_Bcast
///
/// This wrapper for \c MPI_Bcast sends data from the root to all other ranks.
/// The following buffer is required:
/// - \ref kamping::send_recv_buf() containing the data that is sent to the other ranks. Non-root ranks must allocate
lukashuebner marked this conversation as resolved.
Show resolved Hide resolved
/// and provide this buffer as it's needed for deducing the value type. The container will be resized on non-root ranks
/// to fit exactly the received data.
/// The following parameter is optional but causes additional communication if not present.
/// - \ref kamping::recv_count() specifying how many elements are broadcasted. If not specified, will be
/// communicated through an additional bcast. If not specified, we broadcast the whole send_recv_buf. If specified,
/// has to be the same on all ranks (including the root). Has to either be specified or not specified on all ranks. The
/// following parameter is optional:
/// - \ref kamping::root() specifying an alternative root. If not present, the default root of the \c
lukashuebner marked this conversation as resolved.
Show resolved Hide resolved
/// Communicator is used, see root().
/// @todo Add support for `bcast<int>(..)` style deduction of send_recv_buf's type on non-root ranks.
/// @todo Add support for unnamed first parameter send_recv_buf.
/// @tparam Args Automatically deducted template parameters.
/// @param args All required and any number of the optional buffers described above.
/// @return Result type wrapping the output buffer if not specified as input parameter.
template <typename... Args>
auto kamping::Communicator::bcast(Args... args) const {
using namespace ::kamping::internal;
KAMPING_CHECK_PARAMETERS(
Args, KAMPING_REQUIRED_PARAMETERS(send_recv_buf), KAMPING_OPTIONAL_PARAMETERS(root, recv_count));

// Get the root PE
auto&& root = select_parameter_type_or_default<ParameterType::root, Root>(std::tuple(this->root()), args...);
KASSERT(this->is_valid_rank(root.rank()), "Invalid rank as root.", assert::light);

// Get the send_recv_buf; for now, the user *has* to provide a send-receive buffer.
auto&& send_recv_buf = internal::select_parameter_type<internal::ParameterType::send_recv_buf>(args...);
using value_type = typename std::remove_reference_t<decltype(send_recv_buf)>::value_type;
static_assert(!std::is_const_v<decltype(send_recv_buf)>, "Const send_recv_buf'fers are not allowed.");
auto mpi_value_type = mpi_datatype<value_type>();

/// @todo Uncomment, once the send_recv_buf is optional.
// if (this->is_root(root.rank())) {
// KASSERT(has_user_provided_send_recv_buf, "The send_recv_buf is mandatory at the root.", assert::light);
// }

// Get the optional recv_count parameter. If the parameter is not given, allocate a new container.
auto&& recv_count_param = internal::select_parameter_type_or_default<
ParameterType::recv_count, LibAllocatedSingleElementBuffer<int, ParameterType::recv_count>>(
std::tuple(), args...);

constexpr bool recv_count_is_output_parameter = has_to_be_computed<decltype(recv_count_param)>;
KASSERT(
is_same_on_all_ranks(recv_count_is_output_parameter),
"recv_count() parameter is an output parameter on some PEs, but not on alle PEs.", assert::light_communication);
lukashuebner marked this conversation as resolved.
Show resolved Hide resolved

// If it is not user provided, broadcast the size of send_recv_buf from the root to all ranks.
int recv_count = recv_count_param.get_single_element();
if constexpr (recv_count_is_output_parameter) {
if (this->is_root(root.rank())) {
recv_count = asserting_cast<int>(send_recv_buf.size());
}
// Transfer the recv_count
// This error code is unused if KTHROW is removed at compile time.
/// @todo Use bcast_single for this.
[[maybe_unused]] int err = MPI_Bcast(
&recv_count, // buffer
1, // count
mpi_datatype<decltype(recv_count)>(), // datatype
root.rank_signed(), // root
this->mpi_communicator() // comm
);
THROW_IF_MPI_ERROR(err, MPI_Bcast);

// Output the recv count via the output_parameter
*recv_count_param.data() = recv_count;
}
if (this->is_root(root.rank())) {
KASSERT(
asserting_cast<size_t>(recv_count) == send_recv_buf.size(),
"If a recv_count() is provided on the root rank, it has to be equal to the number of elements in the "
"send_recv_buf. For partial transfers, use a kamping::Span.");
}
KASSERT(
this->is_same_on_all_ranks(recv_count), "The recv_count must be equal on all ranks.",
assert::light_communication);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that recv_count is equal to send_recv_buf.size() on root

// Resize my send_recv_buf to be able to hold all received data.
// Trying to resize a single element buffer to something other than 1 will throw an error.
send_recv_buf.resize(asserting_cast<size_t>(recv_count));

// Perform the broadcast. The error code is unused if KTHROW is removed at compile time.
[[maybe_unused]] int err = MPI_Bcast(
send_recv_buf.data(), // buffer
asserting_cast<int>(send_recv_buf.size()), // count
mpi_value_type, // datatype
root.rank_signed(), // root
this->mpi_communicator() // comm
);
THROW_IF_MPI_ERROR(err, MPI_Bcast);

return MPIResult(
std::move(send_recv_buf), BufferCategoryNotUsed{}, std::move(recv_count_param), BufferCategoryNotUsed{},
BufferCategoryNotUsed{});
} // namespace kamping::internal
3 changes: 2 additions & 1 deletion include/kamping/collectives/reduce.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ auto kamping::Communicator::reduce(Args... args) const {
using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;

auto& operation_param = internal::select_parameter_type<internal::ParameterType::op>(args...);
auto operation = operation_param.template build_operation<send_value_type>();
// If you want to understand the syntax of the following line, ignore the "template " ;-)
auto operation = operation_param.template build_operation<send_value_type>();

// Check parameters
static_assert(
Expand Down
3 changes: 3 additions & 0 deletions include/kamping/communicator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ class Communicator {
template <typename... Args>
auto gather(Args... args) const;

template <typename... Args>
auto bcast(Args... args) const;

template <typename... Args>
void barrier(Args... args) const;

Expand Down
4 changes: 3 additions & 1 deletion include/kamping/parameter_objects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ class DataBuffer {
KASSERT(!is_extracted, "Cannot resize a buffer that has already been extracted.", assert::normal);
#endif
if constexpr (is_single_element) {
KASSERT(size == 1u, "Single element buffers must hold exactly one element.");
KASSERT(
size == 1u, "Cannot resize a single element buffer to hold zero or more than one element. Single "
"element buffers always hold exactly one element.");
} else if constexpr (std::is_same_v<MemberType, Span<value_type>>) {
KASSERT(this->size() >= size, "Span cannot be resized and is smaller than the requested size.");
} else {
Expand Down
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ kamping_register_mpi_test(test_mpi_communicator FILES mpi_communicator_test.cpp
kamping_register_mpi_test(test_mpi_datatype FILES mpi_datatype_test.cpp CORES 1)
kamping_register_mpi_test(test_mpi_gather FILES collectives/mpi_gather_test.cpp CORES 1 4)
kamping_register_mpi_test(test_mpi_reduce FILES collectives/mpi_reduce_test.cpp CORES 1 4)
kamping_register_mpi_test(test_mpi_bcast FILES collectives/mpi_bcast_test.cpp CORES 1 4)
kamping_register_mpi_test(test_mpi_allreduce FILES collectives/mpi_allreduce_test.cpp CORES 1 4)
kamping_register_mpi_test(test_operation_wrapper FILES mpi_operation_wrapper_test.cpp CORES 1)
kamping_register_mpi_test(test_parameter_factories_mpi FILES parameter_factories_mpi_test.cpp CORES 1)
Expand Down Expand Up @@ -94,3 +95,4 @@ kamping_register_compilation_failure_test(
"GET_SINGLE_ELEMENT_ON_VECTOR"
LIBRARIES kamping_base
)

Loading