openPMD-api
MPIBenchmarkReport.hpp
1 /* Copyright 2018-2021 Franz Poeschel
2  *
3  * This file is part of openPMD-api.
4  *
5  * openPMD-api is free software: you can redistribute it and/or modify
6  * it under the terms of of either the GNU General Public License or
7  * the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * openPMD-api 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 and the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * and the GNU Lesser General Public License along with openPMD-api.
19  * If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #pragma once
23 
24 #include "openPMD/config.hpp"
25 #if openPMD_HAVE_MPI
26 
27 #include "openPMD/Datatype.hpp"
28 #include "openPMD/Series.hpp"
29 
30 #include "string.h"
31 #include <map>
32 #include <mpi.h>
33 #include <tuple>
34 #include <vector>
35 
36 namespace openPMD
37 {
43 template <typename Duration>
45 {
46  MPI_Comm communicator;
47 
48  MPIBenchmarkReport(MPI_Comm);
49 
53  std::map<
54  std::tuple<
55  int, // rank
56  std::string, // jsonConfig
57  std::string, // extension
58  int, // thread size
59  Datatype,
61  std::pair<Duration, Duration> >
63 
64  enum Selector
65  {
66  RANK = 0,
67  COMPRESSION,
68  COMPRESSION_LEVEL,
69  BACKEND,
70  NRANKS,
71  DTYPE,
72  ITERATIONS
73  };
74 
86  void addReport(
87  int rootThread,
88  std::string jsonConfig,
89  std::string extension,
90  int threadSize,
91  Datatype dt,
92  Series::IterationIndex_t iterations,
93  std::pair<Duration, Duration> const &report);
94 
105  std::pair<Duration, Duration> getReport(
106  int rank,
107  std::string jsonConfig,
108  std::string extension,
109  int threadSize,
110  Datatype dt,
111  Series::IterationIndex_t iterations);
112 
113 private:
114  template <typename D, typename Dummy = D>
115  struct MPIDatatype
116  {};
117 
118  template <typename Dummy>
119  struct MPIDatatype<char, Dummy>
120  {
121  MPI_Datatype dt = MPI_CHAR;
122  };
123  template <typename Dummy>
124  struct MPIDatatype<unsigned char, Dummy>
125  {
126  MPI_Datatype dt = MPI_UNSIGNED_CHAR;
127  };
128  template <typename Dummy>
129  struct MPIDatatype<short, Dummy>
130  {
131  MPI_Datatype dt = MPI_SHORT;
132  };
133  template <typename Dummy>
134  struct MPIDatatype<int, Dummy>
135  {
136  MPI_Datatype dt = MPI_INT;
137  };
138  template <typename Dummy>
139  struct MPIDatatype<long, Dummy>
140  {
141  MPI_Datatype dt = MPI_LONG;
142  };
143  template <typename Dummy>
144  struct MPIDatatype<float, Dummy>
145  {
146  MPI_Datatype dt = MPI_FLOAT;
147  };
148  template <typename Dummy>
149  struct MPIDatatype<double, Dummy>
150  {
151  MPI_Datatype dt = MPI_DOUBLE;
152  };
153  template <typename Dummy>
154  struct MPIDatatype<unsigned short, Dummy>
155  {
156  MPI_Datatype dt = MPI_UNSIGNED_SHORT;
157  };
158  template <typename Dummy>
159  struct MPIDatatype<unsigned int, Dummy>
160  {
161  MPI_Datatype dt = MPI_UNSIGNED;
162  };
163  template <typename Dummy>
164  struct MPIDatatype<unsigned long, Dummy>
165  {
166  MPI_Datatype dt = MPI_UNSIGNED_LONG;
167  };
168  template <typename Dummy>
169  struct MPIDatatype<long double, Dummy>
170  {
171  MPI_Datatype dt = MPI_LONG_DOUBLE;
172  };
173  template <typename Dummy>
174  struct MPIDatatype<long long, Dummy>
175  {
176  MPI_Datatype dt = MPI_LONG_LONG_INT;
177  };
178 
179  MPIDatatype<typename Duration::rep> m_mpiDatatype;
180  MPI_Datatype mpiType = m_mpiDatatype.dt;
181 };
182 
183 // implementation
184 
185 template <typename Duration>
187  int rootThread,
188  std::string jsonConfig,
189  std::string extension,
190  int threadSize,
191  Datatype dt,
192  Series::IterationIndex_t iterations,
193  std::pair<Duration, Duration> const &report)
194 {
195  using rep = typename Duration::rep;
196  // auto mpi_dt = MPIDatatype<rep>::dt;
197  int rank;
198  MPI_Comm_rank(communicator, &rank);
199  int size;
200  MPI_Comm_size(communicator, &size);
201  MPI_Comm restricted;
202  MPI_Comm_split(
203  communicator, rank < threadSize ? 0 : MPI_UNDEFINED, rank, &restricted);
204  rep readWrite[2];
205  if (rank < threadSize)
206  {
207  readWrite[0] = report.first.count();
208  readWrite[1] = report.second.count();
209  }
210  rep *recv = nullptr;
211  if (rank == rootThread)
212  {
213  recv = new rep[2 * threadSize];
214  }
215 
216  if (restricted != MPI_COMM_NULL)
217  {
218  MPI_Gather(
219  readWrite,
220  2, // should be 2 but doesnt work then..
221  this->mpiType,
222  recv,
223  2,
224  this->mpiType,
225  rootThread,
226  restricted);
227  }
228 
229  if (rank == rootThread)
230  {
231  for (int i = 0; i < threadSize; i++)
232  {
233  Duration dWrite{recv[2 * i]};
234  Duration dRead{recv[2 * i + 1]};
235  this->durations.emplace(
236  std::make_tuple(
237  i, jsonConfig, extension, threadSize, dt, iterations),
238  std::make_pair(dWrite, dRead));
239  }
240  delete[] recv;
241  }
242  if (restricted != MPI_COMM_NULL)
243  {
244  MPI_Comm_free(&restricted);
245  }
246 }
247 
248 template <typename Duration>
250  : communicator{comm}
251 {}
252 
253 template <typename Duration>
254 std::pair<Duration, Duration> MPIBenchmarkReport<Duration>::getReport(
255  int rank,
256  std::string jsonConfig,
257  std::string extension,
258  int threadSize,
259  Datatype dt,
260  Series::IterationIndex_t iterations)
261 {
262  auto it = this->durations.find(std::make_tuple(
263  rank, jsonConfig, extension, threadSize, dt, iterations));
264  if (it == this->durations.end())
265  {
266  throw std::runtime_error(
267  "Requested report not found. (Reports are available on the root "
268  "thread only)");
269  }
270  else
271  {
272  return it->second;
273  }
274 }
275 
276 } // namespace openPMD
277 
278 #endif
Iteration::IterationIndex_t IterationIndex_t
An unsigned integer type, used to identify Iterations in a Series.
Definition: Series.hpp:313
Public definitions of openPMD-api.
Definition: Date.cpp:29
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:51
The report for a single benchmark produced by <openPMD/benchmark/mpi/MPIBenchmark>.
Definition: MPIBenchmarkReport.hpp:45
std::map< std::tuple< int, std::string, std::string, int, Datatype, Series::IterationIndex_t >, std::pair< Duration, Duration > > durations
Time needed for writing and reading per compression strategy and level.
Definition: MPIBenchmarkReport.hpp:62
void addReport(int rootThread, std::string jsonConfig, std::string extension, int threadSize, Datatype dt, Series::IterationIndex_t iterations, std::pair< Duration, Duration > const &report)
Add results for a certain compression strategy and level.
Definition: MPIBenchmarkReport.hpp:186
std::pair< Duration, Duration > getReport(int rank, std::string jsonConfig, std::string extension, int threadSize, Datatype dt, Series::IterationIndex_t iterations)
Retrieve the time measured for a certain compression strategy.
Definition: MPIBenchmarkReport.hpp:254