#include <deal.II/base/exceptions.h>
#include <deal.II/base/kokkos.h>
+DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
#include <Kokkos_Core.hpp>
+DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
#include <functional>
#include <memory>
namespace MemorySpace
{
/**
- * Structure which stores data on the host or the device depending on the
- * template parameter @p MemorySpace. The data is copied into the structure
- * which then owns the data and will release the memory when the destructor is
- * called.
+ * Data structure
*/
template <typename T, typename MemorySpace>
struct MemorySpaceData
{
- MemorySpaceData();
+ MemorySpaceData()
+ {
+ static_assert(std::is_same<MemorySpace, Host>::value ||
+ std::is_same<MemorySpace, Device>::value,
+ "MemorySpace should be Host or Device");
+ }
/**
* Copy the active data (values for Host and values_dev for Device) to @p begin.
* If the data is on the device it is moved to the host.
*/
void
- copy_to(T *begin, const std::size_t n_elements);
+ copy_to(T *begin, std::size_t n_elements)
+ {
+ (void)begin;
+ (void)n_elements;
+ }
/**
* Copy the data in @p begin to the active data of the structure (values for
* Host and values_dev for Device). The pointer @p begin must be on the host.
*/
void
- copy_from(const T *begin, const std::size_t n_elements);
+ copy_from(T *begin, std::size_t n_elements)
+ {
+ (void)begin;
+ (void)n_elements;
+ }
/**
- * Kokkos View to the data on the host
+ * Pointer to data on the host.
*/
Kokkos::View<T *, Kokkos::HostSpace> values;
/**
- * Kokkos View to the data on the device
+ * Pointer to data on the device.
*/
Kokkos::View<T *, typename MemorySpace::kokkos_space> values_dev;
// The pointer is shared so that MemorySpaceData can be copied and
// MemorySpaceData::values can be used in Kokkos::parallel_for. This
// pointer owns the data when using shared memory with MPI. In this case,
- // the Kokkos::View in non-owning. When shared memory with MPI is not used,
- // the pointer is not used.
+ // the (host) Kokkos::View is non-owning. When shared memory with MPI is not
+ // used, the pointer is not used.
std::shared_ptr<T> values_sm_ptr;
/**
- * Pointers to the data of the processes sharing the same memory.
+ * Pointers to the data of the processes sharing the same memory. Not used for MemorySpace::Device.
*/
std::vector<ArrayView<const T>> values_sm;
};
*/
template <typename T, typename MemorySpace>
inline void
- swap(MemorySpaceData<T, MemorySpace> &u, MemorySpaceData<T, MemorySpace> &v);
-
+ swap(MemorySpaceData<T, MemorySpace> &,
+ MemorySpaceData<T, MemorySpace> &)
+ {
+ static_assert(std::is_same<MemorySpace, Host>::value ||
+ std::is_same<MemorySpace, Device>::value,
+ "MemorySpace should be Host or Device");
+ }
#ifndef DOXYGEN
- template <typename T, typename MemorySpace>
- MemorySpaceData<T, MemorySpace>::MemorySpaceData()
+ template <typename T>
+ struct MemorySpaceData<T, Host>
+ {
+ using MemorySpace = Host;
+
+ MemorySpaceData()
: values((dealii::Impl::ensure_kokkos_initialized(),
Kokkos::View<T *, Kokkos::HostSpace>("host data", 0)))
- , values_dev(Kokkos::View<T *, typename MemorySpace::kokkos_space>(
- "memoryspace data",
- 0))
- {}
+ {}
+ void
+ copy_to(T *begin, std::size_t n_elements)
+ {
+ Assert(n_elements <= values.extent(0),
+ ExcMessage("n_elements greater than the size of values."));
+ using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
+ Kokkos::
+ View<T *, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
+ begin_view(begin, n_elements);
+ Kokkos::deep_copy(
+ ExecutionSpace{},
+ begin_view,
+ Kokkos::subview(values, Kokkos::make_pair(std::size_t(0), n_elements)));
+ ExecutionSpace{}.fence();
+ }
+ void
+ copy_from(T *begin, std::size_t n_elements)
+ {
+ Assert(n_elements <= values.extent(0),
+ ExcMessage("n_elements greater than the size of values."));
+ using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
+ Kokkos::View<const T *,
+ Kokkos::HostSpace,
+ Kokkos::MemoryTraits<Kokkos::Unmanaged>>
+ begin_view(begin, n_elements);
+ Kokkos::deep_copy(
+ ExecutionSpace{},
+ Kokkos::subview(values, Kokkos::make_pair(std::size_t(0), n_elements)),
+ begin_view);
+ ExecutionSpace{}.fence();
+ }
- template <typename T, typename MemorySpace>
- void
- MemorySpaceData<T, MemorySpace>::copy_to(T * begin,
- const std::size_t n_elements)
+ Kokkos::View<T *, Kokkos::HostSpace> values;
+
+ // unused
+ Kokkos::View<T *, typename MemorySpace::kokkos_space> values_dev;
+
+ std::shared_ptr<T> values_sm_ptr;
+
+ std::vector<ArrayView<const T>> values_sm;
+ };
+
+
+
+ template <typename T>
+ inline void
+ swap(MemorySpaceData<T, Host> &u, MemorySpaceData<T, Host> &v)
{
- Assert(n_elements <= values.extent(0),
- ExcMessage("n_elements greater than the size of values."));
- using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
- Kokkos::
- View<T *, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
- begin_view(begin, n_elements);
- Kokkos::deep_copy(
- ExecutionSpace{},
- begin_view,
- Kokkos::subview(values, Kokkos::make_pair(std::size_t(0), n_elements)));
- ExecutionSpace{}.fence();
+ std::swap(u.values, v.values);
+ std::swap(u.values_sm_ptr, v.values_sm_ptr);
}
- template <typename T, typename MemorySpace>
- void
- MemorySpaceData<T, MemorySpace>::copy_from(const T * begin,
- const std::size_t n_elements)
+ template <typename T>
+ struct MemorySpaceData<T, Device>
{
- Assert(n_elements <= values.extent(0),
- ExcMessage("n_elements greater than the size of values."));
- using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
- Kokkos::View<const T *,
- Kokkos::HostSpace,
- Kokkos::MemoryTraits<Kokkos::Unmanaged>>
- begin_view(begin, n_elements);
- Kokkos::deep_copy(
- ExecutionSpace{},
- Kokkos::subview(values, Kokkos::make_pair(std::size_t(0), n_elements)),
- begin_view);
- ExecutionSpace{}.fence();
- }
+ using MemorySpace = Device;
+ MemorySpaceData()
+ : values((dealii::Impl::ensure_kokkos_initialized(),
+ Kokkos::View<T *, Kokkos::HostSpace>("host data", 0)))
+ , values_dev(Kokkos::View<T *, typename MemorySpace::kokkos_space>(
+ "memoryspace data",
+ 0))
+ {}
+ void
+ copy_to(T *begin, std::size_t n_elements)
+ {
+ Assert(n_elements <= values_dev.extent(0),
+ ExcMessage("n_elements greater than the size of values."));
+ using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
+ Kokkos::
+ View<T *, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
+ begin_view(begin, n_elements);
+ Kokkos::deep_copy(
+ ExecutionSpace{},
+ begin_view,
+ Kokkos::subview(values_dev, Kokkos::make_pair(std::size_t(0), n_elements)));
+ ExecutionSpace{}.fence();
+ }
- /**
- * Swap function similar to std::swap.
- */
- template <typename T, typename MemorySpace>
+ void
+ copy_from(T *begin, std::size_t n_elements)
+ {
+ Assert(n_elements <= values_dev.extent(0),
+ ExcMessage("n_elements greater than the size of values."));
+ using ExecutionSpace = typename MemorySpace::kokkos_space::execution_space;
+ Kokkos::View<const T *,
+ Kokkos::HostSpace,
+ Kokkos::MemoryTraits<Kokkos::Unmanaged>>
+ begin_view(begin, n_elements);
+ Kokkos::deep_copy(
+ ExecutionSpace{},
+ Kokkos::subview(values_dev, Kokkos::make_pair(std::size_t(0), n_elements)),
+ begin_view);
+ ExecutionSpace{}.fence();
+ }
+
+ Kokkos::View<T *, Kokkos::HostSpace> values;
+
+ Kokkos::View<T *, typename MemorySpace::kokkos_space> values_dev;
+
+ // unused
+ std::shared_ptr<T> values_sm_ptr;
+
+ // unused
+ std::vector<ArrayView<const T>> values_sm;
+ };
+
+
+
+ template <typename T>
inline void
- swap(MemorySpaceData<T, MemorySpace> &u, MemorySpaceData<T, MemorySpace> &v)
+ swap(MemorySpaceData<T, Device> &u, MemorySpaceData<T, Device> &v)
{
- auto u_copy = Kokkos::create_mirror(Kokkos::WithoutInitializing, u);
- typename MemorySpace::execution_space exec_space;
- // The first two calls to Kokkos::deep_copy are asynchronous. The last call
- // will wait for the three deep_copy to be done before returning.
- Kokkos::deep_copy(exec_space, u_copy, u);
- Kokkos::deep_copy(exec_space, u, v);
- Kokkos::deep_copy(v, u_copy);
+ std::swap(u.values, v.values);
+ std::swap(u.values_dev, v.values_dev);
}
#endif
{
# if defined(DEAL_II_COMPILER_CUDA_AWARE) && \
defined(DEAL_II_MPI_WITH_CUDA_SUPPORT)
- Assert(
+ Assert(
(std::is_same<MemorySpaceType, dealii::MemorySpace::CUDA>::value),
ExcMessage(
"Using MemorySpace::CUDA only allowed if the code is compiled with a CUDA compiler!"));
# endif
}
+ if (std::is_same_v<MemorySpaceType, MemorySpace::Device>)
+ std::cout << "device" << std::endl;
+ if (std::is_same_v<MemorySpaceType, MemorySpace::Host>)
+ std::cout << "host" << std::endl;
+ std::cout << "size_dev: " << data.values_dev.extent(0) << " " << partitioner->locally_owned_size() << std::endl;
+ std::cout << "size_host: " << data.values.extent(0) << " " << partitioner->locally_owned_size() << std::endl;
+
# if defined DEAL_II_COMPILER_CUDA_AWARE && \
!defined(DEAL_II_MPI_WITH_CUDA_SUPPORT)
- // Move the data to the host and then move it back to the
- // device. We use values to store the elements because the function
- // uses a view of the array and thus we need the data on the host to
- // outlive the scope of the function.
- data.values = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, data.values_dev);
+ if (std::is_same_v<MemorySpaceType, MemorySpace::CUDA>) {
+ // Move the data to the host and then move it back to the
+ // device. We use values to store the elements because the function
+ // uses a view of the array and thus we need the data on the host to
+ // outlive the scope of the function.
+ data.values = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, data.values_dev);
+ }
# endif
-# if !(defined(DEAL_II_COMPILER_CUDA_AWARE) && \
- defined(DEAL_II_MPI_WITH_CUDA_SUPPORT))
+# if defined(DEAL_II_COMPILER_CUDA_AWARE) && \
+ defined(DEAL_II_MPI_WITH_CUDA_SUPPORT)
+ if (std::is_same_v<MemorySpaceType, MemorySpace::CUDA>) {
+ partitioner->export_to_ghosted_array_start<Number, MemorySpace::CUDA>(
+ communication_channel,
+ ArrayView<const Number, MemorySpace::CUDA>(
+ data.values_dev.data(), partitioner->locally_owned_size()),
+ ArrayView<Number, MemorySpace::CUDA>(import_data.values_dev.data(),
+ partitioner->n_import_indices()),
+ ArrayView<Number, MemorySpace::CUDA>(
+ data.values_dev.data() + partitioner->locally_owned_size(),
+ partitioner->n_ghost_indices()),
+ update_ghost_values_requests);
+ } else
+#else
+ {
partitioner->export_to_ghosted_array_start<Number, MemorySpace::Host>(
communication_channel,
ArrayView<const Number, MemorySpace::Host>(
data.values.data() + partitioner->locally_owned_size(),
partitioner->n_ghost_indices()),
update_ghost_values_requests);
-# else
- partitioner->export_to_ghosted_array_start<Number, MemorySpace::CUDA>(
- communication_channel,
- ArrayView<const Number, MemorySpace::CUDA>(
- data.values_dev.data(), partitioner->locally_owned_size()),
- ArrayView<Number, MemorySpace::CUDA>(import_data.values_dev.data(),
- partitioner->n_import_indices()),
- ArrayView<Number, MemorySpace::CUDA>(
- data.values_dev.data() + partitioner->locally_owned_size(),
- partitioner->n_ghost_indices()),
- update_ghost_values_requests);
+ }
# endif
#else
// make this function thread safe
std::lock_guard<std::mutex> lock(mutex);
-# if !(defined(DEAL_II_COMPILER_CUDA_AWARE) && \
- defined(DEAL_II_MPI_WITH_CUDA_SUPPORT))
+# if defined(DEAL_II_COMPILER_CUDA_AWARE) && \
+ defined(DEAL_II_MPI_WITH_CUDA_SUPPORT)
+ if (std::is_same<MemorySpaceType, MemorySpace::CUDA>::value)
+ {
+ partitioner->export_to_ghosted_array_finish(
+ ArrayView<Number, MemorySpace::CUDA>(
+ data.values_dev.data() + partitioner->locally_owned_size(),
+ partitioner->n_ghost_indices()),
+ update_ghost_values_requests);
+ } else
+#else
+ {
partitioner->export_to_ghosted_array_finish(
ArrayView<Number, MemorySpace::Host>(
data.values.data() + partitioner->locally_owned_size(),
partitioner->n_ghost_indices()),
update_ghost_values_requests);
-# else
- partitioner->export_to_ghosted_array_finish(
- ArrayView<Number, MemorySpace::CUDA>(
- data.values_dev.data() + partitioner->locally_owned_size(),
- partitioner->n_ghost_indices()),
- update_ghost_values_requests);
+ }
# endif
}