OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
MPIHelper.cpp
Go to the documentation of this file.
1//
2// Global functions MPIHelper
3//
4// Copyright (c) 2010 - 2013, Yves Ineichen, ETH Zürich
5// All rights reserved
6//
7// Implemented as part of the PhD thesis
8// "Toward massively parallel multi-objective optimization with application to
9// particle accelerators" (https://doi.org/10.3929/ethz-a-009792359)
10//
11// This file is part of OPAL.
12//
13// OPAL is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// You should have received a copy of the GNU General Public License
19// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
20//
21#include <cstddef>
22#include <cstring>
23#include <iomanip>
24#include <limits>
25#include <string>
26
27#include "Util/MPIHelper.h"
28
29namespace {
30
32void writeString(std::ostream& os, const std::string& s) {
33 os << s.size() << ' ' << s;
34}
35
36void readString(std::istream& is, std::string& s) {
37 std::size_t n = 0;
38 is >> n;
39 is.get(); // consume the single separator space
40 s.resize(n);
41 is.read(&s[0], n);
42}
43
44} // namespace
45
46void serialize(Param_t params, std::ostringstream& os) {
47
48 os << std::setprecision(std::numeric_limits<double>::max_digits10);
49 os << params.size();
50 for (const auto& kv : params) {
51 os << ' ';
52 writeString(os, kv.first);
53 os << ' ' << kv.second;
54 }
55}
56
57void serialize(reqVarContainer_t reqvars, std::ostringstream& os) {
58
59 os << reqvars.size();
60 for (const auto& kv : reqvars) {
61 os << ' ';
62 writeString(os, kv.first);
63 os << ' ';
64 kv.second.writeState(os);
65 }
66}
67
68void deserialize(const char* buffer, std::size_t buf_size, Param_t& params) {
69
70 params.clear();
71 std::istringstream is(std::string(buffer, buf_size));
72
73 std::size_t n = 0;
74 is >> n;
75 for (std::size_t i = 0; i < n; ++i) {
76 std::string key;
77 readString(is, key);
78 double value = 0.0;
79 is >> value;
80 params[key] = value;
81 }
82}
83
84void deserialize(const char* buffer, std::size_t buf_size, reqVarContainer_t& reqvars) {
85
86 reqvars.clear();
87 std::istringstream is(std::string(buffer, buf_size));
88
89 std::size_t n = 0;
90 is >> n;
91 for (std::size_t i = 0; i < n; ++i) {
92 std::string key;
93 readString(is, key);
94 reqVarInfo_t info;
95 info.readState(is);
96 reqvars[key] = info;
97 }
98}
99
100void MPI_Bcast_params(Param_t& params, std::size_t root, MPI_Comm comm) {
101
102 int pid = 0;
103 std::size_t my_pid = 0;
104 MPI_Comm_rank(comm, &pid);
105 my_pid = static_cast<std::size_t>(pid);
106
107 std::size_t buf_size = 0;
108 std::ostringstream os;
109
110 if (my_pid == root) {
111 serialize(params, os);
112 buf_size = os.str().length();
113 }
114
115 MPI_Bcast(&buf_size, 1, MPI_UNSIGNED_LONG, root, comm);
116
117 char *buffer = new char[buf_size];
118 if (my_pid == root) std::memcpy(buffer, os.str().c_str(), buf_size);
119
120 MPI_Bcast(buffer, buf_size, MPI_CHAR, root, comm);
121 if (my_pid != root) deserialize(buffer, buf_size, params);
122
123 delete[] buffer;
124}
125
126void MPI_Send_params(Param_t params, std::size_t pid, MPI_Comm comm) {
127
128 std::ostringstream os;
129 serialize(params, os);
130 std::size_t buf_size = os.str().length();
131
132 MPI_Send(&buf_size, 1, MPI_UNSIGNED_LONG, pid,
134
135 char *buffer = new char[buf_size];
136 std::memcpy(buffer, os.str().c_str(), buf_size);
137
138 MPI_Send(buffer, buf_size, MPI_CHAR, pid,
140
141 delete[] buffer;
142}
143
144std::pair<std::size_t*, char*> MPI_ISend_params(Param_t params, std::size_t pid,
145 MPI_Comm comm, MPI_Request *req) {
146
147 std::ostringstream os;
148 serialize(params, os);
149 std::size_t* buf_size = new std::size_t();
150 *buf_size = os.str().length();
151
152 MPI_Isend(buf_size, 1, MPI_UNSIGNED_LONG, pid,
154
155 char *buffer = new char[*buf_size];
156 std::memcpy(buffer, os.str().c_str(), *buf_size);
157
158 MPI_Isend(buffer, *buf_size, MPI_CHAR, pid,
160
161 std::pair<std::size_t*, char*> p(buf_size, buffer);
162
163 return p;
164}
165
166void MPI_Recv_params(Param_t& params, std::size_t pid, MPI_Comm comm) {
167
168 MPI_Status status;
169 std::size_t buf_size = 0;
170 MPI_Recv(&buf_size, 1, MPI_UNSIGNED_LONG, pid,
171 MPI_EXCHANGE_SERIALIZED_DATA_TAG, comm, &status);
172
173 char *buffer = new char[buf_size]();
174
175 MPI_Recv(buffer, buf_size, MPI_CHAR, pid,
176 MPI_EXCHANGE_SERIALIZED_DATA_TAG, comm, &status);
177
178 deserialize(buffer, buf_size, params);
179
180 delete[] buffer;
181}
182
183void MPI_Send_reqvars(reqVarContainer_t reqvars, std::size_t pid, MPI_Comm comm) {
184
185 std::ostringstream os;
186 serialize(reqvars, os);
187 std::size_t buf_size = os.str().length();
188
189 MPI_Send(&buf_size, 1, MPI_UNSIGNED_LONG, pid,
191
192 char *buffer = new char[buf_size];
193 std::memcpy(buffer, os.str().c_str(), buf_size);
194
195 MPI_Send(buffer, buf_size, MPI_CHAR, pid,
197
198 delete[] buffer;
199}
200
201void MPI_Recv_reqvars(reqVarContainer_t& reqvars, std::size_t pid, MPI_Comm comm) {
202
203 MPI_Status status;
204 std::size_t buf_size = 0;
205 MPI_Recv(&buf_size, 1, MPI_UNSIGNED_LONG, pid,
206 MPI_EXCHANGE_SERIALIZED_DATA_TAG, comm, &status);
207
208 char *buffer = new char[buf_size]();
209
210 MPI_Recv(buffer, buf_size, MPI_CHAR, pid,
211 MPI_EXCHANGE_SERIALIZED_DATA_TAG, comm, &status);
212
213 deserialize(buffer, buf_size, reqvars);
214
215 delete[] buffer;
216}
std::map< std::string, reqVarInfo_t > reqVarContainer_t
Definition Types.h:96
namedVariableCollection_t Param_t
Definition Types.h:52
void MPI_Send_reqvars(reqVarContainer_t reqvars, std::size_t pid, MPI_Comm comm)
std::pair< std::size_t *, char * > MPI_ISend_params(Param_t params, std::size_t pid, MPI_Comm comm, MPI_Request *req)
void serialize(Param_t params, std::ostringstream &os)
serializes params to a text stream, replaces boost::serialization
Definition MPIHelper.cpp:46
void MPI_Send_params(Param_t params, std::size_t pid, MPI_Comm comm)
void MPI_Recv_reqvars(reqVarContainer_t &reqvars, std::size_t pid, MPI_Comm comm)
void MPI_Recv_params(Param_t &params, std::size_t pid, MPI_Comm comm)
void deserialize(const char *buffer, std::size_t buf_size, Param_t &params)
Definition MPIHelper.cpp:68
void MPI_Bcast_params(Param_t &params, std::size_t root, MPI_Comm comm)
broadcast params to all entities in comm
#define MPI_EXCHANGE_SERIALIZED_DATA_TAG
tag for exchanging serialized data
Definition MPIHelper.h:67