1 // Copyright (C) 2006 Trustees of Indiana University
2 //
3 // Authors: Douglas Gregor
4 // Andrew Lumsdaine
5
6 // Use, modification and distribution is subject to the Boost Software
7 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9
10 // Performance test of the reduce() collective
11 #include <boost/mpi.hpp>
12 #include <boost/lexical_cast.hpp>
13
14 namespace mpi = boost::mpi;
15
16 struct add_int {
operator ()add_int17 int operator()(int x, int y) const { return x + y; }
18 };
19
20 struct wrapped_int
21 {
wrapped_intwrapped_int22 wrapped_int() : value(0) { }
wrapped_intwrapped_int23 wrapped_int(int value) : value(value) { }
24
25 template<typename Archiver>
serializewrapped_int26 void serialize(Archiver& ar, const unsigned int /*version*/) {
27 ar & value;
28 }
29
30 int value;
31 };
32
operator +(wrapped_int x,wrapped_int y)33 inline wrapped_int operator+(wrapped_int x, wrapped_int y)
34 {
35 return wrapped_int(x.value + y.value);
36 }
37
38 namespace boost { namespace mpi {
39 template<> struct is_mpi_datatype<wrapped_int> : mpl::true_ { };
40 } }
41
42 struct serialized_int
43 {
serialized_intserialized_int44 serialized_int() : value(0) { }
serialized_intserialized_int45 serialized_int(int value) : value(value) { }
46
47 template<typename Archiver>
serializeserialized_int48 void serialize(Archiver& ar, const unsigned int /*version*/) {
49 ar & value;
50 }
51
52 int value;
53 };
54
operator +(serialized_int x,serialized_int y)55 inline serialized_int operator+(serialized_int x, serialized_int y)
56 {
57 return serialized_int(x.value + y.value);
58 }
59
main(int argc,char * argv[])60 int main(int argc, char* argv[])
61 {
62 mpi::environment env(argc, argv);
63 mpi::communicator world;
64
65 int repeat_count = 100;
66 int outer_repeat_count = 2;
67
68 if (argc > 1) repeat_count = boost::lexical_cast<int>(argv[1]);
69 if (argc > 2) outer_repeat_count = boost::lexical_cast<int>(argv[2]);
70
71 if (world.rank() == 0)
72 std::cout << "# of processors: " << world.size() << std::endl
73 << "# of iterations: " << repeat_count << std::endl;
74
75 int value = world.rank();
76 int result;
77 wrapped_int wi_value = world.rank();
78 wrapped_int wi_result;
79 serialized_int si_value = world.rank();
80 serialized_int si_result;
81
82 // Spin for a while...
83 for (int i = 0; i < repeat_count/10; ++i) {
84 reduce(world, value, result, std::plus<int>(), 0);
85 reduce(world, value, result, add_int(), 0);
86 reduce(world, wi_value, wi_result, std::plus<wrapped_int>(), 0);
87 reduce(world, si_value, si_result, std::plus<serialized_int>(), 0);
88 }
89
90 for (int outer = 0; outer < outer_repeat_count; ++outer) {
91 // Raw MPI
92 mpi::timer time;
93 for (int i = 0; i < repeat_count; ++i) {
94 MPI_Reduce(&value, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
95 }
96 double reduce_raw_mpi_total_time = time.elapsed();
97
98 // MPI_INT/MPI_SUM case
99 time.restart();
100 for (int i = 0; i < repeat_count; ++i) {
101 reduce(world, value, result, std::plus<int>(), 0);
102 }
103 double reduce_int_sum_total_time = time.elapsed();
104
105 // MPI_INT/MPI_Op case
106 time.restart();
107 for (int i = 0; i < repeat_count; ++i) {
108 reduce(world, value, result, add_int(), 0);
109 }
110 double reduce_int_op_total_time = time.elapsed();
111
112 // MPI_Datatype/MPI_Op case
113 time.restart();
114 for (int i = 0; i < repeat_count; ++i) {
115 reduce(world, wi_value, wi_result, std::plus<wrapped_int>(), 0);
116 }
117 double reduce_type_op_total_time = time.elapsed();
118
119 // Serialized/MPI_Op case
120 time.restart();
121 for (int i = 0; i < repeat_count; ++i) {
122 reduce(world, si_value, si_result, std::plus<serialized_int>(), 0);
123 }
124 double reduce_ser_op_total_time = time.elapsed();
125
126
127 if (world.rank() == 0)
128 std::cout << "\nInvocation\tElapsed Time (seconds)"
129 << "\nRaw MPI\t\t\t" << reduce_raw_mpi_total_time
130 << "\nMPI_INT/MPI_SUM\t\t" << reduce_int_sum_total_time
131 << "\nMPI_INT/MPI_Op\t\t" << reduce_int_op_total_time
132 << "\nMPI_Datatype/MPI_Op\t" << reduce_type_op_total_time
133 << "\nSerialized/MPI_Op\t" << reduce_ser_op_total_time
134 << std::endl;
135 }
136
137 return 0;
138 }
139