NeoN
A framework for CFD software
Loading...
Searching...
No Matches
halfDuplexCommBuffer.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2023 - 2025 NeoN authors
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <string>
8#include <typeindex>
9#include <vector>
10
11#include "NeoN/core/error.hpp"
14#include "NeoN/core/view.hpp"
15
16namespace NeoN
17{
18
19#ifdef NF_WITH_MPI_SUPPORT
20
21namespace mpi
22{
23
30inline int bufferHash(const std::string& str)
31{
32 // There is also an MPI environment value for that, but somehow it doesn't work using that
33 // Also reserve 10 tags for other uses
34 constexpr int maxTagValue = 32767 - 10;
35 std::size_t tag = std::hash<std::string> {}(str);
36 tag &= 0x7FFFFFFF; // turn 'int' signed bit to 0, MPI does not like negative tags.
37 return (static_cast<int>(tag) % maxTagValue) + 10;
38}
39
50class HalfDuplexCommBuffer
51{
52
53public:
54
58 HalfDuplexCommBuffer() = default;
59
63 ~HalfDuplexCommBuffer() = default;
64
71 HalfDuplexCommBuffer(MPIEnvironment mpiEnviron, std::vector<size_t> rankCommSize)
72 : mpiEnviron_(mpiEnviron)
73 {
74 setCommRankSize<char>(rankCommSize);
75 }
76
82 inline void setMPIEnvironment(MPIEnvironment mpiEnviron) { mpiEnviron_ = mpiEnviron; }
83
89 inline bool isCommInit() const { return tag_ != -1; }
90
97 template<typename valueType>
98 void setCommRankSize(std::vector<size_t> rankCommSize)
99 {
101 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
102 );
104 rankCommSize.size() == mpiEnviron_.sizeRank(),
105 "Rank size mismatch. " << rankCommSize.size() << " vs. " << mpiEnviron_.sizeRank()
106 );
107 typeSize_ = sizeof(valueType);
108 rankOffset_.resize(rankCommSize.size() + 1);
109 request_.resize(rankCommSize.size(), MPI_REQUEST_NULL);
110 updateDataSize([&](const size_t rank) { return rankCommSize[rank]; }, sizeof(valueType));
111 }
112
119 template<typename valueType>
120 void initComm(std::string commName)
121 {
123 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
124 );
125 setType<valueType>();
126 commName_ = commName;
127 tag_ = bufferHash(commName);
128 }
129
135 inline const std::string& getCommName() const { return commName_; }
136
141 bool isComplete();
142
146 void send();
147
152 void receive();
153
157 void waitComplete();
158
162 void finaliseComm();
163
171 template<typename valueType>
172 View<valueType> get(const size_t rank)
173 {
174 NF_DEBUG_ASSERT(isCommInit(), "Communication buffer is not initialised.");
175 NF_DEBUG_ASSERT(typeSize_ == sizeof(valueType), "Data type (size) mismatch.");
176 return View<valueType>(
177 reinterpret_cast<valueType*>(rankBuffer_.data() + rankOffset_[rank]),
178 (rankOffset_[rank + 1] - rankOffset_[rank]) / sizeof(valueType)
179 );
180 }
181
189 template<typename valueType>
190 View<const valueType> get(const size_t rank) const
191 {
192 NF_DEBUG_ASSERT(isCommInit(), "Communication buffer is not initialised.");
193 NF_DEBUG_ASSERT(typeSize_ == sizeof(valueType), "Data type (size) mismatch.");
194 return View<const valueType>(
195 reinterpret_cast<const valueType*>(rankBuffer_.data() + rankOffset_[rank]),
196 (rankOffset_[rank + 1] - rankOffset_[rank]) / sizeof(valueType)
197 );
198 }
199
200private:
201
202 int tag_ {-1}; /*< The tag for the communication. */
203 std::string commName_ {"unassigned"}; /*< The name of the communication. */
204 std::size_t typeSize_ {sizeof(char)}; /*< The data type currently stored in the buffer. */
205 MPIEnvironment mpiEnviron_; /*< The MPI environment. */
206 std::vector<MPI_Request> request_; /*< The MPI request for communication with each rank. */
207 std::vector<char> rankBuffer_; /*< The buffer data for all ranks. Never shrinks. */
208 std::vector<std::size_t>
209 rankOffset_; /*< The offset (in bytes) for a rank data in the buffer. */
210
214 template<typename valueType>
215 void setType()
216 {
218 !isCommInit(), "Communication buffer was initialised by name: " << commName_ << "."
219 );
220 if (0 == (typeSize_ - sizeof(valueType))) return;
221 updateDataSize(
222 [rankOffset = rankOffset_, typeSize = typeSize_](const size_t rank)
223 { return (rankOffset[rank + 1] - rankOffset[rank]) / typeSize; },
224 sizeof(valueType)
225 );
226
227 typeSize_ = sizeof(valueType);
228 }
229
237 template<typename func>
238 void updateDataSize(func rankSize, std::size_t newSize)
239 {
240 std::size_t dataSize = 0;
241 for (size_t rank = 0; rank < mpiEnviron_.sizeRank(); ++rank)
242 {
243 rankOffset_[rank] = dataSize;
244 dataSize += rankSize(rank) * newSize;
245 }
246 rankOffset_.back() = dataSize;
247 if (rankBuffer_.size() < dataSize) rankBuffer_.resize(dataSize); // we never size down.
248 }
249};
250
251} // namespace mpi
252
253#endif
254
255}
#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:213
Definition array.hpp:20