]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (C) 2011 Júlio Hoffimann. |
2 | ||
3 | // Use, modification and distribution is subject to the Boost Software | |
4 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | // Message Passing Interface 1.1 -- Section 4.6. Scatterv | |
8 | #ifndef BOOST_MPI_SCATTERV_HPP | |
9 | #define BOOST_MPI_SCATTERV_HPP | |
10 | ||
11 | #include <boost/mpi/exception.hpp> | |
12 | #include <boost/mpi/datatype.hpp> | |
13 | #include <vector> | |
14 | #include <boost/mpi/packed_oarchive.hpp> | |
15 | #include <boost/mpi/packed_iarchive.hpp> | |
16 | #include <boost/mpi/detail/point_to_point.hpp> | |
17 | #include <boost/mpi/communicator.hpp> | |
18 | #include <boost/mpi/environment.hpp> | |
19 | #include <boost/assert.hpp> | |
20 | ||
21 | namespace boost { namespace mpi { | |
22 | ||
23 | namespace detail { | |
24 | // We're scattering from the root for a type that has an associated MPI | |
25 | // datatype, so we'll use MPI_Scatterv to do all of the work. | |
26 | template<typename T> | |
27 | void | |
28 | scatterv_impl(const communicator& comm, const T* in_values, const int* sizes, | |
29 | const int* displs, T* out_values, int out_size, int root, mpl::true_) | |
30 | { | |
31 | MPI_Datatype type = get_mpi_datatype<T>(*in_values); | |
32 | BOOST_MPI_CHECK_RESULT(MPI_Scatterv, | |
33 | (const_cast<T*>(in_values), const_cast<int*>(sizes), | |
34 | const_cast<int*>(displs), type, | |
35 | out_values, out_size, type, root, comm)); | |
36 | } | |
37 | ||
38 | // We're scattering from a non-root for a type that has an associated MPI | |
39 | // datatype, so we'll use MPI_Scatterv to do all of the work. | |
40 | template<typename T> | |
41 | void | |
42 | scatterv_impl(const communicator& comm, T* out_values, int out_size, int root, | |
43 | mpl::true_) | |
44 | { | |
45 | MPI_Datatype type = get_mpi_datatype<T>(*out_values); | |
46 | BOOST_MPI_CHECK_RESULT(MPI_Scatterv, | |
47 | (0, 0, 0, type, | |
48 | out_values, out_size, type, | |
49 | root, comm)); | |
50 | } | |
51 | ||
52 | // We're scattering from the root for a type that does not have an | |
53 | // associated MPI datatype, so we'll need to serialize | |
54 | // it. Unfortunately, this means that we cannot use MPI_Scatterv, so | |
55 | // we'll just have the root send individual messages to the other | |
56 | // processes. | |
57 | template<typename T> | |
58 | void | |
59 | scatterv_impl(const communicator& comm, const T* in_values, const int* sizes, | |
60 | const int* displs, T* out_values, int out_size, int root, mpl::false_) | |
61 | { | |
62 | int tag = environment::collectives_tag(); | |
63 | int nprocs = comm.size(); | |
64 | ||
65 | for (int dest = 0; dest < nprocs; ++dest) { | |
66 | if (dest == root) { | |
67 | // Our own values will never be transmitted: just copy them. | |
68 | std::copy(in_values + displs[dest], | |
69 | in_values + displs[dest] + out_size, out_values); | |
70 | } else { | |
71 | // Send archive | |
72 | packed_oarchive oa(comm); | |
73 | for (int i = 0; i < sizes[dest]; ++i) | |
74 | oa << in_values[ displs[dest] + i ]; | |
75 | detail::packed_archive_send(comm, dest, tag, oa); | |
76 | } | |
77 | } | |
78 | } | |
79 | ||
80 | // We're scattering to a non-root for a type that does not have an | |
81 | // associated MPI datatype, so we'll need to de-serialize | |
82 | // it. Unfortunately, this means that we cannot use MPI_Scatterv, so | |
83 | // we'll just have all of the non-root nodes send individual | |
84 | // messages to the root. | |
85 | template<typename T> | |
86 | void | |
87 | scatterv_impl(const communicator& comm, T* out_values, int out_size, int root, | |
88 | mpl::false_) | |
89 | { | |
90 | int tag = environment::collectives_tag(); | |
91 | ||
92 | packed_iarchive ia(comm); | |
93 | MPI_Status status; | |
94 | detail::packed_archive_recv(comm, root, tag, ia, status); | |
95 | for (int i = 0; i < out_size; ++i) | |
96 | ia >> out_values[i]; | |
97 | } | |
98 | } // end namespace detail | |
99 | ||
100 | template<typename T> | |
101 | void | |
102 | scatterv(const communicator& comm, const T* in_values, | |
103 | const std::vector<int>& sizes, const std::vector<int>& displs, | |
104 | T* out_values, int out_size, int root) | |
105 | { | |
106 | int rank = comm.rank(); | |
107 | if (rank == root) | |
108 | detail::scatterv_impl(comm, in_values, &sizes[0], &displs[0], | |
109 | out_values, out_size, root, is_mpi_datatype<T>()); | |
110 | else | |
111 | detail::scatterv_impl(comm, out_values, out_size, root, | |
112 | is_mpi_datatype<T>()); | |
113 | } | |
114 | ||
115 | template<typename T> | |
116 | void | |
117 | scatterv(const communicator& comm, const std::vector<T>& in_values, | |
118 | const std::vector<int>& sizes, const std::vector<int>& displs, | |
119 | T* out_values, int out_size, int root) | |
120 | { | |
121 | if (comm.rank() == root) | |
122 | ::boost::mpi::scatterv(comm, &in_values[0], sizes, displs, | |
123 | out_values, out_size, root); | |
124 | else | |
125 | ::boost::mpi::scatterv(comm, static_cast<const T*>(0), sizes, displs, | |
126 | out_values, out_size, root); | |
127 | } | |
128 | ||
129 | template<typename T> | |
130 | void scatterv(const communicator& comm, T* out_values, int out_size, int root) | |
131 | { | |
132 | BOOST_ASSERT(comm.rank() != root); | |
133 | detail::scatterv_impl(comm, out_values, out_size, root, is_mpi_datatype<T>()); | |
134 | } | |
135 | ||
136 | /////////////////////// | |
137 | // common use versions | |
138 | /////////////////////// | |
139 | template<typename T> | |
140 | void | |
141 | scatterv(const communicator& comm, const T* in_values, | |
142 | const std::vector<int>& sizes, T* out_values, int root) | |
143 | { | |
144 | int nprocs = comm.size(); | |
145 | int myrank = comm.rank(); | |
146 | ||
147 | std::vector<int> displs(nprocs); | |
148 | for (int rank = 0, aux = 0; rank < nprocs; ++rank) { | |
149 | displs[rank] = aux; | |
150 | aux += sizes[rank]; | |
151 | } | |
152 | ::boost::mpi::scatterv(comm, in_values, sizes, displs, out_values, | |
153 | sizes[myrank], root); | |
154 | } | |
155 | ||
156 | template<typename T> | |
157 | void | |
158 | scatterv(const communicator& comm, const std::vector<T>& in_values, | |
159 | const std::vector<int>& sizes, T* out_values, int root) | |
160 | { | |
161 | ::boost::mpi::scatterv(comm, &in_values[0], sizes, out_values, root); | |
162 | } | |
163 | ||
164 | } } // end namespace boost::mpi | |
165 | ||
166 | #endif // BOOST_MPI_SCATTERV_HPP |