Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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
24namespace Teuchos {
25namespace Details {
26
34template<class T>
35class MpiTypeTraits {
36public:
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
95template<>
96class MpiTypeTraits<char> {
97public:
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
119template<>
120class MpiTypeTraits<unsigned char> {
121public:
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
144template<>
145class MpiTypeTraits<signed char> {
146public:
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
178namespace Impl {
179
189template<class T>
190struct MyComplex {
191 T re;
192 T im;
193};
194
205template<class T>
206MPI_Datatype
207computeStdComplexMpiDatatype (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
288template<>
289class MpiTypeTraits< std::complex<double> > {
290private:
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
297public:
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
337template<>
338class MpiTypeTraits< std::complex<float> > {
339private:
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
346public:
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
387template<>
388class MpiTypeTraits<double> {
389public:
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
409template<>
410class MpiTypeTraits<float> {
411public:
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
431template<>
432class MpiTypeTraits<long long> {
433public:
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
457template<>
458class MpiTypeTraits<unsigned long long> {
459public:
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
480template<>
481class MpiTypeTraits<long> {
482public:
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
502template<>
503class MpiTypeTraits<unsigned long> {
504public:
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
524template<>
525class MpiTypeTraits<int> {
526public:
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
546template<>
547class MpiTypeTraits<unsigned int> {
548public:
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
568template<>
569class MpiTypeTraits<short> {
570public:
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
590template<>
591class MpiTypeTraits<unsigned short> {
592public:
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
Namespace of implementation details.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...