changed: refactor MPIPacker

to limit the overload party, we put packing details for
specific types in separate structs.
emit compiler error if unsupported type is given,
better to detect this on compile time rather than runtime
This commit is contained in:
Arne Morten Kvarving
2022-09-07 13:54:15 +02:00
parent 3a19ab31bd
commit b1092c1a12
4 changed files with 318 additions and 408 deletions

View File

@@ -74,7 +74,6 @@ list (APPEND MAIN_SOURCE_FILES
opm/simulators/timestepping/gatherConvergenceReport.cpp opm/simulators/timestepping/gatherConvergenceReport.cpp
opm/simulators/utils/DeferredLogger.cpp opm/simulators/utils/DeferredLogger.cpp
opm/simulators/utils/gatherDeferredLogger.cpp opm/simulators/utils/gatherDeferredLogger.cpp
opm/simulators/utils/MPIPacker.cpp
opm/simulators/utils/ParallelFileMerger.cpp opm/simulators/utils/ParallelFileMerger.cpp
opm/simulators/utils/ParallelRestart.cpp opm/simulators/utils/ParallelRestart.cpp
opm/simulators/wells/ALQState.cpp opm/simulators/wells/ALQState.cpp
@@ -146,7 +145,8 @@ if(HAVE_AMGCL)
endif() endif()
if(MPI_FOUND) if(MPI_FOUND)
list(APPEND MAIN_SOURCE_FILES opm/simulators/utils/ParallelEclipseState.cpp list(APPEND MAIN_SOURCE_FILES opm/simulators/utils/ParallelEclipseState.cpp
opm/simulators/utils/ParallelSerialization.cpp) opm/simulators/utils/ParallelSerialization.cpp
opm/simulators/utils/MPIPacker.cpp)
endif() endif()
# originally generated with the command: # originally generated with the command:

View File

@@ -107,11 +107,11 @@ public:
const_cast<T&>(data).serializeOp(*this); const_cast<T&>(data).serializeOp(*this);
} else { } else {
if (m_op == Operation::PACKSIZE) if (m_op == Operation::PACKSIZE)
m_packSize += Mpi::packSize(data, m_comm); m_packSize += Mpi::Packer::packSize(data, m_comm);
else if (m_op == Operation::PACK) else if (m_op == Operation::PACK)
Mpi::pack(data, m_buffer, m_position, m_comm); Mpi::Packer::pack(data, m_buffer, m_position, m_comm);
else if (m_op == Operation::UNPACK) else if (m_op == Operation::UNPACK)
Mpi::unpack(const_cast<T&>(data), m_buffer, m_position, m_comm); Mpi::Packer::unpack(const_cast<T&>(data), m_buffer, m_position, m_comm);
} }
} }
@@ -138,14 +138,14 @@ public:
}; };
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm); m_packSize += Mpi::Packer::packSize(data.size(), m_comm);
handle(data); handle(data);
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.size(), m_buffer, m_position, m_comm); Mpi::packer::pack(data.size(), m_buffer, m_position, m_comm);
handle(data); handle(data);
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
size_t size; size_t size;
Mpi::unpack(size, m_buffer, m_position, m_comm); Mpi::Packer::unpack(size, m_buffer, m_position, m_comm);
data.resize(size); data.resize(size);
handle(data); handle(data);
} }
@@ -156,8 +156,8 @@ public:
void vector(std::vector<bool>& data) void vector(std::vector<bool>& data)
{ {
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm); m_packSize += Mpi::Packer::packSize(data.size(), m_comm);
m_packSize += data.size()*Mpi::packSize(bool(), m_comm); m_packSize += data.size()*Mpi::Packer::packSize(bool(), m_comm);
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
(*this)(data.size()); (*this)(data.size());
for (const auto entry : data) { // Not a reference: vector<bool> range for (const auto entry : data) { // Not a reference: vector<bool> range
@@ -198,14 +198,14 @@ public:
}; };
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm); m_packSize += Mpi::Packer::packSize(data.size(), m_comm);
handle(data); handle(data);
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.size(), m_buffer, m_position, m_comm); Mpi::Packer::pack(data.size(), m_buffer, m_position, m_comm);
handle(data); handle(data);
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
size_t size; size_t size;
Mpi::unpack(size, m_buffer, m_position, m_comm); Mpi::Packer::unpack(size, m_buffer, m_position, m_comm);
handle(data); handle(data);
} }
} }
@@ -223,14 +223,14 @@ public:
(*this)(d); (*this)(d);
}; };
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.index(), m_comm); m_packSize += Mpi::Packer::packSize(data.index(), m_comm);
std::visit(visitor, data); std::visit(visitor, data);
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.index(), m_buffer, m_position, m_comm); Mpi::Packer::pack(data.index(), m_buffer, m_position, m_comm);
std::visit(visitor, data); std::visit(visitor, data);
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
size_t index; size_t index;
Mpi::unpack(index, m_buffer, m_position, m_comm); Mpi::Packer::unpack(index, m_buffer, m_position, m_comm);
auto& data_mut = const_cast<std::variant<Args...>&>(data); auto& data_mut = const_cast<std::variant<Args...>&>(data);
data_mut = detail::make_variant<Args...>(index); data_mut = detail::make_variant<Args...>(index);
std::visit(visitor, data_mut); std::visit(visitor, data_mut);
@@ -244,18 +244,18 @@ public:
void optional(const std::optional<T>& data) void optional(const std::optional<T>& data)
{ {
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.has_value(), m_comm); m_packSize += Mpi::Packer::packSize(data.has_value(), m_comm);
if (data.has_value()) { if (data.has_value()) {
(*this)(*data); (*this)(*data);
} }
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.has_value(), m_buffer, m_position, m_comm); Mpi::Packer::pack(data.has_value(), m_buffer, m_position, m_comm);
if (data.has_value()) { if (data.has_value()) {
(*this)(*data); (*this)(*data);
} }
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
bool has; bool has;
Mpi::unpack(has, m_buffer, m_position, m_comm); Mpi::Packer::unpack(has, m_buffer, m_position, m_comm);
if (has) { if (has) {
T res; T res;
(*this)(res); (*this)(res);
@@ -306,20 +306,20 @@ public:
}; };
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm); m_packSize += Mpi::Packer::packSize(data.size(), m_comm);
for (auto& it : data) { for (auto& it : data) {
keyHandle(it.first); keyHandle(it.first);
handle(it.second); handle(it.second);
} }
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.size(), m_buffer, m_position, m_comm); Mpi::Packer::pack(data.size(), m_buffer, m_position, m_comm);
for (auto& it : data) { for (auto& it : data) {
keyHandle(it.first); keyHandle(it.first);
handle(it.second); handle(it.second);
} }
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
size_t size; size_t size;
Mpi::unpack(size, m_buffer, m_position, m_comm); Mpi::Packer::unpack(size, m_buffer, m_position, m_comm);
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
Key key; Key key;
keyHandle(key); keyHandle(key);
@@ -351,18 +351,18 @@ public:
}; };
if (m_op == Operation::PACKSIZE) { if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm); m_packSize += Mpi::Packer::packSize(data.size(), m_comm);
for (auto& it : data) { for (auto& it : data) {
handle(it); handle(it);
} }
} else if (m_op == Operation::PACK) { } else if (m_op == Operation::PACK) {
Mpi::pack(data.size(), m_buffer, m_position, m_comm); Mpi::Packer::pack(data.size(), m_buffer, m_position, m_comm);
for (auto& it : data) { for (auto& it : data) {
handle(it); handle(it);
} }
} else if (m_op == Operation::UNPACK) { } else if (m_op == Operation::UNPACK) {
size_t size; size_t size;
Mpi::unpack(size, m_buffer, m_position, m_comm); Mpi::Packer::unpack(size, m_buffer, m_position, m_comm);
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
Data entry; Data entry;
handle(entry); handle(entry);

View File

@@ -19,277 +19,118 @@
#include <config.h> #include <config.h>
#include "MPIPacker.hpp" #include "MPIPacker.hpp"
#include <bitset>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <ctime> #include <ctime>
#include <string>
#include <type_traits>
#include <dune/common/parallel/mpitraits.hh> #include <opm/common/utility/TimeService.hpp>
#if HAVE_MPI
#include <ebos/eclmpiserializer.hh>
#endif
namespace Opm namespace Opm {
namespace Mpi {
namespace detail {
template<std::size_t Size>
std::size_t Packing<false,std::bitset<Size>>::
packSize(const std::bitset<Size>& data,
Parallel::MPIComm comm)
{ {
namespace Mpi return Packing<true,unsigned long long>::packSize(data.to_ullong(), comm);
{
template<class T>
std::size_t packSize(const T*, std::size_t, Opm::Parallel::MPIComm,
std::integral_constant<bool, false>)
{
OPM_THROW(std::logic_error, "Packing not (yet) supported for this non-pod type.");
} }
template<class T> template<std::size_t Size>
std::size_t packSize(const T*, std::size_t l, Opm::Parallel::MPIComm comm, void Packing<false,std::bitset<Size>>::
std::integral_constant<bool, true>) pack(const std::bitset<Size>& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{ {
#if HAVE_MPI Packing<true,unsigned long long>::pack(data.to_ullong(), buffer, position, comm);
int size;
MPI_Pack_size(1, Dune::MPITraits<std::size_t>::getType(), comm, &size);
std::size_t totalSize = size;
MPI_Pack_size(l, Dune::MPITraits<T>::getType(), comm, &size);
return totalSize + size;
#else
(void) comm;
return l-l;
#endif
} }
template<class T> template<std::size_t Size>
std::size_t packSize(const T* data, std::size_t l, Opm::Parallel::MPIComm comm) void Packing<false,std::bitset<Size>>::
unpack(std::bitset<Size>& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{ {
return packSize(data, l, comm, typename std::is_pod<T>::type()); unsigned long long d;
Packing<true,unsigned long long>::unpack(d, buffer, position, comm);
data = std::bitset<Size>(d);
} }
std::size_t packSize(const char* str, Opm::Parallel::MPIComm comm) std::size_t Packing<false,std::string>::
packSize(const std::string& data, Parallel::MPIComm comm)
{ {
#if HAVE_MPI
int size; int size;
MPI_Pack_size(1, Dune::MPITraits<std::size_t>::getType(), comm, &size); MPI_Pack_size(1, Dune::MPITraits<std::size_t>::getType(), comm, &size);
int totalSize = size; int totalSize = size;
MPI_Pack_size(strlen(str)+1, MPI_CHAR, comm, &size); MPI_Pack_size(strlen(data.c_str()), MPI_CHAR, comm, &size);
return totalSize + size; return totalSize + size;
#else
(void) str;
(void) comm;
return 0;
#endif
} }
std::size_t packSize(const std::string& str, Opm::Parallel::MPIComm comm) void Packing<false,std::string>::
pack(const std::string& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{ {
return packSize(str.c_str(), comm); std::size_t length = strlen(data.c_str());
}
template <class T>
struct Packing
{
};
template <std::size_t Size>
struct Packing<std::bitset<Size>>
{
static std::size_t packSize(const std::bitset<Size>& data, Opm::Parallel::MPIComm comm)
{
return Mpi::packSize(data.to_ullong(), comm);
}
static void pack(const std::bitset<Size>& data, std::vector<char>& buffer, int& position, Opm::Parallel::MPIComm comm)
{
Mpi::pack(data.to_ullong(), buffer, position, comm);
}
static void unpack(std::bitset<Size>& data, std::vector<char>& buffer, int& position, Opm::Parallel::MPIComm comm)
{
unsigned long long d;
Mpi::unpack(d, buffer, position, comm);
data = std::bitset<Size>(d);
}
};
template<std::size_t Size>
std::size_t packSize(const std::bitset<Size>& data, Opm::Parallel::MPIComm comm)
{
return Packing<std::bitset<Size>>::packSize(data, comm);
}
std::size_t packSize(const Opm::time_point&, Opm::Parallel::MPIComm comm)
{
std::time_t tp = 0;
return packSize(tp, comm);
}
////// pack routines
template<class T>
void pack(const T*, std::size_t, std::vector<char>&, int&,
Opm::Parallel::MPIComm, std::integral_constant<bool, false>)
{
OPM_THROW(std::logic_error, "Packing not (yet) supported for this non-pod type.");
}
template<class T>
void pack(const T* data, std::size_t l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm,
std::integral_constant<bool, true>)
{
#if HAVE_MPI
MPI_Pack(&l, 1, Dune::MPITraits<std::size_t>::getType(), buffer.data(),
buffer.size(), &position, comm);
MPI_Pack(data, l, Dune::MPITraits<T>::getType(), buffer.data(),
buffer.size(), &position, comm);
#else
(void) data;
(void) comm;
(void) l;
(void) buffer;
(void) position;
#endif
}
template<class T>
void pack(const T* data, std::size_t l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
pack(data, l, buffer, position, comm, typename std::is_pod<T>::type());
}
void pack(const char* str, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
#if HAVE_MPI
std::size_t length = strlen(str)+1;
MPI_Pack(&length, 1, Dune::MPITraits<std::size_t>::getType(), buffer.data(), MPI_Pack(&length, 1, Dune::MPITraits<std::size_t>::getType(), buffer.data(),
buffer.size(), &position, comm); buffer.size(), &position, comm);
MPI_Pack(str, strlen(str)+1, MPI_CHAR, buffer.data(), buffer.size(), MPI_Pack(data.c_str(), length, MPI_CHAR, buffer.data(), buffer.size(),
&position, comm); &position, comm);
#else
(void) str;
(void) comm;
(void) buffer;
(void) position;
#endif
} }
void pack(const std::string& str, std::vector<char>& buffer, int& position, void Packing<false,std::string>::
Opm::Parallel::MPIComm comm) unpack(std::string& data,
std::vector<char>& buffer,
int& position,
Opm::Parallel::MPIComm comm)
{ {
pack(str.c_str(), buffer, position, comm); std::size_t length = 0;
MPI_Unpack(buffer.data(), buffer.size(), &position, &length, 1,
Dune::MPITraits<std::size_t>::getType(), comm);
std::vector<char> cStr(length+1, '\0');
MPI_Unpack(buffer.data(), buffer.size(), &position, cStr.data(), length,
MPI_CHAR, comm);
data.clear();
data.append(cStr.data());
} }
template<std::size_t Size> std::size_t Packing<false,time_point>::
void pack(const std::bitset<Size>& data, std::vector<char>& buffer, packSize(const time_point&, Opm::Parallel::MPIComm comm)
int& position, Opm::Parallel::MPIComm comm)
{ {
Packing<std::bitset<Size>>::pack(data, buffer, position, comm); return Packing<true,std::time_t>::packSize(std::time_t(), comm);
} }
void pack(const Opm::time_point& data, std::vector<char>& buffer, int& position, void Packing<false,time_point>::
Opm::Parallel::MPIComm comm) pack(const time_point& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{ {
pack(Opm::TimeService::to_time_t(data), buffer, position, comm); Packing<true,std::time_t>::pack(TimeService::to_time_t(data),
buffer, position, comm);
} }
void Packing<false,time_point>::
/// Mpi::unpack routines unpack(time_point& data,
std::vector<char>& buffer,
template<class T> int& position,
void unpack(T*, const std::size_t&, std::vector<char>&, int&, Parallel::MPIComm comm)
Opm::Parallel::MPIComm, std::integral_constant<bool, false>)
{ {
OPM_THROW(std::logic_error, "Packing not (yet) supported for this non-pod type."); std::time_t res;
Packing<true,std::time_t>::unpack(res, buffer, position, comm);
data = TimeService::from_time_t(res);
} }
template<class T> template struct Packing<false,std::bitset<4>>;
void unpack(T* data, const std::size_t& l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm,
std::integral_constant<bool, true>)
{
#if HAVE_MPI
MPI_Unpack(buffer.data(), buffer.size(), &position, data, l,
Dune::MPITraits<T>::getType(), comm);
#else
(void) data;
(void) comm;
(void) l;
(void) buffer;
(void) position;
#endif
} }
template<class T>
void unpack(T* data, const std::size_t& l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
unpack(data, l, buffer, position, comm, typename std::is_pod<T>::type());
}
void unpack(char* str, std::size_t length, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
#if HAVE_MPI
MPI_Unpack(buffer.data(), buffer.size(), &position, const_cast<char*>(str), length, MPI_CHAR, comm);
#else
(void) str;
(void) comm;
(void) length;
(void) buffer;
(void) position;
#endif
}
void unpack(std::string& str, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
std::size_t length=0;
unpack(length, buffer, position, comm);
std::vector<char> cStr(length, '\0');
unpack(cStr.data(), length, buffer, position, comm);
str.clear();
str.append(cStr.data());
}
template<std::size_t Size>
void unpack(std::bitset<Size>& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
Packing<std::bitset<Size>>::unpack(data, buffer, position, comm);
}
void unpack([[maybe_unused]] Opm::time_point& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
std::time_t tp;
unpack(tp, buffer, position, comm);
#if HAVE_MPI
data = Opm::TimeService::from_time_t(tp);
#endif
}
#define INSTANTIATE_PACK(...) \
template std::size_t packSize(const __VA_ARGS__& data, \
Opm::Parallel::MPIComm comm); \
template void pack(const __VA_ARGS__& data, \
std::vector<char>& buffer, int& position, \
Opm::Parallel::MPIComm comm); \
template void unpack(__VA_ARGS__& data, \
std::vector<char>& buffer, int& position, \
Opm::Parallel::MPIComm comm);
INSTANTIATE_PACK(float)
INSTANTIATE_PACK(double)
INSTANTIATE_PACK(bool)
INSTANTIATE_PACK(int)
INSTANTIATE_PACK(unsigned char)
INSTANTIATE_PACK(unsigned int)
INSTANTIATE_PACK(unsigned long int)
INSTANTIATE_PACK(unsigned long long int)
INSTANTIATE_PACK(std::bitset<4>)
#undef INSTANTIATE_PACK
} // end namespace Mpi } // end namespace Mpi
} // end namespace Opm } // end namespace Opm

View File

@@ -19,179 +19,248 @@
#ifndef MPI_SERIALIZER_HPP #ifndef MPI_SERIALIZER_HPP
#define MPI_SERIALIZER_HPP #define MPI_SERIALIZER_HPP
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/utility/TimeService.hpp> #include <opm/common/utility/TimeService.hpp>
#include <opm/simulators/utils/ParallelCommunication.hpp> #include <opm/simulators/utils/ParallelCommunication.hpp>
#include <dune/common/parallel/mpitraits.hh>
#include <bitset> #include <bitset>
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <typeinfo>
namespace Opm namespace Opm {
namespace Mpi {
namespace detail {
//! \brief Abstract struct for packing which is (partially) specialized for specific types.
template <bool pod, class T>
struct Packing
{ {
static std::size_t packSize(const T&, Parallel::MPIComm);
static void pack(const T&, std::vector<char>&, int&, Parallel::MPIComm);
static void unpack(T&, std::vector<char>&, int&, Parallel::MPIComm);
};
namespace Mpi //! \brief Packaging for pod data.
template<class T>
struct Packing<true,T>
{ {
template<class T> //! \brief Calculates the pack size for a POD.
std::size_t packSize(const T*, std::size_t, Opm::Parallel::MPIComm, //! \param data The data to pack
std::integral_constant<bool, false>); //! \param comm The communicator to use
static std::size_t packSize(const T& data, Parallel::MPIComm comm)
{
return packSize(&data, 1, comm);
}
template<class T> //! \brief Calculates the pack size for an array of POD.
std::size_t packSize(const T*, std::size_t l, Opm::Parallel::MPIComm comm, //! \param data The array to pack
std::integral_constant<bool, true>); //! \param n Length of array
//! \param comm The communicator to use
static std::size_t packSize(const T*, std::size_t n, Parallel::MPIComm comm)
{
int size = 0;
MPI_Pack_size(n, Dune::MPITraits<T>::getType(), comm, &size);
return size;
}
template<class T> //! \brief Pack a POD.
std::size_t packSize(const T* data, std::size_t l, Opm::Parallel::MPIComm comm); //! \param data The variable to pack
//! \param buffer Buffer to pack into
//! \param position Position in buffer to use
//! \param comm The communicator to use
static void pack(const T& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
pack(&data, 1, buffer, position, comm);
}
//! \brief Pack an array of POD.
//! \param data The array to pack
//! \param n Length of array
//! \param buffer Buffer to pack into
//! \param position Position in buffer to use
//! \param comm The communicator to use
static void pack(const T* data,
std::size_t n,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
MPI_Pack(data, n, Dune::MPITraits<T>::getType(), buffer.data(),
buffer.size(), &position, comm);
}
//! \brief Unpack a POD.
//! \param data The variable to unpack
//! \param buffer Buffer to unpack from
//! \param position Position in buffer to use
//! \param comm The communicator to use
static void unpack(T& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
unpack(&data, 1, buffer, position, comm);
}
//! \brief Unpack an array of POD.
//! \param data The array to unpack
//! \param n Length of array
//! \param buffer Buffer to unpack from
//! \param position Position in buffer to use
//! \param comm The communicator to use
static void unpack(T* data,
std::size_t n,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
MPI_Unpack(buffer.data(), buffer.size(), &position, data, n,
Dune::MPITraits<T>::getType(), comm);
}
};
//! \brief Default handling for unsupported types.
template<class T> template<class T>
std::size_t packSize(const T&, Opm::Parallel::MPIComm, struct Packing<false,T>
std::integral_constant<bool, false>)
{ {
std::string msg = std::string{"Packing not (yet) supported for non-pod type: "} + typeid(T).name(); static std::size_t packSize(const T&, Parallel::MPIComm)
OPM_THROW(std::logic_error, msg); {
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
return 0;
}
static void pack(const T&, std::vector<char>&, int&,
Parallel::MPIComm)
{
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
}
static void unpack(T&, std::vector<char>&, int&,
Parallel::MPIComm)
{
static_assert(!std::is_same_v<T,T>, "Packing not supported for type");
}
};
//! \brief Specialization for std::bitset
template <std::size_t Size>
struct Packing<false,std::bitset<Size>>
{
static std::size_t packSize(const std::bitset<Size>&, Opm::Parallel::MPIComm);
static void pack(const std::bitset<Size>&, std::vector<char>&, int&, Opm::Parallel::MPIComm);
static void unpack(std::bitset<Size>&, std::vector<char>&, int&, Opm::Parallel::MPIComm);
};
#define ADD_PACK_SPECIALIZATION(T) \
template<> \
struct Packing<false,T> \
{ \
static std::size_t packSize(const T&, Parallel::MPIComm); \
static void pack(const T&, std::vector<char>&, int&, Parallel::MPIComm); \
static void unpack(T&, std::vector<char>&, int&, Parallel::MPIComm); \
};
ADD_PACK_SPECIALIZATION(std::string)
ADD_PACK_SPECIALIZATION(time_point)
} }
template<class T> //! \brief Struct handling packing of serialization for MPI communication.
std::size_t packSize(const T&, Opm::Parallel::MPIComm comm, struct Packer {
std::integral_constant<bool, true>) //! \brief Calculates the pack size for a variable.
{ //! \tparam T The type of the data to be packed
#if HAVE_MPI //! \param data The data to pack
int size{}; //! \param comm The communicator to use
MPI_Pack_size(1, Dune::MPITraits<T>::getType(), comm, &size); template<class T>
return size; static std::size_t packSize(const T& data, Parallel::MPIComm comm)
#else {
(void) comm; return detail::Packing<std::is_pod_v<T>,T>::packSize(data,comm);
return 0; }
#endif
}
template<class T> //! \brief Calculates the pack size for an array.
std::size_t packSize(const T& data, Opm::Parallel::MPIComm comm) //! \tparam T The type of the data to be packed
{ //! \param data The array to pack
return packSize(data, comm, typename std::is_pod<T>::type()); //! \param n Length of array
} //! \param comm The communicator to use
template<class T>
static std::size_t packSize(const T* data, std::size_t n, Parallel::MPIComm comm)
{
static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
return detail::Packing<true,T>::packSize(data,n,comm);
}
std::size_t packSize(const char* str, Opm::Parallel::MPIComm comm); //! \brief Pack a variable.
//! \tparam T The type of the data to be packed
//! \param data The variable to pack
//! \param buffer Buffer to pack into
//! \param position Position in buffer to use
//! \param comm The communicator to use
template<class T>
static void pack(const T& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
detail::Packing<std::is_pod_v<T>,T>::pack(data, buffer, position, comm);
}
template<std::size_t Size> //! \brief Pack an array.
std::size_t packSize(const std::bitset<Size>& data, Opm::Parallel::MPIComm comm); //! \tparam T The type of the data to be packed
//! \param data The array to pack
//! \param n Length of array
//! \param buffer Buffer to pack into
//! \param position Position in buffer to use
//! \param comm The communicator to use
template<class T>
static void pack(const T* data,
std::size_t n,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
detail::Packing<true,T>::pack(data, n, buffer, position, comm);
}
////// pack routines //! \brief Unpack a variable.
//! \tparam T The type of the data to be unpacked
//! \param data The variable to unpack
//! \param buffer Buffer to unpack from
//! \param position Position in buffer to use
//! \param comm The communicator to use
template<class T>
static void unpack(T& data,
std::vector<char>& buffer,
int& position,
Parallel::MPIComm comm)
{
detail::Packing<std::is_pod_v<T>,T>::unpack(data, buffer, position, comm);
}
template<class T> //! \brief Unpack an array.
void pack(const T*, std::size_t, std::vector<char>&, int&, //! \tparam T The type of the data to be unpacked
Opm::Parallel::MPIComm, std::integral_constant<bool, false>); //! \param data The array to unpack
//! \param n Length of array
template<class T> //! \param buffer Buffer to unpack from
void pack(const T* data, std::size_t l, std::vector<char>& buffer, int& position, //! \param position Position in buffer to use
Opm::Parallel::MPIComm comm, std::integral_constant<bool, true>); //! \param comm The communicator to use
template<class T>
template<class T> static void unpack(T* data,
void pack(const T* data, std::size_t l, std::vector<char>& buffer, int& position, std::size_t n,
Opm::Parallel::MPIComm comm); std::vector<char>& buffer,
int& position,
template<class T> Parallel::MPIComm comm)
void pack(const T&, std::vector<char>&, int&, {
Opm::Parallel::MPIComm, std::integral_constant<bool, false>) static_assert(std::is_pod_v<T>, "Array packing not supported for non-pod data");
{ detail::Packing<true,T>::unpack(data, n, buffer, position, comm);
OPM_THROW(std::logic_error, "Packing not (yet) supported for this non-pod type."); }
} };
template<class T>
void pack(const T& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm, std::integral_constant<bool, true>)
{
#if HAVE_MPI
MPI_Pack(&data, 1, Dune::MPITraits<T>::getType(), buffer.data(),
buffer.size(), &position, comm);
#else
(void) data;
(void) comm;
(void) buffer;
(void) position;
#endif
}
template<class T>
void pack(const T& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
pack(data, buffer, position, comm, typename std::is_pod<T>::type());
}
void pack(const char* str, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm);
template<std::size_t Size>
void pack(const std::bitset<Size>& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm);
/// unpack routines
template<class T>
void unpack(T*, const std::size_t&, std::vector<char>&, int&,
Opm::Parallel::MPIComm, std::integral_constant<bool, false>);
template<class T>
void unpack(T* data, const std::size_t& l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm,
std::integral_constant<bool, true>);
template<class T>
void unpack(T* data, const std::size_t& l, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm);
template<class T>
void unpack(T&, std::vector<char>&, int&,
Opm::Parallel::MPIComm, std::integral_constant<bool, false>)
{
OPM_THROW(std::logic_error, "Packing not (yet) supported for this non-pod type.");
}
template<class T>
void unpack(T& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm, std::integral_constant<bool, true>)
{
#if HAVE_MPI
MPI_Unpack(buffer.data(), buffer.size(), &position, &data, 1,
Dune::MPITraits<T>::getType(), comm);
#else
(void) data;
(void) comm;
(void) buffer;
(void) position;
#endif
}
template<class T>
void unpack(T& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm)
{
unpack(data, buffer, position, comm, typename std::is_pod<T>::type());
}
void unpack(char* str, std::size_t length, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm);
template<std::size_t Size>
void unpack(std::bitset<Size>& data, std::vector<char>& buffer, int& position,
Opm::Parallel::MPIComm comm);
/// prototypes for complex types
#define ADD_PACK_PROTOTYPES(T) \
std::size_t packSize(const T& data, Opm::Parallel::MPIComm comm); \
void pack(const T& data, std::vector<char>& buffer, int& position, \
Opm::Parallel::MPIComm comm); \
void unpack(T& data, std::vector<char>& buffer, int& position, \
Opm::Parallel::MPIComm comm);
ADD_PACK_PROTOTYPES(std::string)
ADD_PACK_PROTOTYPES(time_point)
} // end namespace Mpi } // end namespace Mpi
} // end namespace Opm } // end namespace Opm
#endif // MPI_SERIALIZER_HPP #endif // MPI_SERIALIZER_HPP