std::complex<double>
我想使用 Boost.MPI传输大量数字。在Boost.MPI 教程中解释说
为了获得不包含任何指针的小型固定长度数据类型的最佳性能,使用 Boost.MPI 和 Boost.Serialization 的类型特征标记它们非常重要。
已经讨论过不包含指针的固定长度类型可以用作 as
is_mpi_datatype
,例如:namespace boost { namespace mpi { template <> struct is_mpi_datatype<gps_position> : mpl::true_ { }; } }
或等效的宏
BOOST_IS_MPI_DATATYPE(gps_position)
的文档is_mpi_datatype
给出了另一个例子:
[...] 为此,首先将数据类型设为 Serializable(使用 Boost.Serialization 库);然后,专门化
is_mpi_datatype
该类型的特征,point
以便它derive mpl::true_
:namespace boost { namespace mpi { template<> struct is_mpi_datatype<point> : public mpl::true_ { }; } }
当我完全尝试优化性能 [在我下面的尝试中的选项 (A) 或 (B)] 时,我观察到 Boost.MPI 不使用内置 MPI 数据类型MPI_DOUBLE_COMPLEX
,也不映射到MPI_SUM
操作 [断言 (3) 和 ( 4)在我下面的尝试中]。此外,启用 (A) 或 (B) 之一以及禁用断言 (3) 和 (4) 会在运行时产生分段错误。
在Boost.MPI 的某些源文件中,我发现了一个名为的未记录(?)宏BOOST_MPI_DATATYPE
,它做正确的事情,但标有注释/// INTERNAL ONLY
。
在实现这个丑陋的 hack(?)之前,我想问一下:告诉 Boost.MPI 使用内置MPI_DOUBLE_COMPLEX
数据类型的预期方法是什么std::complex<double>
?
#include <complex>
#include <functional>
#include <iostream>
#include <boost/mpi.hpp>
#include <boost/mpi/operations.hpp>
#include <boost/serialization/complex.hpp>
// tested with GCC 6.2.0, OpenMPI 2.0.1, boost 1.62.0
// mpic++ -lboost_mpi -lboost_serialization boost-mpi-complex.cpp
using dcomplex = std::complex<double>;
using dcplus = std::plus<dcomplex>;
////////////////////////////////////////////////////////////////////////////////
// How to pass assertions (1) to (5) below?
////////////////////////////////////////////////////////////////////////////////
// (A): documented, but fails assertions (2) and (3)
// if (2) and (3) are removed with this OPTION: segmentation fault at runtime
//BOOST_IS_MPI_DATATYPE(dcomplex)
// (B): documented, but same problems as (A)
namespace boost::mpi {
//template<> struct is_mpi_datatype<dcomplex> : boost::mpl::true_ {};
}
// (C): works, but not documented(?) and has `INTERNAL ONLY` comment in source
namespace boost::mpi {
//BOOST_MPI_DATATYPE(dcomplex, MPI_DOUBLE_COMPLEX, complex);
}
// (D): works, equivalent to (C)
// BUT if `is_mpi_complex_datatype` is specialized without `get_mpi_datatype`
// then compilation is fine with all assertions, but running yields segfault
namespace boost::mpi {
//template<> inline MPI_Datatype get_mpi_datatype<dcomplex>(const dcomplex&) {
// return MPI_DOUBLE_COMPLEX;
//}
//template<> struct is_mpi_complex_datatype<dcomplex> : boost::mpl::true_ {};
}
// optional; works as expected for assertion (4)
namespace boost::mpi {
template<> struct is_commutative<dcplus, dcomplex> : mpl::true_ {};
}
// If these assertions are removed and none of (A) to (D) is activated then
// everything works as expected, but I would like to optimize serialization
static_assert(boost::mpi::is_mpi_datatype<dcomplex>{}); // (1)
static_assert(boost::mpi::is_mpi_builtin_datatype<dcomplex>{}); // (2)
static_assert(boost::mpi::is_mpi_op<dcplus, dcomplex>{}); // (3)
static_assert(boost::mpi::is_commutative<dcplus, dcomplex>{}); // (4)
static_assert(boost::serialization::is_bitwise_serializable<dcomplex>{}); // (5)
int main() {
boost::mpi::environment env{};
boost::mpi::communicator world{};
constexpr size_t N = 4;
dcomplex data[N]{};
if(0 == world.rank()) {
for(size_t i=0; i<N; ++i) data[i] = dcomplex{double(i), 0.0};
}
if(1 == world.rank()) {
for(size_t i=0; i<N; ++i) data[i] = dcomplex{0.0, double(N+i)};
}
all_reduce(world, boost::mpi::inplace(data), N, dcplus{});
if(0 == world.rank()) {
for(auto&& x : data) std::cout << x << std::endl;
}
return 0;
}