Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_Details_MpiTypeTraits.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_DETAILS_MPITYPETRAITS_HPP
43 #define TEUCHOS_DETAILS_MPITYPETRAITS_HPP
44 
48 
49 #include "Teuchos_config.h"
50 
51 #ifdef HAVE_TEUCHOS_MPI
52 
53 #include <mpi.h>
54 #include <complex>
55 
56 namespace Teuchos {
57 namespace Details {
58 
66 template<class T>
67 class MpiTypeTraits {
68 public:
74  static const bool isSpecialized = false;
75 
92  static const bool needsFree = false;
93 
110  static MPI_Datatype getType (const T&) {
111  // In this default implementation, isSpecialized == false, so the
112  // return value of getType is undefined. We have to return
113  // something, so we return the predefined "invalid" MPI_Datatype,
114  // MPI_DATATYPE_NULL. Specializations of getType need to redefine
115  // this method to return something other than MPI_DATATYPE_NULL.
116  return MPI_DATATYPE_NULL;
117  }
118 };
119 
120 //
121 // Specializations of MpiTypeTraits.
122 //
123 
127 template<>
128 class MpiTypeTraits<char> {
129 public:
131  static const bool isSpecialized = true;
132 
135  static const bool needsFree = false;
136 
138  static MPI_Datatype getType (const char&) {
139  return MPI_CHAR;
140  }
141 
143  static MPI_Datatype getType () {
144  return MPI_CHAR;
145  }
146 };
147 
151 template<>
152 class MpiTypeTraits<unsigned char> {
153 public:
155  static const bool isSpecialized = true;
156 
159  static const bool needsFree = false;
160 
162  static MPI_Datatype getType (const unsigned char&) {
163  return MPI_UNSIGNED_CHAR;
164  }
165 
167  static MPI_Datatype getType () {
168  return MPI_UNSIGNED_CHAR;
169  }
170 };
171 
172 #if MPI_VERSION >= 2
173 template<>
177 class MpiTypeTraits<signed char> {
178 public:
180  static const bool isSpecialized = true;
181 
184  static const bool needsFree = false;
185 
187  static MPI_Datatype getType (const signed char&) {
188  return MPI_SIGNED_CHAR;
189  }
190 
192  static MPI_Datatype getType () {
193  return MPI_SIGNED_CHAR;
194  }
195 };
196 #endif // MPI_VERSION >= 2
197 
198 // mfh 09 Nov 2016: amb reports on 11 Nov 2014: "I am disabling these
199 // specializations for now. MPI_C_DOUBLE_COMPLEX is causing a problem
200 // in some builds. This code was effectively turned on only yesterday
201 // (10 Nov 2014) when TEUCHOS_HAVE_COMPLEX was corrected to be
202 // HAVE_TEUCHOS_COMPLEX, so evidently there are no users of these
203 // specializations."
204 //
205 // mfh 14 Nov 2016: my work-around for the above issue, is
206 // conservatively to assume that I need MPI_VERSION >= 3 for these
207 // types to exist. If I don't have MPI_VERSION >= 3, I create custom
208 // MPI_Datatype for these types.
209 
210 namespace Impl {
211 
221 template<class T>
222 struct MyComplex {
223  T re;
224  T im;
225 };
226 
237 template<class T>
238 MPI_Datatype
239 computeStdComplexMpiDatatype (const std::complex<T>& z)
240 {
241 #ifdef HAVE_TEUCHOSCORE_CXX11
242  static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
243  "works if MpiTypeTraits<T>::isSpecialized.");
244  static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
245  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
246  "leak memory.");
247 #endif // HAVE_TEUCHOSCORE_CXX11
248 
249  // We assume here that every instance of T has the same
250  // MPI_Datatype, i.e., has the same binary representation.
251  MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
252  MPI_Datatype outerDatatype; // return value
253 
254  // If std::complex<T> has the same layout as T[2], then we can use a
255  // contiguous derived MPI_Datatype. This is likely the only code
256  // path that will execute. Contiguous types are likely more
257  // efficient for MPI to execute, and almost certainly more efficient
258  // for MPI to set up.
259  if (sizeof (std::complex<T>) == 2 * sizeof (T)) {
260  (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
261  }
262  else { // must use the general struct approach
263  // I borrowed and adapted the code below from the MPICH
264  // documentation:
265  //
266  // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
267  int blockLengths[3];
268  MPI_Aint arrayOfDisplacements[3];
269  MPI_Datatype arrayOfTypes[3];
270 
271 #ifdef HAVE_TEUCHOSCORE_CXX11
272  // See documentation of MyComplex (above) for explanation.
273  static_assert (sizeof (MyComplex<T>) == sizeof (std::complex<T>),
274  "Attempt to construct a struct of the same size and layout "
275  "as std::complex<T> failed.");
276 #endif // HAVE_TEUCHOSCORE_CXX11
277  MyComplex<T> z2;
278 
279  // First entry in the struct.
280  blockLengths[0] = 1;
281  // Normally, &z2.re would equal &z2, but I'll be conservative and
282  // actually compute the offset, even though it's probably just 0.
283  //
284  // Need the cast to prevent the compiler complaining about
285  // subtracting addresses of different types.
286  arrayOfDisplacements[0] = reinterpret_cast<char*>(&z2.re) - reinterpret_cast<char*>(&z2);
287  arrayOfTypes[0] = innerDatatype;
288 
289  // Second entry in the struct.
290  blockLengths[1] = 1;
291  arrayOfDisplacements[1] = reinterpret_cast<char*>(&z2.im) - reinterpret_cast<char*>(&z2);
292  arrayOfTypes[1] = innerDatatype;
293 
294 #if MPI_VERSION < 2
295  // Upper bound of the struct.
296  blockLengths[2] = 1;
297  arrayOfDisplacements[2] = sizeof (MyComplex<T>);
298  arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
299 #endif // MPI_VERSION < 2
300 
301  // Define the MPI_Datatype.
302 #if MPI_VERSION < 2
303  (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
304  arrayOfTypes, &outerDatatype);
305 #else
306  // Don't include the upper bound with MPI_Type_create_struct.
307  (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
308  arrayOfTypes, &outerDatatype);
309 #endif // MPI_VERSION < 2
310  }
311 
312  MPI_Type_commit (&outerDatatype);
313  return outerDatatype;
314 }
315 
316 } // namespace Impl
317 
318 
320 template<>
321 class MpiTypeTraits< std::complex<double> > {
322 private:
323 #if MPI_VERSION >= 3
324  static const bool hasMpi3 = true;
325 #else
326  static const bool hasMpi3 = false;
327 #endif // MPI_VERSION >= 3
328 
329 public:
331  static const bool isSpecialized = true;
332 
335  static const bool needsFree = ! hasMpi3;
336 
338  static MPI_Datatype getType (const std::complex<double>& z) {
339  if (hasMpi3) {
340 #if MPI_VERSION >= 3
341  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
342 #else
343  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
344 #endif // MPI_VERSION >= 3
345  }
346  else { // ! hasMpi3
347  return Impl::computeStdComplexMpiDatatype<double> (z);
348  }
349  }
350 
352  static MPI_Datatype getType () {
353  if (hasMpi3) {
354 #if MPI_VERSION >= 3
355  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
356 #else
357  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
358 #endif // MPI_VERSION >= 3
359  }
360  else { // ! hasMpi3
361  // Values are arbitrary. The function just looks at the address
362  // offsets of the class fields, not their contents.
363  std::complex<double> z (3.0, 4.0);
364  return Impl::computeStdComplexMpiDatatype<double> (z);
365  }
366  }
367 };
368 
369 template<>
370 class MpiTypeTraits< std::complex<float> > {
371 private:
372 #if MPI_VERSION >= 3
373  static const bool hasMpi3 = true;
374 #else
375  static const bool hasMpi3 = false;
376 #endif // MPI_VERSION >= 3
377 
378 public:
380  static const bool isSpecialized = true;
381 
384  static const bool needsFree = ! hasMpi3;
385 
387  static MPI_Datatype getType (const std::complex<float>& z) {
388  if (hasMpi3) {
389 #if MPI_VERSION >= 3
390  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
391 #else
392  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
393 #endif // MPI_VERSION >= 3
394  }
395  else { // ! hasMpi3
396  return Impl::computeStdComplexMpiDatatype<float> (z);
397  }
398  }
399 
401  static MPI_Datatype getType () {
402  if (hasMpi3) {
403 #if MPI_VERSION >= 3
404  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
405 #else
406  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
407 #endif // MPI_VERSION >= 3
408  }
409  else { // ! hasMpi3
410  // Values are arbitrary. The function just looks at the address
411  // offsets of the class fields, not their contents.
412  std::complex<float> z (3.0, 4.0);
413  return Impl::computeStdComplexMpiDatatype<float> (z);
414  }
415  }
416 };
417 
419 template<>
420 class MpiTypeTraits<double> {
421 public:
423  static const bool isSpecialized = true;
424 
427  static const bool needsFree = false;
428 
430  static MPI_Datatype getType (const double&) {
431  return MPI_DOUBLE;
432  }
433 
435  static MPI_Datatype getType () {
436  return MPI_DOUBLE;
437  }
438 };
439 
441 template<>
442 class MpiTypeTraits<float> {
443 public:
445  static const bool isSpecialized = true;
446 
449  static const bool needsFree = false;
450 
452  static MPI_Datatype getType (const float&) {
453  return MPI_FLOAT;
454  }
455 
457  static MPI_Datatype getType () {
458  return MPI_FLOAT;
459  }
460 };
461 
463 template<>
464 class MpiTypeTraits<long long> {
465 public:
467  static const bool isSpecialized = true;
468 
471  static const bool needsFree = false;
472 
474  static MPI_Datatype getType (const long long&) {
475  return MPI_LONG_LONG; // synonym for MPI_LONG_LONG_INT in MPI 2.2
476  }
477 
479  static MPI_Datatype getType () {
480  return MPI_LONG_LONG;
481  }
482 };
483 
484 
485 #if MPI_VERSION >= 2
486 template<>
490 class MpiTypeTraits<unsigned long long> {
491 public:
493  static const bool isSpecialized = true;
494 
497  static const bool needsFree = false;
498 
500  static MPI_Datatype getType (const unsigned long long&) {
501  return MPI_UNSIGNED_LONG_LONG;
502  }
503 
505  static MPI_Datatype getType () {
506  return MPI_UNSIGNED_LONG_LONG;
507  }
508 };
509 #endif // MPI_VERSION >= 2
510 
512 template<>
513 class MpiTypeTraits<long> {
514 public:
516  static const bool isSpecialized = true;
517 
520  static const bool needsFree = false;
521 
523  static MPI_Datatype getType (const long&) {
524  return MPI_LONG;
525  }
526 
528  static MPI_Datatype getType () {
529  return MPI_LONG;
530  }
531 };
532 
534 template<>
535 class MpiTypeTraits<unsigned long> {
536 public:
538  static const bool isSpecialized = true;
539 
542  static const bool needsFree = false;
543 
545  static MPI_Datatype getType (const unsigned long&) {
546  return MPI_UNSIGNED_LONG;
547  }
548 
550  static MPI_Datatype getType () {
551  return MPI_UNSIGNED_LONG;
552  }
553 };
554 
556 template<>
557 class MpiTypeTraits<int> {
558 public:
560  static const bool isSpecialized = true;
561 
564  static const bool needsFree = false;
565 
567  static MPI_Datatype getType (const int&) {
568  return MPI_INT;
569  }
570 
572  static MPI_Datatype getType () {
573  return MPI_INT;
574  }
575 };
576 
578 template<>
579 class MpiTypeTraits<unsigned int> {
580 public:
582  static const bool isSpecialized = true;
583 
586  static const bool needsFree = false;
587 
589  static MPI_Datatype getType (const unsigned int&) {
590  return MPI_UNSIGNED;
591  }
592 
594  static MPI_Datatype getType () {
595  return MPI_UNSIGNED;
596  }
597 };
598 
600 template<>
601 class MpiTypeTraits<short> {
602 public:
604  static const bool isSpecialized = true;
605 
608  static const bool needsFree = false;
609 
611  static MPI_Datatype getType (const short&) {
612  return MPI_SHORT;
613  }
614 
616  static MPI_Datatype getType () {
617  return MPI_SHORT;
618  }
619 };
620 
622 template<>
623 class MpiTypeTraits<unsigned short> {
624 public:
626  static const bool isSpecialized = true;
627 
630  static const bool needsFree = false;
631 
633  static MPI_Datatype getType (const unsigned short&) {
634  return MPI_UNSIGNED_SHORT;
635  }
636 
638  static MPI_Datatype getType () {
639  return MPI_UNSIGNED_SHORT;
640  }
641 };
642 
643 } // namespace Details
644 } // namespace Teuchos
645 
646 #endif // HAVE_TEUCHOS_MPI
647 
648 #endif // TEUCHOS_DETAILS_MPITYPETRAITS_HPP
649