mpiutil.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
27#ifndef OPM_MATERIAL_MPIUTIL_HH
28#define OPM_MATERIAL_MPIUTIL_HH
29
30#include <dune/common/parallel/mpitraits.hh>
31
32#include <cassert>
33#include <numeric>
34#include <string>
35#include <vector>
36
37
38#if HAVE_MPI
39
40#include <mpi.h>
41
42
43
45{
46
47 template <typename T>
49 {
50 int pack_size;
51 MPI_Pack_size(1, Dune::MPITraits<T>::getType(), MPI_COMM_WORLD, &pack_size);
52 return pack_size;
53 }
54
55 // -------- Packer --------
56 template <typename T>
57 struct Packer
58 {
59 static int size(const T&)
60 {
61 return packSize<T>();
62 }
63
64 static void pack(const T& content, std::vector<char>& buf, int& offset)
65 {
66 MPI_Pack(&content, 1, Dune::MPITraits<T>::getType(), buf.data(), buf.size(), &offset, MPI_COMM_WORLD);
67 }
68
69 static T unpack(const std::vector<char>& recv_buffer, int& offset)
70 {
71 T content;
72 auto* data = const_cast<char*>(recv_buffer.data());
73 MPI_Unpack(data, recv_buffer.size(), &offset, &content, 1, Dune::MPITraits<T>::getType(), MPI_COMM_WORLD);
74 return content;
75 }
76 };
77
78 // -------- Packer, string specialization --------
79 template <>
80 struct Packer<std::string>
81 {
82 static int size(const std::string& content)
83 {
84 return packSize<unsigned int>() + content.size()*packSize<char>();
85 }
86
87 static void pack(const std::string& content, std::vector<char>& buf, int& offset)
88 {
89 unsigned int size = content.size();
90 Packer<unsigned int>::pack(size, buf, offset);
91 if (size > 0) {
92 MPI_Pack(const_cast<char*>(content.c_str()), size, MPI_CHAR, buf.data(), buf.size(), &offset, MPI_COMM_WORLD);
93 }
94 }
95
96 static std::string unpack(const std::vector<char>& recv_buffer, int& offset)
97 {
98 unsigned int size = Packer<unsigned int>::unpack(recv_buffer, offset);
99 std::string text;
100 if (size > 0) {
101 auto* data = const_cast<char*>(recv_buffer.data());
102 std::vector<char> chars(size);
103 MPI_Unpack(data, recv_buffer.size(), &offset, chars.data(), size, MPI_CHAR, MPI_COMM_WORLD);
104 text = std::string(chars.data(), size);
105 }
106 return text;
107 }
108 };
109
110 // -------- Packer, vector partial specialization --------
111 template <typename T>
112 struct Packer<std::vector<T>>
113 {
114 static int size(const std::string& content)
115 {
116 int sz = 0;
117 sz += packSize<unsigned int>();
118 for (const T& elem : content) {
119 sz += Packer<T>::size(elem);
120 }
121 return sz;
122 }
123
124 static void pack(const std::vector<T>& content, std::vector<char>& buf, int& offset)
125 {
126 unsigned int size = content.size();
127 Packer<unsigned int>::pack(size, buf, offset);
128 for (const T& elem : content) {
129 Packer<T>::pack(elem);
130 }
131 }
132
133 static std::vector<T> unpack(const std::vector<char>& recv_buffer, int& offset)
134 {
135 unsigned int size = Packer<T>::unpack(recv_buffer, offset);
136 std::vector<T> content;
137 content.reserve(size);
138 for (unsigned int i = 0; i < size; ++i) {
139 content.push_back(Packer<T>::unpack(recv_buffer, offset));
140 }
141 return content;
142 }
143 };
144
145
146} // anonymous namespace
147
148
149namespace Opm
150{
151
153 inline std::vector<std::string> gatherStrings(const std::string& local_string)
154 {
155 using StringPacker = mpiutil_details::Packer<std::string>;
156
157 // Pack local messages.
158 const int message_size = StringPacker::size(local_string);
159 std::vector<char> buffer(message_size);
160 int offset = 0;
161 StringPacker::pack(local_string, buffer, offset);
162 assert(offset == message_size);
163
164 // Get message sizes and create offset/displacement array for gathering.
165 int num_processes = -1;
166 MPI_Comm_size(MPI_COMM_WORLD, &num_processes);
167 std::vector<int> message_sizes(num_processes);
168 MPI_Allgather(&message_size, 1, MPI_INT, message_sizes.data(), 1, MPI_INT, MPI_COMM_WORLD);
169 std::vector<int> displ(num_processes + 1, 0);
170 std::partial_sum(message_sizes.begin(), message_sizes.end(), displ.begin() + 1);
171
172 // Gather.
173 std::vector<char> recv_buffer(displ.back());
174 MPI_Allgatherv(buffer.data(), buffer.size(), MPI_PACKED,
175 const_cast<char*>(recv_buffer.data()), message_sizes.data(),
176 displ.data(), MPI_PACKED,
177 MPI_COMM_WORLD);
178
179 // Unpack and return.
180 std::vector<std::string> ret;
181 for (int process = 0; process < num_processes; ++process) {
182 offset = displ[process];
183 std::string s = StringPacker::unpack(recv_buffer, offset);
184 if (!s.empty()) {
185 ret.push_back(s);
186 }
187 assert(offset == displ[process + 1]);
188 }
189 return ret;
190 }
191
192} // namespace Opm
193
194#else // HAVE_MPI
195
196namespace Opm
197{
198 inline std::vector<std::string> gatherStrings(const std::string& local_string)
199 {
200 if (local_string.empty()) {
201 return {};
202 } else {
203 return { local_string };
204 }
205 }
206} // namespace Opm
207
208#endif // HAVE_MPI
209
210#endif // OPM_MATERIAL_MPIUTIL_HH
211
Definition: blackoilboundaryratevector.hh:37
std::vector< std::string > gatherStrings(const std::string &local_string)
From each rank, gather its string (if not empty) into a vector.
Definition: mpiutil.hh:153
Definition: mpiutil.hh:45
int packSize()
Definition: mpiutil.hh:48
static void pack(const std::string &content, std::vector< char > &buf, int &offset)
Definition: mpiutil.hh:87
static int size(const std::string &content)
Definition: mpiutil.hh:82
static std::string unpack(const std::vector< char > &recv_buffer, int &offset)
Definition: mpiutil.hh:96
static void pack(const std::vector< T > &content, std::vector< char > &buf, int &offset)
Definition: mpiutil.hh:124
static int size(const std::string &content)
Definition: mpiutil.hh:114
static std::vector< T > unpack(const std::vector< char > &recv_buffer, int &offset)
Definition: mpiutil.hh:133
Definition: mpiutil.hh:58
static int size(const T &)
Definition: mpiutil.hh:59
static void pack(const T &content, std::vector< char > &buf, int &offset)
Definition: mpiutil.hh:64
static T unpack(const std::vector< char > &recv_buffer, int &offset)
Definition: mpiutil.hh:69