Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
MessagePassingUtils.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* MessagePassingUtils.h (C) 2000-2026 */
9/* */
10/* Various utilities to handle message passing. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_MESSAGEPASSINGUTILS_H
13#define ARCCORE_ALINA_MESSAGEPASSINGUTILS_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * This file is based on the work on AMGCL library (version march 2026)
18 * which can be found at https://github.com/ddemidov/amgcl.
19 *
20 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
21 * SPDX-License-Identifier: MIT
22 */
23/*---------------------------------------------------------------------------*/
24/*---------------------------------------------------------------------------*/
25
26#include "arccore/base/FixedArray.h"
27#include "arccore/common/Array.h"
28
29#include "arccore/message_passing_mpi/StandaloneMpiMessagePassingMng.h"
31#include "arccore/message_passing/PointToPointMessageInfo.h"
32
33#include "arccore/alina/ValueTypeInterface.h"
34#include "arccore/alina/AlinaUtils.h"
35
36#include <vector>
37#include <numeric>
38#include <complex>
39#include <type_traits>
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44namespace Arcane::Alina
45{
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
51struct mpi_init
52{
53 mpi_init(int* argc, char*** argv)
54 {
55 MPI_Init(argc, argv);
56 }
57
58 ~mpi_init()
59 {
60 MPI_Finalize();
61 }
62};
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
68struct mpi_init_thread
69{
70 mpi_init_thread(int* argc, char*** argv)
71 {
72 int _;
73 MPI_Init_thread(argc, argv, MPI_THREAD_MULTIPLE, &_);
74 }
75
76 ~mpi_init_thread()
77 {
78 MPI_Finalize();
79 }
80};
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
87struct mpi_communicator
88{
89 MPI_Comm comm = MPI_COMM_NULL;
90 int rank = 0;
91 int size = 0;
92 Ref<IMessagePassingMng> m_message_passing_mng;
93
94 mpi_communicator() = default;
95
96 explicit mpi_communicator(MPI_Comm comm)
97 : comm(comm)
98 {
99 MPI_Comm_rank(comm, &rank);
100 MPI_Comm_size(comm, &size);
102 };
103
104 operator MPI_Comm() const
105 {
106 return comm;
107 }
108
110 template <typename T>
111 std::vector<T> exclusive_sum(T n) const
112 {
113 // TODO: Use scan.
114 std::vector<T> v(size + 1);
115 v[0] = 0;
116 T v0 = n;
117 ConstArrayView<T> v0_view(1, &v0);
118 ArrayView<T> out_view(static_cast<Int32>(v.size()), &v[1]);
119 mpAllGather(m_message_passing_mng.get(), v0_view, out_view);
120 std::partial_sum(v.begin(), v.end(), v.begin());
121 return v;
122 }
123
124 std::complex<long double> reduceSum(const std::complex<long double>& lval) const
125 {
126 return _reduceSumForComplex(lval);
127 }
128 std::complex<double> reduceSum(const std::complex<double>& lval) const
129 {
130 return _reduceSumForComplex(lval);
131 }
132 std::complex<float> reduceSum(const std::complex<float>& lval) const
133 {
134 return _reduceSumForComplex(lval);
135 }
136
137 template <typename T> T reduceSum(const T& lval) const
138 {
139 return mpAllReduce(m_message_passing_mng.get(), MessagePassing::eReduceType::ReduceSum, lval);
140 }
141
142 void waitAll(ArrayView<MessagePassing::Request> requests) const
143 {
144 mpWaitAll(m_message_passing_mng.get(), requests);
145 }
146 void wait(MessagePassing::Request request) const
147 {
148 ArrayView<MessagePassing::Request> requests(1, &request);
149 mpWaitAll(m_message_passing_mng.get(), requests);
150 }
151
161 template <class Condition, class Message>
162 void check(const Condition& cond, const Message& message)
163 {
164 int lc = static_cast<int>(cond);
165 int gc = _reduce(MPI_PROD, lc);
166
167 if (gc==0) {
168 IMessagePassingMng* pm = m_message_passing_mng.get();
169 UniqueArray<int> c(size);
170 if (rank == 0)
171 c.resize(size);
172 ConstArrayView<int> in_view(1, &lc);
173 mpGather(pm, in_view, c, 0);
174 if (rank == 0) {
175 std::cerr << "Failed assumption: " << message << std::endl;
176 std::cerr << "Offending processes:";
177 for (int i = 0; i < size; ++i)
178 if (!c[i])
179 std::cerr << " " << i;
180 std::cerr << std::endl;
181 }
182 mpBarrier(pm);
183 ARCCORE_FATAL("CheckError in MessagePassingUtils: {0}", message);
184 }
185 }
186
187 template <typename T> MessagePassing::Request
188 doIReceive(T* buf, int count, int source, int tag) const
189 {
190 using namespace Arcane::MessagePassing;
191 Span<T> s(buf, count);
192 Span<unsigned char> schar(reinterpret_cast<unsigned char*>(s.data()), s.sizeBytes());
193 PointToPointMessageInfo msg_info(MessageRank{ source }, MessageTag{ tag }, eBlockingType::NonBlocking);
194 return mpReceive(m_message_passing_mng.get(), schar, msg_info);
195 }
196
197 template <typename T> void
198 doReceive(T* buf, int count, int source, int tag) const
199 {
200 using namespace Arcane::MessagePassing;
201 Span<T> s(buf, count);
202 Span<unsigned char> schar(reinterpret_cast<unsigned char*>(s.data()), s.sizeBytes());
203 PointToPointMessageInfo msg_info(MessageRank{ source }, MessageTag{ tag }, eBlockingType::Blocking);
204 mpReceive(m_message_passing_mng.get(), schar, msg_info);
205 }
206
207 template <typename T> MessagePassing::Request
208 doISend(const T* buf, int count, int dest, int tag) const
209 {
210 using namespace Arcane::MessagePassing;
211 Span<const T> s(buf, count);
212 Span<const unsigned char> schar(reinterpret_cast<const unsigned char*>(s.data()), s.sizeBytes());
213 PointToPointMessageInfo msg_info(MessageRank{ dest }, MessageTag{ tag }, eBlockingType::NonBlocking);
214 return mpSend(m_message_passing_mng.get(), schar, msg_info);
215 }
216
217 template <typename T> void
218 doSend(const T* buf, int count, int dest, int tag) const
219 {
220 using namespace Arcane::MessagePassing;
221 Span<const T> s(buf, count);
222 Span<const unsigned char> schar(reinterpret_cast<const unsigned char*>(s.data()), s.sizeBytes());
223 PointToPointMessageInfo msg_info(MessageRank{ dest }, MessageTag{ tag }, eBlockingType::Blocking);
224 mpSend(m_message_passing_mng.get(), schar, msg_info);
225 }
226
227 private:
228
229 int _reduce(MPI_Op op, int lval) const
230 {
231 int gval = 0;
232
233 MPI_Allreduce((void*)&lval, &gval, 1, MPI_INT, op, comm);
234 return gval;
235 }
236
237 template <typename T> std::complex<T>
238 _reduceSumForComplex(const std::complex<T>& lval) const
239 {
240 // Specialisation for 'std::complex<float>' as 2 float.
241 FixedArray<T, 2> values = { { lval.real(), lval.imag() } };
242 mpAllReduce(m_message_passing_mng.get(), MessagePassing::eReduceType::ReduceSum, values.view());
243 return std::complex<T>(values[0], values[1]);
244 }
245};
246
247/*---------------------------------------------------------------------------*/
248/*---------------------------------------------------------------------------*/
249
250} // namespace Arcane::Alina
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255#endif
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
Brief list of message exchange functions.
Modifiable view of an array of type T.
void resize(Int64 s)
Changes the number of elements in the array to s.
Constant view of an array of type T.
constexpr __host__ __device__ ArrayView< T > view()
Modifiable view of the array.
Interface of the message passing manager.
static Ref< IMessagePassingMng > createRef(MPI_Comm comm, bool clean_comm=false)
Creates a manager associated with the communicator comm.
Information for sending/receiving a point-to-point message.
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
View of an array of elements of type T.
Definition Span.h:633
1D data vector with value semantics (STL style).
Declarations of types and methods used by message exchange mechanisms.
C void mpGather(IMessagePassingMng *pm, Span< const char > send_buf, Span< char > recv_buf, Int32 rank)
C char mpAllReduce(IMessagePassingMng *pm, eReduceType rt, char v)
void mpBarrier(IMessagePassingMng *pm)
Performs a barrier.
Definition Messages.cc:249
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
allGather() message for serialization
Definition Messages.cc:309
void mpWaitAll(IMessagePassingMng *pm, ArrayView< Request > requests)
Blocks until the requests in requests are finished.
Definition Messages.cc:164
Request mpReceive(IMessagePassingMng *pm, ISerializer *values, const PointToPointMessageInfo &message)
Receive message using an ISerializer.
Definition Messages.cc:290
Request mpSend(IMessagePassingMng *pm, const ISerializer *values, const PointToPointMessageInfo &message)
Send message using an ISerializer.
Definition Messages.cc:279
std::int32_t Int32
Signed integer type of 32 bits.
void check(const Condition &cond, const Message &message)
Communicator-wise condition checking.
std::vector< T > exclusive_sum(T n) const
Exclusive sum over mpi communicator.