KaMPIng 0.2.0
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
group.hpp
Go to the documentation of this file.
1// This file is part of KaMPIng.
2//
3// Copyright 2024 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14/// @file
15/// @brief An abstraction around `MPI_Group`.
16
17#pragma once
18
19#include <iterator>
20#include <memory>
21#include <optional>
22#include <type_traits>
23
24#include <mpi.h>
25
28#include "kamping/kassert/kassert.hpp"
29
30namespace kamping {
31
32/// @brief Describes the equality of two groups.
33enum class GroupEquality : uint8_t {
34 Identical, ///< The order and members of the two groups are the same.
35 Similar, ///< Only the members are the same, the order is different.
36 Unequal, ///< Otherwise
37 Invalid ///< Tried to convert an invalid value to a GroupEquality.
38};
39
40/// @brief A group of MPI processes.
41class Group {
42public:
43 /// @brief Constructs a new group from an existing MPI group.
44 Group(MPI_Group group, bool owning = false) : _group(group), _owns_group(owning) {}
45
46 Group(Group const&) = delete;
47 Group operator=(Group const&) = delete;
48
49 /// @brief Move constructor.
51 this->_group = other._group;
52 other._owns_group = false;
53 this->_owns_group = true;
54 }
55
56 /// @brief Move assignment.
58 this->_group = other._group;
59 other._owns_group = false;
60 this->_owns_group = true;
61 return *this;
62 }
63
64 /// @brief Constructs the group associated with a communicator.
65 template <typename Comm>
66 Group(Comm const& comm) : _owns_group(true) {
67 int err = MPI_Comm_group(comm.mpi_communicator(), &_group);
68 THROW_IF_MPI_ERROR(err, "MPI_Comm_group");
69 }
70
71 /// @brief Constructs an empty group.
72 /// @return An empty group.
73 [[nodiscard]] static Group empty() {
74 return Group(MPI_GROUP_EMPTY);
75 }
76
77 /// @brief Default destructor, freeing the encapsulated group if owned.
79 if (_owns_group) {
80 MPI_Group_free(&_group);
81 }
82 }
83
84 // TODO We need a safe tag for this -> move to another PR
85 // template <typename Comm>
86 // Comm create_comm(Comm const& comm) const {
87 // constexpr int safe_tag = 1337; // TODO
88 // MPI_Comm new_comm;
89 // MPI_Comm_group_create(comm, _group, safe_tag, &new_comm);
90 // return Comm(new_comm);
91 // }
92 // TODO _excl, _incl, _range_incl, _range_excl, and translate_ranks
93
94 /// @brief Compare two groups.
95 /// @param other The group to compare with.
96 /// @return The equality of the two groups (see \ref GroupEquality).
98 int result;
99 int err = MPI_Group_compare(_group, other._group, &result);
100 THROW_IF_MPI_ERROR(err, "MPI_Group_compare");
101
102 switch (result) {
103 case MPI_IDENT:
104 return GroupEquality::Identical;
105 case MPI_SIMILAR:
106 return GroupEquality::Similar;
107 case MPI_UNEQUAL:
108 return GroupEquality::Unequal;
109 default:
110 KAMPING_ASSERT(false, "MPI_Group_compare returned an unknown value");
111 return GroupEquality::Invalid;
112 }
113 }
114
115 /// @brief Compare two groups.
116 /// @param other The group to compare with.
117 /// @return True if the groups are identical; see \ref GroupEquality. False otherwise.
118 [[nodiscard]] bool is_identical(Group const& other) const {
119 return compare(other) == GroupEquality::Identical;
120 }
121
122 /// @brief Compare two groups.
123 /// @param other The group to compare with.
124 /// @return True if the groups are similar; see \ref GroupEquality. False otherwise.
125 [[nodiscard]] bool is_similar(Group const& other) const {
126 return compare(other) == GroupEquality::Similar;
127 }
128
129 /// @brief Compare two groups.
130 /// @param other The group to compare with.
131 /// @return True if the groups are identical; see \ref GroupEquality. False otherwise.
132 [[nodiscard]] bool has_same_ranks(Group const& other) const {
133 auto const result = compare(other);
134 return (result == GroupEquality::Identical) || (result == GroupEquality::Similar);
135 }
136
137 /// @brief Makes a group from the difference of two groups.
138 /// @param other The other group.
139 /// @return A group containing all the ranks of the first group that are not in the second group.
140 Group difference(Group const& other) const {
142 MPI_Group_difference(_group, other._group, &diff);
143 return Group(diff);
144 }
145
146 /// @brief Makes a group from the intersection of two groups.
147 /// @param other The other group.
148 /// @return A group containing only the ranks present in both groups.
151 int err = MPI_Group_intersection(_group, other._group, &inter);
152 THROW_IF_MPI_ERROR(err, "MPI_Group_intersection");
153 return Group(inter);
154 }
155
156 /// @brief Makes a group from the union of two groups.
157 /// @param other The other group.
158 /// @return A group containing all ranks present in either of the two groups.
159 /// @note The set_ prefix was choosen in order to avoid a name clash with the C++ keyword `union`.
160 Group set_union(Group const& other) const {
162 int err = MPI_Group_union(_group, other._group, &un);
163 THROW_IF_MPI_ERROR(err, "MPI_Group_union");
164 return Group(un);
165 }
166
167 /// @brief Translates a rank relative to this group to a rank relative to another group.
168 /// @param rank_in_this_group The rank in this group.
169 /// @param other_group The other group.
170 /// @return An optional containing the rank in the other group, or std::nullopt if the rank is not present in the
171 /// other group.
172 [[nodiscard]] std::optional<int> translate_rank_to_group(int rank_in_this_group, Group const& other_group) const {
173 int rank_in_other_group = 0;
174 int err =
176 THROW_IF_MPI_ERROR(err, "MPI_Group_translate_ranks");
178 return std::nullopt;
179 }
180 return rank_in_other_group;
181 }
182
183 /// @brief Translates multiple ranks relative to this group to ranks relative to another group.
184 /// @tparam In A random access iterator type with `int` as value type.
185 /// @tparam Out A random access iterator type with `int` as value type.
186 /// @param ranks_in_this_group_begin Iterator to the beginning of the ranks in this group.
187 /// @param ranks_in_this_group_end Iterator to the end of the ranks in this group.
188 /// @param ranks_in_other_group_begin Iterator to the beginning of the output ranks in the other group.
189 /// @param other_group The other group.
190 ///
191 /// @note The output ranks will be written starting from `ranks_in_other_group_begin`. The caller must ensure that
192 /// there is enough space to write all the output ranks.
193 /// If a rank is not present in the other group, the corresponding output rank will be set to `MPI_UNDEFINED`.
194 template <typename In, typename Out>
199 Group const& other_group
200 ) const {
201 static_assert(
202 std::is_same_v<typename std::iterator_traits<In>::value_type, int>,
203 "Input iterator value type must be int"
204 );
205 static_assert(
206 std::is_same_v<typename std::iterator_traits<Out>::value_type, int>,
207 "Output iterator value type must be int"
208 );
209 static_assert(
210 std::is_base_of_v<std::random_access_iterator_tag, typename std::iterator_traits<In>::iterator_category>,
211 "Input iterator must be a random access iterator"
212 );
213 static_assert(
214 std::is_base_of_v<std::random_access_iterator_tag, typename std::iterator_traits<Out>::iterator_category>,
215 "Output iterator must be a random access iterator"
216 );
217
220 _group,
221 count,
222 std::addressof(*ranks_in_this_group_begin),
223 other_group.mpi_group(),
224 std::addressof(*ranks_in_other_group_begin)
225 );
226 THROW_IF_MPI_ERROR(err, "MPI_Group_translate_ranks");
227 }
228
229 /// @brief Get the number of ranks in the group.
230 /// @return The number of ranks in the group.
231 [[nodiscard]] size_t size() const {
232 int size;
233 int err = MPI_Group_size(_group, &size);
234 THROW_IF_MPI_ERROR(err, "MPI_Group_size");
236 }
237
238 /// @brief Get the rank of the calling process in the group.
239 /// @return The rank of the calling process in the group.
240 [[nodiscard]] size_t rank() const {
241 int rank;
242 int err = MPI_Group_rank(_group, &rank);
243 THROW_IF_MPI_ERROR(err, "MPI_Group_rank");
245 }
246
247 /// @brief Native MPI_Group handle corresponding to this Group.
248 /// @return The MPI_Group handle.
250 return _group;
251 }
252
253private:
254 MPI_Group _group;
255 bool _owns_group;
256};
257
258} // namespace kamping
Helper functions that make casts safer.
A group of MPI processes.
Definition group.hpp:41
bool is_similar(Group const &other) const
Compare two groups.
Definition group.hpp:125
size_t rank() const
Get the rank of the calling process in the group.
Definition group.hpp:240
bool is_identical(Group const &other) const
Compare two groups.
Definition group.hpp:118
Group & operator=(Group &&other)
Move assignment.
Definition group.hpp:57
size_t size() const
Get the number of ranks in the group.
Definition group.hpp:231
Group set_union(Group const &other) const
Makes a group from the union of two groups.
Definition group.hpp:160
GroupEquality compare(Group const &other) const
Compare two groups.
Definition group.hpp:97
~Group()
Default destructor, freeing the encapsulated group if owned.
Definition group.hpp:78
Group(Comm const &comm)
Constructs the group associated with a communicator.
Definition group.hpp:66
void translate_ranks_to_group(In ranks_in_this_group_begin, In ranks_in_this_group_end, Out ranks_in_other_group_begin, Group const &other_group) const
Translates multiple ranks relative to this group to ranks relative to another group.
Definition group.hpp:195
Group intersection(Group const &other) const
Makes a group from the intersection of two groups.
Definition group.hpp:149
std::optional< int > translate_rank_to_group(int rank_in_this_group, Group const &other_group) const
Translates a rank relative to this group to a rank relative to another group.
Definition group.hpp:172
MPI_Group mpi_group() const
Native MPI_Group handle corresponding to this Group.
Definition group.hpp:249
Group(Group &&other)
Move constructor.
Definition group.hpp:50
Group(MPI_Group group, bool owning=false)
Constructs a new group from an existing MPI group.
Definition group.hpp:44
Group difference(Group const &other) const
Makes a group from the difference of two groups.
Definition group.hpp:140
bool has_same_ranks(Group const &other) const
Compare two groups.
Definition group.hpp:132
static Group empty()
Constructs an empty group.
Definition group.hpp:73
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
Code for error handling.
#define THROW_IF_MPI_ERROR(error_code, function)
Wrapper around THROWING_KAMPING_ASSERT for MPI errors.
Definition error_handling.hpp:34
GroupEquality
Describes the equality of two groups.
Definition group.hpp:33
@ Similar
Only the members are the same, the order is different.
@ Invalid
Tried to convert an invalid value to a GroupEquality.
@ Identical
The order and members of the two groups are the same.