vtk-m/vtkm/cont/testing/TestingSerialization.h
Kenneth Moreland ec34cb56c4 Use new ways to get array portal in control environment
Also fix deadlocks that occur when portals are not destroyed
in time.
2020-02-26 13:10:46 -07:00

208 lines
5.4 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_testing_TestingSerialization_h
#define vtk_m_cont_testing_TestingSerialization_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/thirdparty/diy/serialization.h>
#include <random>
namespace vtkm
{
namespace cont
{
namespace testing
{
namespace serialization
{
//-----------------------------------------------------------------------------
static std::default_random_engine generator;
template <typename T>
class UniformRandomValueGenerator
{
private:
using DistributionType = typename std::conditional<std::is_integral<T>::value,
std::uniform_int_distribution<vtkm::Id>,
std::uniform_real_distribution<T>>::type;
public:
UniformRandomValueGenerator()
: Distribution(-127, 127)
{
}
UniformRandomValueGenerator(T min, T max)
: Distribution(static_cast<typename DistributionType::result_type>(min),
static_cast<typename DistributionType::result_type>(max))
{
}
T operator()() { return static_cast<T>(this->Distribution(generator)); }
private:
DistributionType Distribution;
};
template <typename T, typename Tag = typename vtkm::VecTraits<T>::HasMultipleComponents>
struct BaseScalarType;
template <typename T>
struct BaseScalarType<T, vtkm::VecTraitsTagSingleComponent>
{
using Type = T;
};
template <typename T>
struct BaseScalarType<T, vtkm::VecTraitsTagMultipleComponents>
{
using Type = typename BaseScalarType<typename vtkm::VecTraits<T>::ComponentType>::Type;
};
template <typename T>
using BaseScalarType_t = typename BaseScalarType<T>::Type;
template <typename T>
struct RandomValue_
{
static T Make(UniformRandomValueGenerator<T>& rangen) { return static_cast<T>(rangen()); }
};
template <typename T, vtkm::IdComponent NumComponents>
struct RandomValue_<vtkm::Vec<T, NumComponents>>
{
using VecType = vtkm::Vec<T, NumComponents>;
static VecType Make(UniformRandomValueGenerator<BaseScalarType_t<T>>& rangen)
{
VecType val{};
for (vtkm::IdComponent i = 0; i < NumComponents; ++i)
{
val[i] = RandomValue_<T>::Make(rangen);
}
return val;
}
};
template <typename T>
struct RandomValue : RandomValue_<T>
{
using RandomValue_<T>::Make;
static T Make(BaseScalarType_t<T> min, BaseScalarType_t<T> max)
{
auto rangen = UniformRandomValueGenerator<BaseScalarType_t<T>>(min, max);
return Make(rangen);
}
static T Make()
{
auto rangen = UniformRandomValueGenerator<BaseScalarType_t<T>>();
return Make(rangen);
}
};
template <typename T>
struct RandomArrayHandle
{
static vtkm::cont::ArrayHandle<T> Make(UniformRandomValueGenerator<BaseScalarType_t<T>>& rangen,
vtkm::Id length)
{
vtkm::cont::ArrayHandle<T> a;
a.Allocate(length);
for (vtkm::Id i = 0; i < length; ++i)
{
a.WritePortal().Set(i, RandomValue<T>::Make(rangen));
}
return a;
}
static vtkm::cont::ArrayHandle<T> Make(vtkm::Id length,
BaseScalarType_t<T> min,
BaseScalarType_t<T> max)
{
auto rangen = UniformRandomValueGenerator<BaseScalarType_t<T>>(min, max);
return Make(rangen, length);
}
static vtkm::cont::ArrayHandle<T> Make(vtkm::Id length)
{
auto rangen = UniformRandomValueGenerator<BaseScalarType_t<T>>();
return Make(rangen, length);
}
};
//-----------------------------------------------------------------------------
template <typename T>
struct Block
{
T send;
T received;
};
template <typename T, typename TestEqualFunctor>
void TestSerialization(const T& obj, const TestEqualFunctor& test)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
vtkmdiy::Master master(comm);
auto nblocks = comm.size();
vtkmdiy::RoundRobinAssigner assigner(comm.size(), nblocks);
std::vector<int> gids;
assigner.local_gids(comm.rank(), gids);
VTKM_ASSERT(gids.size() == 1);
auto gid = gids[0];
Block<T> block;
block.send = obj;
vtkmdiy::Link* link = new vtkmdiy::Link;
vtkmdiy::BlockID neighbor;
// send neighbor
neighbor.gid = (gid < (nblocks - 1)) ? (gid + 1) : 0;
neighbor.proc = assigner.rank(neighbor.gid);
link->add_neighbor(neighbor);
// recv neighbor
neighbor.gid = (gid > 0) ? (gid - 1) : (nblocks - 1);
neighbor.proc = assigner.rank(neighbor.gid);
link->add_neighbor(neighbor);
master.add(gid, &block, link);
// compute, exchange, compute
master.foreach ([](Block<T>* b, const vtkmdiy::Master::ProxyWithLink& cp) {
cp.enqueue(cp.link()->target(0), b->send);
});
master.exchange();
master.foreach ([](Block<T>* b, const vtkmdiy::Master::ProxyWithLink& cp) {
cp.dequeue(cp.link()->target(1).gid, b->received);
});
comm.barrier();
test(block.send, block.received);
}
}
}
}
} // vtkm::cont::testing::serialization
#endif // vtk_m_cont_testing_TestingSerialization_h