Skip to content

Commit 9b51e65

Browse files
hmenkeMobellaaj
andcommitted
Expand API surface and test cases
This adds a new abstraction for MPI_Group to be able to use the post-start-complete-wait RMA cycle. Also adds documentation and more tests. Co-authored-by: Mohamed Aziz Bellaaj <[email protected]>
1 parent f61a0e6 commit 9b51e65

File tree

7 files changed

+758
-142
lines changed

7 files changed

+758
-142
lines changed

c++/mpi/communicator.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,29 @@ namespace mpi {
194194
}
195195
};
196196

197-
/// The shared communicator class
197+
/**
198+
* @ingroup mpi_osc_shm
199+
* @brief C++ wrapper around @p MPI_Comm that is a result of the @p split_shared operation.
200+
*
201+
* @details In the plain MPI C API it is not distinguishable whether an @p
202+
* MPI_Comm is local to a shared memory island or not. Thus we introduce an
203+
* extra type for that whose only purpose is to make that distinction on the
204+
* type-level to prevent wrong usage of the shared memory APIs.
205+
*/
198206
class shared_communicator : public communicator {};
199207

208+
/**
209+
* @brief Partition the communicator into subcommunicators according to their type.
210+
*
211+
* @details In the MPI3.0 standard the only supported split type is @p
212+
* MPI_COMM_TYPE_SHARED. OpenMPI (and possibly other implementations) provide
213+
* more custom split types, however, they are not portable.
214+
*
215+
* @param split_type Type of processes to be grouped together.
216+
* @param key Control of rank assignment.
217+
*
218+
* @return New communicator.
219+
*/
200220
[[nodiscard]] inline shared_communicator communicator::split_shared(int split_type, int key) const {
201221
if (has_env) {
202222
shared_communicator c;

c++/mpi/group.hpp

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright (c) 2024 Simons Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0.txt
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// Authors: Thomas Hahn, Alexander Hampel, Olivier Parcollet, Nils Wentzell
16+
17+
/**
18+
* @file
19+
* @brief Provides a C++ wrapper class for an @p MPI_Group object.
20+
*/
21+
22+
#pragma once
23+
24+
#include "./communicator.hpp"
25+
#include "./environment.hpp"
26+
27+
#include <mpi.h>
28+
29+
#include <cstdlib>
30+
#include <unistd.h>
31+
32+
namespace mpi {
33+
34+
/**
35+
* @ingroup mpi_essentials
36+
* @brief C++ wrapper around @p MPI_Group providing various convenience functions.
37+
*
38+
* @details It stores an @p MPI_Group object as its only member which by default is set to @p MPI_GROUP_NULL.
39+
*/
40+
class group {
41+
// Wrapped @p MPI_Group object.
42+
MPI_Group _grp = MPI_GROUP_NULL;
43+
44+
public:
45+
/// Construct a group with @p MPI_GROUP_NULL.
46+
group() = default;
47+
48+
/// Deleted copy constructor.
49+
group(group const &) = delete;
50+
51+
/// Deleted copy assignment operator.
52+
group &operator=(group const &) = delete;
53+
54+
/// Move constructor leaves moved-from object with @p MPI_GROUP_NULL.
55+
group(group &&other) noexcept : _grp{std::exchange(other._grp, MPI_GROUP_NULL)} {}
56+
57+
/// Move assignment operator leaves moved-from object with @p MPI_GROUP_NULL.
58+
group &operator=(group &&rhs) noexcept {
59+
if (this != std::addressof(rhs)) {
60+
this->free();
61+
this->_grp = std::exchange(rhs._grp, MPI_GROUP_NULL);
62+
}
63+
return *this;
64+
}
65+
66+
/// Destructor
67+
virtual ~group() { free(); }
68+
69+
/**
70+
* @brief Take ownership of an existing @p MPI_Group object.
71+
* @param grp The group to be handled.
72+
*/
73+
explicit group(MPI_Group grp) : _grp(grp) {}
74+
75+
/**
76+
* @brief Create a group from a communicator.
77+
* @param c The communicator from which to create a group.
78+
*/
79+
explicit group(communicator c) {
80+
if (has_env) { MPI_Comm_group(c.get(), &_grp); }
81+
}
82+
83+
/// Get the wrapped @p MPI_Group object.
84+
[[nodiscard]] MPI_Group get() const noexcept { return _grp; }
85+
86+
/// Check if the contained @p MPI_Group is @p MPI_GROUP_NULL.
87+
[[nodiscard]] bool is_null() const noexcept { return _grp == MPI_GROUP_NULL; }
88+
89+
/// Rank of the calling process in the given group.
90+
[[nodiscard]] int rank() const {
91+
int rank = 0;
92+
if (has_env) { MPI_Group_rank(_grp, &rank); }
93+
return rank;
94+
}
95+
96+
/// Size of a group.
97+
[[nodiscard]] int size() const {
98+
int size = 1;
99+
if (has_env) { MPI_Group_size(_grp, &size); }
100+
return size;
101+
}
102+
103+
/**
104+
* @brief Produces a group by reordering an existing group and taking only listed members.
105+
* @param ranks List of ranks to include in the new group.
106+
* @return New group containing only the listed members.
107+
*/
108+
group include(std::vector<int> const &ranks) const {
109+
MPI_Group newgroup = MPI_GROUP_NULL;
110+
if (has_env) { MPI_Group_incl(_grp, ranks.size(), ranks.data(), &newgroup); }
111+
return group(newgroup);
112+
}
113+
114+
/// Free the group.
115+
void free() {
116+
if (has_env) {
117+
if (_grp != MPI_GROUP_NULL) { MPI_Group_free(&_grp); }
118+
}
119+
}
120+
};
121+
122+
} // namespace mpi

0 commit comments

Comments
 (0)