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