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//
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
56namespace Teuchos {
57namespace Details {
58
66template<class T>
67class MpiTypeTraits {
68public:
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
127template<>
128class MpiTypeTraits<char> {
129public:
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
151template<>
152class MpiTypeTraits<unsigned char> {
153public:
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
176template<>
177class MpiTypeTraits<signed char> {
178public:
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
210namespace Impl {
211
221template<class T>
222struct MyComplex {
223 T re;
224 T im;
225};
226
237template<class T>
238MPI_Datatype
239computeStdComplexMpiDatatype (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
320template<>
321class MpiTypeTraits< std::complex<double> > {
322private:
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
329public:
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
369template<>
370class MpiTypeTraits< std::complex<float> > {
371private:
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
378public:
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
419template<>
420class MpiTypeTraits<double> {
421public:
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
441template<>
442class MpiTypeTraits<float> {
443public:
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
463template<>
464class MpiTypeTraits<long long> {
465public:
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
489template<>
490class MpiTypeTraits<unsigned long long> {
491public:
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
512template<>
513class MpiTypeTraits<long> {
514public:
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
534template<>
535class MpiTypeTraits<unsigned long> {
536public:
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
556template<>
557class MpiTypeTraits<int> {
558public:
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
578template<>
579class MpiTypeTraits<unsigned int> {
580public:
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
600template<>
601class MpiTypeTraits<short> {
602public:
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
622template<>
623class MpiTypeTraits<unsigned short> {
624public:
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
Namespace of implementation details.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...