DASH  0.3.0
main.cpp
1 
6 #include <libdash.h>
7 #include <iostream>
8 #include <iomanip>
9 #include <string>
10 #ifdef MPI_IMPL_ID
11 #include <mpi.h>
12 #endif
13 
14 using std::cout;
15 using std::endl;
16 using std::setw;
17 using std::setprecision;
18 
19 typedef dash::util::Timer<
20  dash::util::TimeMeasure::Clock
21  > Timer;
22 
25 
26 typedef struct benchmark_params_t {
27  int reps;
28  int rounds;
30 
31 typedef struct measurement_t {
32  std::string testcase;
33  double time_total_s;
34 } measurement;
35 
36 enum experiment_t{
37  ARRAYSTRUCT = 0,
38  ARRAYDOUBLE,
39  DARTSTRUCT,
40  DARTDOUBLE,
41  DARTLAMBDA,
42  MPIDOUBLE
43 };
44 
45 #ifdef HAVE_ASSERT
46 #include <cassert>
47 #define ASSERT_EQ(_e, _a) do { \
48  assert((_e) == (_a)); \
49 } while (0)
50 #else
51 #define ASSERT_EQ(_e, _a) do { \
52  dash__unused(_e); \
53  dash__unused(_a); \
54 } while (0)
55 #endif
56 
57 std::array<const char*, 6> testcase_str {{
58  "reduce.arraystruct",
59  "reduce.arraydouble",
60  "reduce.dartstruct",
61  "reduce.dartdouble",
62  "reduce.dartlambda",
63  "reduce.mpidouble"
64  }};
65 
66 
67 void print_measurement_header();
68 void print_measurement_record(
69  const bench_cfg_params & cfg_params,
71  const benchmark_params & params);
72 
73 benchmark_params parse_args(int argc, char * argv[]);
74 
75 void print_params(
76  const dash::util::BenchmarkParams & bench_cfg,
77  const benchmark_params & params);
78 
79 
80 measurement evaluate(
81  int reps,
82  experiment_t testcase,
83  benchmark_params params);
84 
85 template<typename ValueType, typename BinaryOperation>
86 ValueType reduce_array(
87  const ValueType* l_first,
88  const ValueType* l_last,
89  const ValueType init,
90  BinaryOperation binary_op = dash::plus<ValueType>())
91 {
92  struct local_result {
93  ValueType l_result;
94  bool l_valid;
95  };
96 
97  auto & team = dash::Team::All();
98  auto myid = team.myid();
99  auto result = init;
100 
101  dash::Array<local_result> l_results(team.size(), team);
102  if (l_first != l_last) {
103  auto l_result = std::accumulate(std::next(l_first), l_last, *l_first, binary_op);
104  l_results.local[0].l_result = l_result;
105  l_results.local[0].l_valid = true;
106  } else {
107  l_results.local[0].l_valid = false;
108  }
109 
110  l_results.barrier();
111 
112  if (myid == 0) {
113  for (size_t i = 0; i < team.size(); i++) {
114  local_result lr = l_results[i];
115  if (lr.l_valid) {
116  result = binary_op(result, lr.l_result);
117  }
118  }
119  }
120  return result;
121 }
122 
123 typedef struct minmax{
124  float min, max;
125  struct minmax operator+(const minmax &other) const {
126  auto res = *this;
127  res.min += other.min;
128  res.max += other.max;
129  return res;
130  }
131 
132  struct minmax& operator+=(const minmax &other) {
133  auto& res = *this;
134  res.min += other.min;
135  res.max += other.max;
136  return res;
137  }
138 } minmax_t;
139 
140 static void minmax_fn(const void *invec, void *inoutvec, size_t, void *)
141 {
142  const minmax_t* minmax_in = static_cast<const minmax_t*>(invec);
143  minmax_t* minmax_out = static_cast<minmax_t*>(inoutvec);
144 
145  if (minmax_in->min < minmax_out->min) {
146  minmax_out->min = minmax_in->min;
147  }
148 
149  if (minmax_in->max > minmax_out->max) {
150  minmax_out->max = minmax_in->max;
151  }
152 }
153 
154 template<typename T>
155 static void minmax_lambda(const void *invec, void *inoutvec, size_t, void *userdata)
156 {
157  const minmax_t* minmax_in = static_cast<const minmax_t*>(invec);
158  minmax_t* minmax_out = static_cast<minmax_t*>(inoutvec);
159  T& fn = *static_cast<T*>(userdata);
160  *minmax_out = fn(*minmax_in, *minmax_out);
161 }
162 
163 int main(int argc, char** argv)
164 {
165  dash::init(&argc, &argv);
166 
167  Timer::Calibrate(0);
168 
169  measurement res;
170 
171  dash::util::BenchmarkParams bench_params("bench.14.reduce");
172  bench_params.print_header();
173  bench_params.print_pinning();
174 
175  benchmark_params params = parse_args(argc, argv);
176  auto bench_cfg = bench_params.config();
177 
178  print_params(bench_params, params);
179  print_measurement_header();
180 
181  int round = 0;
182 #ifdef MPI_IMPL_ID
183  std::array<experiment_t, 6> testcases{{
184  ARRAYSTRUCT,
185  ARRAYDOUBLE,
186  DARTSTRUCT,
187  DARTDOUBLE,
188  DARTLAMBDA,
189  MPIDOUBLE
190  }};
191 #else
192  std::array<experiment_t, 5> testcases{{
193  ARRAYSTRUCT,
194  ARRAYDOUBLE,
195  DARTSTRUCT,
196  DARTDOUBLE,
197  DARTLAMBDA
198  }};
199 #endif
200 
201  while(round < params.rounds) {
202  for(auto testcase : testcases){
203  res = evaluate(params.reps, testcase, params);
204  print_measurement_record(bench_cfg, res, params);
205  }
206  round++;
207  }
208 
209  if (dash::myid() == 0) {
210  cout << "Benchmark finished" << endl;
211  }
212 
213  dash::finalize();
214  return 0;
215 }
216 
217 measurement evaluate(int reps, experiment_t testcase, benchmark_params params)
218 {
219  measurement mes;
220 
221  auto r = dash::myid();
222 
223 
224  float lmin = r;
225  float lmax = 1000 - r;
226 
227  auto ts_tot_start = Timer::Now();
228 
229  for (int i = 0; i < reps; i++) {
230  if (testcase == ARRAYSTRUCT) {
231  minmax_t in{lmin, lmax};
232  minmax_t init{0.0, 0.0};
233  minmax_t out = reduce_array(&in, std::next(&in), init,
235  if (dash::myid() == 0) {
236  assert((int)out.min == (dash::size()-1)*(dash::size())/2);
237  assert((int)out.max == dash::size()*1000
238  - ((dash::size()-1)*(dash::size()))/2);
239  }
240  }
241  else if (testcase == ARRAYDOUBLE) {
242  double in = lmin + lmax;
243  double out = reduce_array(&in, std::next(&in), 0.0,
245  if (dash::myid() == 0) {
246  ASSERT_EQ((int)out, (dash::size()-1)*(dash::size())/2 + dash::size()*1000 - ((dash::size()-1)*(dash::size()))/2);
247  }
248  }
249  else if (testcase == DARTSTRUCT) {
250  minmax_t in{lmin, lmax};
251  minmax_t init{0.0, 0.0};
252  minmax_t out = dash::reduce(&in, std::next(&in), init, true);
253  ASSERT_EQ((int)out.min, (dash::size()-1)*(dash::size())/2);
254  ASSERT_EQ((int)out.max, dash::size()*1000 - ((dash::size()-1)*(dash::size()))/2);
255  } else if (testcase == DARTDOUBLE) {
256  double in = lmin + lmax;
257  double out = dash::reduce(&in, std::next(&in), 0.0, true);
258  ASSERT_EQ((int)out, (dash::size()-1)*(dash::size())/2 + dash::size()*1000 - ((dash::size()-1)*(dash::size()))/2);
259  } else if (testcase == DARTLAMBDA) {
260  double in = lmin + lmax;
261  double out = dash::reduce(&in, std::next(&in), 0.0,
262  [](double a, double b){ return a + b; });
263  ASSERT_EQ((int)out, (dash::size()-1)*(dash::size())/2 + dash::size()*1000 - ((dash::size()-1)*(dash::size()))/2);
264  }
265 #ifdef MPI_IMPL_ID
266  else if (testcase == MPIDOUBLE) {
267  double in = lmin + lmax;
268  double out;
269  MPI_Allreduce(&in, &out, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
270  ASSERT_EQ((int)out, (dash::size()-1)*(dash::size())/2 + dash::size()*1000 - ((dash::size()-1)*(dash::size()))/2);
271  }
272 #endif
273  }
274 
275  mes.time_total_s = Timer::ElapsedSince(ts_tot_start) / (double)reps / 1E6;
276  mes.testcase = testcase_str[testcase];
277  return mes;
278 }
279 
280 void print_measurement_header()
281 {
282  if (dash::myid() == 0) {
283  cout << std::right
284  << std::setw( 5) << "units" << ","
285  << std::setw( 9) << "mpi.impl" << ","
286  << std::setw(30) << "impl" << ","
287  << std::setw( 8) << "total.s"
288  << endl;
289  }
290 }
291 
292 void print_measurement_record(
293  const bench_cfg_params & cfg_params,
295  const benchmark_params & params)
296 {
297  if (dash::myid() == 0) {
298  std::string mpi_impl = dash__toxstr(MPI_IMPL_ID);
299  auto mes = measurement;
300  cout << std::right
301  << std::setw(5) << dash::size() << ","
302  << std::setw(9) << mpi_impl << ","
303  << std::fixed << setprecision(2) << setw(30) << mes.testcase << ","
304  << std::fixed << setprecision(8) << setw(12) << mes.time_total_s
305  << endl;
306  }
307 }
308 
309 benchmark_params parse_args(int argc, char * argv[])
310 {
311  benchmark_params params;
312  params.reps = 100;
313  params.rounds = 10;
314 
315  for (auto i = 1; i < argc; i += 2) {
316  std::string flag = argv[i];
317  if (flag == "-r") {
318  params.reps = atoi(argv[i+1]);
319  }
320  if (flag == "-n") {
321  params.rounds = atoi(argv[i+1]);
322  }
323  }
324  return params;
325 }
326 
327 void print_params(
328  const dash::util::BenchmarkParams & bench_cfg,
329  const benchmark_params & params)
330 {
331  if (dash::myid() != 0) {
332  return;
333  }
334 
335  bench_cfg.print_section_start("Runtime arguments");
336  bench_cfg.print_param("-r", "repetitions per round", params.reps);
337  bench_cfg.print_param("-n", "rounds", params.rounds);
338  bench_cfg.print_section_end();
339 }
global_unit_t myid()
Shortcut to query the global unit ID of the calling unit.
Reduce operands to their sum.
Definition: Operation.h:163
std::iterator_traits< LocalInputIter >::value_type reduce(LocalInputIter in_first, LocalInputIter in_last, InitType init, BinaryOperation binary_op=BinaryOperation(), bool non_empty=true, dash::Team &team=dash::Team::All())
Accumulate values in each process&#39; range [in_first, in_last) using the provided binary reduce functio...
Definition: Reduce.h:79
size_t size()
Return the number of units in the global team.
void finalize()
Finalize the DASH library and the underlying runtime system.
A distributed array.
Definition: Array.h:89
struct dash::dart_operation ValueType
Reduce operands to their minimum value.
Definition: main.cpp:123
static Team & All()
The invariant Team instance containing all available units.
Definition: Team.h:213
void init(int *argc, char ***argv)
Initialize the DASH library and the underlying runtime system.