Teuchos Package Browser (Single Doxygen Collection)  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 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef TEUCHOS_DETAILS_MPITYPETRAITS_HPP
11 #define TEUCHOS_DETAILS_MPITYPETRAITS_HPP
12 
16 
17 #include "Teuchos_config.h"
18 
19 #ifdef HAVE_TEUCHOS_MPI
20 
21 #include <mpi.h>
22 #include <complex>
23 
24 namespace Teuchos {
25 namespace Details {
26 
34 template<class T>
35 class MpiTypeTraits {
36 public:
42  static const bool isSpecialized = false;
43 
60  static const bool needsFree = false;
61 
78  static MPI_Datatype getType (const T&) {
79  // In this default implementation, isSpecialized == false, so the
80  // return value of getType is undefined. We have to return
81  // something, so we return the predefined "invalid" MPI_Datatype,
82  // MPI_DATATYPE_NULL. Specializations of getType need to redefine
83  // this method to return something other than MPI_DATATYPE_NULL.
84  return MPI_DATATYPE_NULL;
85  }
86 };
87 
88 //
89 // Specializations of MpiTypeTraits.
90 //
91 
95 template<>
96 class MpiTypeTraits<char> {
97 public:
99  static const bool isSpecialized = true;
100 
103  static const bool needsFree = false;
104 
106  static MPI_Datatype getType (const char&) {
107  return MPI_CHAR;
108  }
109 
111  static MPI_Datatype getType () {
112  return MPI_CHAR;
113  }
114 };
115 
119 template<>
120 class MpiTypeTraits<unsigned char> {
121 public:
123  static const bool isSpecialized = true;
124 
127  static const bool needsFree = false;
128 
130  static MPI_Datatype getType (const unsigned char&) {
131  return MPI_UNSIGNED_CHAR;
132  }
133 
135  static MPI_Datatype getType () {
136  return MPI_UNSIGNED_CHAR;
137  }
138 };
139 
140 #if MPI_VERSION >= 2
141 template<>
145 class MpiTypeTraits<signed char> {
146 public:
148  static const bool isSpecialized = true;
149 
152  static const bool needsFree = false;
153 
155  static MPI_Datatype getType (const signed char&) {
156  return MPI_SIGNED_CHAR;
157  }
158 
160  static MPI_Datatype getType () {
161  return MPI_SIGNED_CHAR;
162  }
163 };
164 #endif // MPI_VERSION >= 2
165 
166 // mfh 09 Nov 2016: amb reports on 11 Nov 2014: "I am disabling these
167 // specializations for now. MPI_C_DOUBLE_COMPLEX is causing a problem
168 // in some builds. This code was effectively turned on only yesterday
169 // (10 Nov 2014) when TEUCHOS_HAVE_COMPLEX was corrected to be
170 // HAVE_TEUCHOS_COMPLEX, so evidently there are no users of these
171 // specializations."
172 //
173 // mfh 14 Nov 2016: my work-around for the above issue, is
174 // conservatively to assume that I need MPI_VERSION >= 3 for these
175 // types to exist. If I don't have MPI_VERSION >= 3, I create custom
176 // MPI_Datatype for these types.
177 
178 namespace Impl {
179 
189 template<class T>
190 struct MyComplex {
191  T re;
192  T im;
193 };
194 
205 template<class T>
206 MPI_Datatype
207 computeStdComplexMpiDatatype (const std::complex<T>& z)
208 {
209 #ifdef HAVE_TEUCHOSCORE_CXX11
210  static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
211  "works if MpiTypeTraits<T>::isSpecialized.");
212  static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
213  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
214  "leak memory.");
215 #endif // HAVE_TEUCHOSCORE_CXX11
216 
217  // We assume here that every instance of T has the same
218  // MPI_Datatype, i.e., has the same binary representation.
219  MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
220  MPI_Datatype outerDatatype; // return value
221 
222  // If std::complex<T> has the same layout as T[2], then we can use a
223  // contiguous derived MPI_Datatype. This is likely the only code
224  // path that will execute. Contiguous types are likely more
225  // efficient for MPI to execute, and almost certainly more efficient
226  // for MPI to set up.
227  if (sizeof (std::complex<T>) == 2 * sizeof (T)) {
228  (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
229  }
230  else { // must use the general struct approach
231  // I borrowed and adapted the code below from the MPICH
232  // documentation:
233  //
234  // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
235  int blockLengths[3];
236  MPI_Aint arrayOfDisplacements[3];
237  MPI_Datatype arrayOfTypes[3];
238 
239 #ifdef HAVE_TEUCHOSCORE_CXX11
240  // See documentation of MyComplex (above) for explanation.
241  static_assert (sizeof (MyComplex<T>) == sizeof (std::complex<T>),
242  "Attempt to construct a struct of the same size and layout "
243  "as std::complex<T> failed.");
244 #endif // HAVE_TEUCHOSCORE_CXX11
245  MyComplex<T> z2;
246 
247  // First entry in the struct.
248  blockLengths[0] = 1;
249  // Normally, &z2.re would equal &z2, but I'll be conservative and
250  // actually compute the offset, even though it's probably just 0.
251  //
252  // Need the cast to prevent the compiler complaining about
253  // subtracting addresses of different types.
254  arrayOfDisplacements[0] = reinterpret_cast<char*>(&z2.re) - reinterpret_cast<char*>(&z2);
255  arrayOfTypes[0] = innerDatatype;
256 
257  // Second entry in the struct.
258  blockLengths[1] = 1;
259  arrayOfDisplacements[1] = reinterpret_cast<char*>(&z2.im) - reinterpret_cast<char*>(&z2);
260  arrayOfTypes[1] = innerDatatype;
261 
262 #if MPI_VERSION < 2
263  // Upper bound of the struct.
264  blockLengths[2] = 1;
265  arrayOfDisplacements[2] = sizeof (MyComplex<T>);
266  arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
267 #endif // MPI_VERSION < 2
268 
269  // Define the MPI_Datatype.
270 #if MPI_VERSION < 2
271  (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
272  arrayOfTypes, &outerDatatype);
273 #else
274  // Don't include the upper bound with MPI_Type_create_struct.
275  (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
276  arrayOfTypes, &outerDatatype);
277 #endif // MPI_VERSION < 2
278  }
279 
280  MPI_Type_commit (&outerDatatype);
281  return outerDatatype;
282 }
283 
284 } // namespace Impl
285 
286 
288 template<>
289 class MpiTypeTraits< std::complex<double> > {
290 private:
291 #if MPI_VERSION >= 3
292  static const bool hasMpi3 = true;
293 #else
294  static const bool hasMpi3 = false;
295 #endif // MPI_VERSION >= 3
296 
297 public:
299  static const bool isSpecialized = true;
300 
303  static const bool needsFree = ! hasMpi3;
304 
306  static MPI_Datatype getType (const std::complex<double>& z) {
307  if (hasMpi3) {
308 #if MPI_VERSION >= 3
309  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
310 #else
311  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
312 #endif // MPI_VERSION >= 3
313  }
314  else { // ! hasMpi3
315  return Impl::computeStdComplexMpiDatatype<double> (z);
316  }
317  }
318 
320  static MPI_Datatype getType () {
321  if (hasMpi3) {
322 #if MPI_VERSION >= 3
323  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
324 #else
325  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
326 #endif // MPI_VERSION >= 3
327  }
328  else { // ! hasMpi3
329  // Values are arbitrary. The function just looks at the address
330  // offsets of the class fields, not their contents.
331  std::complex<double> z (3.0, 4.0);
332  return Impl::computeStdComplexMpiDatatype<double> (z);
333  }
334  }
335 };
336 
337 template<>
338 class MpiTypeTraits< std::complex<float> > {
339 private:
340 #if MPI_VERSION >= 3
341  static const bool hasMpi3 = true;
342 #else
343  static const bool hasMpi3 = false;
344 #endif // MPI_VERSION >= 3
345 
346 public:
348  static const bool isSpecialized = true;
349 
352  static const bool needsFree = ! hasMpi3;
353 
355  static MPI_Datatype getType (const std::complex<float>& z) {
356  if (hasMpi3) {
357 #if MPI_VERSION >= 3
358  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
359 #else
360  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
361 #endif // MPI_VERSION >= 3
362  }
363  else { // ! hasMpi3
364  return Impl::computeStdComplexMpiDatatype<float> (z);
365  }
366  }
367 
369  static MPI_Datatype getType () {
370  if (hasMpi3) {
371 #if MPI_VERSION >= 3
372  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
373 #else
374  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
375 #endif // MPI_VERSION >= 3
376  }
377  else { // ! hasMpi3
378  // Values are arbitrary. The function just looks at the address
379  // offsets of the class fields, not their contents.
380  std::complex<float> z (3.0, 4.0);
381  return Impl::computeStdComplexMpiDatatype<float> (z);
382  }
383  }
384 };
385 
387 template<>
388 class MpiTypeTraits<double> {
389 public:
391  static const bool isSpecialized = true;
392 
395  static const bool needsFree = false;
396 
398  static MPI_Datatype getType (const double&) {
399  return MPI_DOUBLE;
400  }
401 
403  static MPI_Datatype getType () {
404  return MPI_DOUBLE;
405  }
406 };
407 
409 template<>
410 class MpiTypeTraits<float> {
411 public:
413  static const bool isSpecialized = true;
414 
417  static const bool needsFree = false;
418 
420  static MPI_Datatype getType (const float&) {
421  return MPI_FLOAT;
422  }
423 
425  static MPI_Datatype getType () {
426  return MPI_FLOAT;
427  }
428 };
429 
431 template<>
432 class MpiTypeTraits<long long> {
433 public:
435  static const bool isSpecialized = true;
436 
439  static const bool needsFree = false;
440 
442  static MPI_Datatype getType (const long long&) {
443  return MPI_LONG_LONG; // synonym for MPI_LONG_LONG_INT in MPI 2.2
444  }
445 
447  static MPI_Datatype getType () {
448  return MPI_LONG_LONG;
449  }
450 };
451 
452 
453 #if MPI_VERSION >= 2
454 template<>
458 class MpiTypeTraits<unsigned long long> {
459 public:
461  static const bool isSpecialized = true;
462 
465  static const bool needsFree = false;
466 
468  static MPI_Datatype getType (const unsigned long long&) {
469  return MPI_UNSIGNED_LONG_LONG;
470  }
471 
473  static MPI_Datatype getType () {
474  return MPI_UNSIGNED_LONG_LONG;
475  }
476 };
477 #endif // MPI_VERSION >= 2
478 
480 template<>
481 class MpiTypeTraits<long> {
482 public:
484  static const bool isSpecialized = true;
485 
488  static const bool needsFree = false;
489 
491  static MPI_Datatype getType (const long&) {
492  return MPI_LONG;
493  }
494 
496  static MPI_Datatype getType () {
497  return MPI_LONG;
498  }
499 };
500 
502 template<>
503 class MpiTypeTraits<unsigned long> {
504 public:
506  static const bool isSpecialized = true;
507 
510  static const bool needsFree = false;
511 
513  static MPI_Datatype getType (const unsigned long&) {
514  return MPI_UNSIGNED_LONG;
515  }
516 
518  static MPI_Datatype getType () {
519  return MPI_UNSIGNED_LONG;
520  }
521 };
522 
524 template<>
525 class MpiTypeTraits<int> {
526 public:
528  static const bool isSpecialized = true;
529 
532  static const bool needsFree = false;
533 
535  static MPI_Datatype getType (const int&) {
536  return MPI_INT;
537  }
538 
540  static MPI_Datatype getType () {
541  return MPI_INT;
542  }
543 };
544 
546 template<>
547 class MpiTypeTraits<unsigned int> {
548 public:
550  static const bool isSpecialized = true;
551 
554  static const bool needsFree = false;
555 
557  static MPI_Datatype getType (const unsigned int&) {
558  return MPI_UNSIGNED;
559  }
560 
562  static MPI_Datatype getType () {
563  return MPI_UNSIGNED;
564  }
565 };
566 
568 template<>
569 class MpiTypeTraits<short> {
570 public:
572  static const bool isSpecialized = true;
573 
576  static const bool needsFree = false;
577 
579  static MPI_Datatype getType (const short&) {
580  return MPI_SHORT;
581  }
582 
584  static MPI_Datatype getType () {
585  return MPI_SHORT;
586  }
587 };
588 
590 template<>
591 class MpiTypeTraits<unsigned short> {
592 public:
594  static const bool isSpecialized = true;
595 
598  static const bool needsFree = false;
599 
601  static MPI_Datatype getType (const unsigned short&) {
602  return MPI_UNSIGNED_SHORT;
603  }
604 
606  static MPI_Datatype getType () {
607  return MPI_UNSIGNED_SHORT;
608  }
609 };
610 
611 } // namespace Details
612 } // namespace Teuchos
613 
614 #endif // HAVE_TEUCHOS_MPI
615 
616 #endif // TEUCHOS_DETAILS_MPITYPETRAITS_HPP
617