NeoFOAM
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
halfDuplexCommBuffer.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023 NeoFOAM authors
3#pragma once
4
5#include <span>
6#include <string>
7#include <typeindex>
8#include <vector>
9
13
14namespace NeoFOAM
15{
16
17#ifdef NF_WITH_MPI_SUPPORT
18
19namespace mpi
20{
21
28inline int bufferHash(const std::string& str)
29{
30 // There is also an MPI environment value for that, but somehow it doesn't work using that
31 // Also reserve 10 tags for other uses
32 constexpr int maxTagValue = 32767 - 10;
33 std::size_t tag = std::hash<std::string> {}(str);
34 tag &= 0x7FFFFFFF; // turn 'int' signed bit to 0, MPI does not like negative tags.
35 return (static_cast<int>(tag) % maxTagValue) + 10;
36}
37
48class HalfDuplexCommBuffer
49{
50
51public:
52
56 HalfDuplexCommBuffer() = default;
57
61 ~HalfDuplexCommBuffer() = default;
62
69 HalfDuplexCommBuffer(MPIEnvironment mpiEnviron, std::vector<size_t> rankCommSize)
70 : mpiEnviron_(mpiEnviron)
71 {
72 setCommRankSize<char>(rankCommSize);
73 }
74
80 inline void setMPIEnvironment(MPIEnvironment mpiEnviron) { mpiEnviron_ = mpiEnviron; }
81
87 inline bool isCommInit() const { return tag_ != -1; }
88
95 template<typename valueType>
96 void setCommRankSize(std::vector<size_t> rankCommSize)
97 {
99 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
100 );
102 rankCommSize.size() == mpiEnviron_.sizeRank(),
103 "Rank size mismatch. " << rankCommSize.size() << " vs. " << mpiEnviron_.sizeRank()
104 );
105 typeSize_ = sizeof(valueType);
106 rankOffset_.resize(rankCommSize.size() + 1);
107 request_.resize(rankCommSize.size(), MPI_REQUEST_NULL);
108 updateDataSize([&](const size_t rank) { return rankCommSize[rank]; }, sizeof(valueType));
109 }
110
117 template<typename valueType>
118 void initComm(std::string commName)
119 {
121 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
122 );
123 setType<valueType>();
124 commName_ = commName;
125 tag_ = bufferHash(commName);
126 }
127
133 inline const std::string& getCommName() const { return commName_; }
134
139 bool isComplete();
140
144 void send();
145
150 void receive();
151
155 void waitComplete();
156
160 void finaliseComm();
161
169 template<typename valueType>
170 std::span<valueType> get(const size_t rank)
171 {
172 NF_DEBUG_ASSERT(isCommInit(), "Communication buffer is not initialised.");
173 NF_DEBUG_ASSERT(typeSize_ == sizeof(valueType), "Data type (size) mismatch.");
174 return std::span<valueType>(
175 reinterpret_cast<valueType*>(rankBuffer_.data() + rankOffset_[rank]),
176 (rankOffset_[rank + 1] - rankOffset_[rank]) / sizeof(valueType)
177 );
178 }
179
187 template<typename valueType>
188 std::span<const valueType> get(const size_t rank) const
189 {
190 NF_DEBUG_ASSERT(isCommInit(), "Communication buffer is not initialised.");
191 NF_DEBUG_ASSERT(typeSize_ == sizeof(valueType), "Data type (size) mismatch.");
192 return std::span<const valueType>(
193 reinterpret_cast<const valueType*>(rankBuffer_.data() + rankOffset_[rank]),
194 (rankOffset_[rank + 1] - rankOffset_[rank]) / sizeof(valueType)
195 );
196 }
197
198private:
199
200 int tag_ {-1}; /*< The tag for the communication. */
201 std::string commName_ {"unassigned"}; /*< The name of the communication. */
202 std::size_t typeSize_ {sizeof(char)}; /*< The data type currently stored in the buffer. */
203 MPIEnvironment mpiEnviron_; /*< The MPI environment. */
204 std::vector<MPI_Request> request_; /*< The MPI request for communication with each rank. */
205 std::vector<char> rankBuffer_; /*< The buffer data for all ranks. Never shrinks. */
206 std::vector<std::size_t>
207 rankOffset_; /*< The offset (in bytes) for a rank data in the buffer. */
208
212 template<typename valueType>
213 void setType()
214 {
216 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
217 );
218 if (0 == (typeSize_ - sizeof(valueType))) return;
219 updateDataSize(
220 [rankOffset = rankOffset_, typeSize = typeSize_](const size_t rank)
221 { return (rankOffset[rank + 1] - rankOffset[rank]) / typeSize; },
222 sizeof(valueType)
223 );
224
225 typeSize_ = sizeof(valueType);
226 }
227
235 template<typename func>
236 void updateDataSize(func rankSize, std::size_t newSize)
237 {
238 std::size_t dataSize = 0;
239 for (size_t rank = 0; rank < mpiEnviron_.sizeRank(); ++rank)
240 {
241 rankOffset_[rank] = dataSize;
242 dataSize += rankSize(rank) * newSize;
243 }
244 rankOffset_.back() = dataSize;
245 if (rankBuffer_.size() < dataSize) rankBuffer_.resize(dataSize); // we never size down.
246 }
247};
248
249} // namespace mpi
250
251#endif
252
253}
#define NF_DEBUG_ASSERT(condition, message)
Macro for asserting a condition and printing an error message if the condition is false (only in debu...
Definition error.hpp:211