Tpetra parallel linear algebra  Version of the Day
Tpetra_Details_MpiTypeTraits.hpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Tpetra: Templated Linear Algebra Services Package
6 // Copyright (2008) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ************************************************************************
41 // @HEADER
42 */
43 
44 #ifndef TPETRA_DETAILS_MPITYPETRAITS_HPP
45 #define TPETRA_DETAILS_MPITYPETRAITS_HPP
46 
70 
71 #include "TpetraCore_config.h"
72 #ifdef HAVE_TPETRACORE_MPI
73 
74 #include "Kokkos_Complex.hpp"
75 #include "Teuchos_Details_MpiTypeTraits.hpp"
76 // Include this file for uintptr_t.
77 // Windows (Visual Studio 2015) claims to have that type too:
78 //
79 // https://msdn.microsoft.com/en-us/library/323b6b3k.aspx
80 #include <cstdint>
81 
82 namespace Teuchos {
83 namespace Details {
84 
85 namespace Impl {
86 
97 template<class T>
98 MPI_Datatype
99 computeKokkosComplexMpiDatatype (const ::Kokkos::complex<T>& z)
100 {
101  static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
102  "works if MpiTypeTraits<T>::isSpecialized.");
103  static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
104  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
105  "leak memory.");
106  // We assume here that every instance of T has the same
107  // MPI_Datatype, i.e., has the same binary representation.
108  MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
109  MPI_Datatype outerDatatype; // return value
110 
111  // If Kokkos::complex<T> has the same layout as T[2], then we can
112  // use a contiguous derived MPI_Datatype. This is likely the only
113  // code path that will execute. Contiguous types are likely more
114  // efficient for MPI to execute, and almost certainly more efficient
115  // for MPI to set up.
116  if (sizeof ( ::Kokkos::complex<T>) == 2 * sizeof (T)) {
117  (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
118  }
119  else { // must use the general struct approach
120  // I borrowed and adapted the code below from the MPICH
121  // documentation:
122  //
123  // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
124  int blockLengths[3];
125  MPI_Aint arrayOfDisplacements[3];
126  MPI_Datatype arrayOfTypes[3];
127 
128  // See documentation of MyComplex (above) for explanation.
129  static_assert (sizeof (MyComplex<T>) == sizeof ( ::Kokkos::complex<T>),
130  "Attempt to construct a struct of the same size and layout "
131  "as Kokkos::complex<T> failed.");
132  ::Teuchos::Details::Impl::MyComplex<T> z2;
133 
134  // First entry in the struct.
135  blockLengths[0] = 1;
136  // Normally, &z2.re would equal &z2, but I'll be conservative and
137  // actually compute the offset, even though it's probably just 0.
138  //
139  // Need the cast to prevent the compiler complaining about
140  // subtracting addresses of different types.
141  arrayOfDisplacements[0] = reinterpret_cast<uintptr_t> (&z2.re) - reinterpret_cast<uintptr_t> (&z2);
142  arrayOfTypes[0] = innerDatatype;
143 
144  // Second entry in the struct.
145  blockLengths[1] = 1;
146  arrayOfDisplacements[1] = reinterpret_cast<uintptr_t> (&z2.im) - reinterpret_cast<uintptr_t> (&z2);
147  arrayOfTypes[1] = innerDatatype;
148 
149 #if MPI_VERSION < 2
150  // Upper bound of the struct.
151  blockLengths[2] = 1;
152  arrayOfDisplacements[2] = sizeof (MyComplex<T>);
153  arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
154 #endif // MPI_VERSION < 2
155 
156  // Define the MPI_Datatype.
157 #if MPI_VERSION < 2
158  (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
159  arrayOfTypes, &outerDatatype);
160 #else
161  // Don't include the upper bound with MPI_Type_create_struct.
162  (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
163  arrayOfTypes, &outerDatatype);
164 #endif // MPI_VERSION < 2
165  }
166 
167  MPI_Type_commit (&outerDatatype);
168  return outerDatatype;
169 }
170 
171 } // namespace Impl
172 
174 template<>
175 class MpiTypeTraits< ::Kokkos::complex<double> > {
176 private:
177 #if MPI_VERSION >= 3
178  static const bool hasMpi3 = true;
179 #else
180  static const bool hasMpi3 = false;
181 #endif // MPI_VERSION >= 3
182 
183 public:
185  static const bool isSpecialized = true;
186 
189  static const bool needsFree = ! hasMpi3;
190 
192  static MPI_Datatype getType (const ::Kokkos::complex<double>& z) {
193  if (hasMpi3) {
194 #if MPI_VERSION >= 3
195  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
196 #else
197  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
198 #endif // MPI_VERSION >= 3
199  }
200  else { // ! hasMpi3
201  return Impl::computeKokkosComplexMpiDatatype<double> (z);
202  }
203  }
204 
206  static MPI_Datatype getType () {
207  if (hasMpi3) {
208 #if MPI_VERSION >= 3
209  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
210 #else
211  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
212 #endif // MPI_VERSION >= 3
213  }
214  else { // ! hasMpi3
215  // Values are arbitrary. The function just looks at the address
216  // offsets of the class fields, not their contents.
217  ::Kokkos::complex<double> z (3.0, 4.0);
218  return Impl::computeKokkosComplexMpiDatatype<double> (z);
219  }
220  }
221 };
222 
223 template<>
224 class MpiTypeTraits< ::Kokkos::complex<float> > {
225 private:
226 #if MPI_VERSION >= 3
227  static const bool hasMpi3 = true;
228 #else
229  static const bool hasMpi3 = false;
230 #endif // MPI_VERSION >= 3
231 
232 public:
234  static const bool isSpecialized = true;
235 
238  static const bool needsFree = ! hasMpi3;
239 
241  static MPI_Datatype getType (const ::Kokkos::complex<float>& z) {
242  if (hasMpi3) {
243 #if MPI_VERSION >= 3
244  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
245 #else
246  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
247 #endif // MPI_VERSION >= 3
248  }
249  else { // ! hasMpi3
250  return Impl::computeKokkosComplexMpiDatatype<float> (z);
251  }
252  }
253 
255  static MPI_Datatype getType () {
256  if (hasMpi3) {
257 #if MPI_VERSION >= 3
258  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
259 #else
260  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
261 #endif // MPI_VERSION >= 3
262  }
263  else { // ! hasMpi3
264  // Values are arbitrary. The function just looks at the address
265  // offsets of the class fields, not their contents.
266  ::Kokkos::complex<float> z (3.0, 4.0);
267  return Impl::computeKokkosComplexMpiDatatype<float> (z);
268  }
269  }
270 };
271 
272 } // namespace Details
273 } // namespace Teuchos
274 
275 namespace Tpetra {
276 namespace Details {
277 
278 // Import MpiTypeTraits into the Tpetra::Details namespace.
279 using ::Teuchos::Details::MpiTypeTraits;
280 
281 } // namespace Details
282 } // namespace Tpetra
283 
284 #endif // HAVE_TPETRACORE_MPI
285 #endif // TPETRA_DETAILS_MPITYPETRAITS_HPP
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Implementation details of Tpetra.