8#include <compile_time_options.h>
12#include <deal.II/base/exceptions.h>
13#include <deal.II/base/memory_space.h>
14#include <deal.II/base/vectorization.h>
30 !std::is_same_v<dealii::MemorySpace::Host::kokkos_space,
31 dealii::MemorySpace::Default::kokkos_space>;
48 : dealii::VectorizedArray<NUMBER>::size();
64 dealii::MemorySpace::Default,
65 dealii::MemorySpace::Host>;
75 template <
typename MemorySpace>
77 std::conditional_t<std::is_same_v<MemorySpace, dealii::MemorySpace::Host>,
78 dealii::MemorySpace::Default,
79 dealii::MemorySpace::Host>;
193 template <
typename Derived>
209 template <
typename MemorySpace>
222 template <
typename MemorySpace>
233 template <
typename MemorySpace>
247 template <
typename MemorySpace>
282 template <
typename MemorySpace>
296 template <
typename MemorySpace>
318 using HostSpace = dealii::MemorySpace::Host;
319 using DefaultSpace = dealii::MemorySpace::Default;
321 template <
typename MemorySpace>
322 bool &residency_flag()
const;
325 const Derived &derived()
const;
327 mutable bool host_resident_ =
false;
328 mutable bool default_resident_ =
false;
458 template <
typename T>
467 static constexpr bool is_array = std::is_pointer_v<T>;
475 static_assert(std::is_trivially_copyable_v<value_type>,
476 "The stored type has to be trivially copyable so that we "
477 "can move it into device memory");
479 static_assert(!std::is_pointer_v<value_type>,
480 "Only a single level of indirection is supported: a "
481 "Mirrored<T *> object maintains a one dimensional array of "
482 "objects of type T");
484 static_assert(!std::is_array_v<T>,
485 "An array of objects is spelled Mirrored<T *>, and not "
499 template <
typename InitializedMemorySpace = dealii::MemorySpace::Host>
500 Mirrored(
const std::string &label =
"mirrored object",
503 InitializedMemorySpace = {})
517 template <
typename InitializedMemorySpace = dealii::MemorySpace::Host>
518 Mirrored(
const std::string &label =
"mirrored array",
519 const std::size_t
size = 0,
522 InitializedMemorySpace = {})
530 template <
typename InitializedMemorySpace = dealii::MemorySpace::Host>
534 InitializedMemorySpace = {})
548 template <typename MemorySpace = dealii::MemorySpace::Host>
556 template <typename MemorySpace = dealii::MemorySpace::Host>
565 using HostSpace = dealii::MemorySpace::Host;
566 using DefaultSpace = dealii::MemorySpace::Default;
568 template <typename MemorySpace>
569 using KokkosView = Kokkos::View<T, typename MemorySpace::kokkos_space>;
574 template <typename MemorySpace>
575 KokkosView<MemorySpace> &storage() const;
582 template <typename InitializedMemorySpace>
583 void initialize_storage();
589 template <typename MemorySpace>
590 void allocate_storage() const;
592 template <typename To, typename From>
593 void deep_copy_storage() const;
595 template <typename MemorySpace>
596 void deallocate_storage();
601 std::
size_t size_ = 0;
603 mutable KokkosView<HostSpace> host_;
604 mutable KokkosView<DefaultSpace> default_;
639 template <
int dim, typename Number, typename MemorySpace, typename Object>
644 using SimdNumber = std::conditional_t<
645 std::is_same_v<MemorySpace, dealii::MemorySpace::Host>,
646 dealii::VectorizedArray<Number>,
656 template <
typename T>
657 static auto create_view(
const Object &
object)
659 if constexpr (std::is_same_v<MemorySpace, dealii::MemorySpace::Host>)
660 return object.
template view<dim, T>();
661 else if constexpr (
requires {
662 object.template view<dim, T, MemorySpace>();
664 return object.
template view<dim, T, MemorySpace>();
669 "The equation does not support MemorySpace");
670 return object.template view<dim, T>();
675 decltype(create_view<Number>(std::declval<const Object &>()));
677 decltype(create_view<SimdNumber>(std::declval<const Object &>()));
681 : scalar_view_(create_view<Number>(object))
682 , simd_view_(create_view<SimdNumber>(object))
690 template <
typename T>
691 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
const auto &
view()
const
693 if constexpr (std::is_same_v<T, typename get_value_type<T>::type>)
700 ScalarView scalar_view_;
710 template <
int dim,
typename Number,
typename MemorySpace,
typename Object>
725 template <
typename Derived>
726 template <
typename MemorySpace>
729 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
730 std::is_same_v<MemorySpace, DefaultSpace>,
731 "Unexpected memory space");
734 Assert(host_resident_ == default_resident_,
736 "Internal error: the host and default memory spaces coincide "
737 "but the two residency flags do not. There is only a single "
738 "allocation, so the object has to be resident on both memory "
739 "spaces, or on neither of them."));
740 return host_resident_ || default_resident_;
743 return residency_flag<MemorySpace>();
747 template <
typename Derived>
748 template <
typename MemorySpace>
751 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
752 std::is_same_v<MemorySpace, DefaultSpace>,
753 "Unexpected memory space");
759 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
760 return transfer_policy_ ==
764 return transfer_policy_ ==
770 template <
typename Derived>
771 template <
typename MemorySpace>
774 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
775 std::is_same_v<MemorySpace, DefaultSpace>,
776 "Unexpected memory space");
783 Assert(host_resident_ && default_resident_,
785 "Unable to copy to the chosen memory space: the host and "
786 "default memory spaces coincide but the object is not "
787 "resident on them. The object has not been properly "
792 Assert(!is_pinned<MemorySpace>() || is_resident<MemorySpace>(),
794 "Unable to copy to the chosen memory space: the selected "
795 "transfer policy pins the chosen memory space but the object "
796 "is not resident on it. The object has not been properly "
799 if (is_resident<MemorySpace>())
802 using OtherSpace = other_space_t<MemorySpace>;
803 Assert(is_resident<OtherSpace>(),
805 "Unable to copy to the chosen memory space: the object has "
806 "not been properly initialized."));
808 derived().template allocate_storage<MemorySpace>();
809 derived().template deep_copy_storage<MemorySpace, OtherSpace>();
810 residency_flag<MemorySpace>() =
true;
814 template <
typename Derived>
815 template <
typename MemorySpace>
818 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
819 std::is_same_v<MemorySpace, DefaultSpace>,
820 "Unexpected memory space");
828 Assert(host_resident_ && default_resident_,
830 "Unable to move to the chosen memory space: the host and "
831 "default memory spaces coincide but the object is not "
832 "resident on them. The object has not been properly "
837 Assert(!is_pinned<MemorySpace>() || is_resident<MemorySpace>(),
839 "Unable to move to the chosen memory space: the selected "
840 "transfer policy pins the chosen memory space but the object "
841 "is not resident on it. The object has not been properly "
844 using OtherSpace = other_space_t<MemorySpace>;
846 Assert(!is_pinned<OtherSpace>(),
848 "Unable to move to the chosen memory space: the selected "
849 "transfer policy requires the data to remain resident on "
850 "the other memory space."));
852 if (!is_resident<MemorySpace>()) {
853 Assert(is_resident<OtherSpace>(),
855 "Unable to move to the chosen memory space: the object has "
856 "not been properly initialized."));
858 derived().template allocate_storage<MemorySpace>();
859 derived().template deep_copy_storage<MemorySpace, OtherSpace>();
860 residency_flag<MemorySpace>() =
true;
863 if (residency_flag<OtherSpace>()) {
864 derived().template deallocate_storage<OtherSpace>();
865 residency_flag<OtherSpace>() =
false;
870 template <
typename Derived>
873 return transfer_policy_;
877 template <
typename Derived>
883 Assert(!is_pinned<HostSpace>() || is_resident<HostSpace>(),
885 "Unable to select the given transfer policy: the policy pins "
886 "the host memory space but the object is not resident on it. "
887 "Transfer the data to the pinned memory space before selecting "
888 "the transfer policy."));
890 Assert(!is_pinned<DefaultSpace>() || is_resident<DefaultSpace>(),
892 "Unable to select the given transfer policy: the policy pins "
893 "the default memory space but the object is not resident on "
894 "it. Transfer the data to the pinned memory space before "
895 "selecting the transfer policy."));
899 template <
typename Derived>
900 template <
typename MemorySpace>
904 copy_to_memory_space<MemorySpace>();
907 Assert(is_resident<MemorySpace>(),
909 "The chosen memory space is not resident. Either call "
910 "copy_to_memory_space() / move_to_memory_space() prior to "
911 "requesting a view, or select one of the "
912 "TransferPolicy::implicit_transfers* policies."));
917 template <
typename Derived>
918 template <
typename MemorySpace>
922 Assert(!
is_pinned<other_space_t<MemorySpace>>(),
924 "Unable to request a writable view on the chosen memory "
925 "space: the selected transfer policy requires the data to "
926 "remain resident on the other memory space."));
928 move_to_memory_space<MemorySpace>();
931 Assert(is_resident<MemorySpace>(),
933 "The chosen memory space is not resident. Either call "
934 "copy_to_memory_space() / move_to_memory_space() prior to "
935 "requesting a view, or select one of the "
936 "TransferPolicy::implicit_transfers* policies."));
941 template <
typename Derived>
944 const bool default_resident)
947 Assert(host_resident == default_resident,
949 "Unable to reset the residency flags: the host and default "
950 "memory spaces coincide, so there is only a single "
951 "allocation and both flags have to coincide as well."));
954 host_resident_ = host_resident;
955 default_resident_ = default_resident;
957 Assert(!is_pinned<HostSpace>() || is_resident<HostSpace>(),
959 "Unable to reset the residency flags: the selected transfer "
960 "policy pins the host memory space and requires the data to "
961 "remain resident on it."));
963 Assert(!is_pinned<DefaultSpace>() || is_resident<DefaultSpace>(),
965 "Unable to reset the residency flags: the selected transfer "
966 "policy pins the default memory space and requires the data "
967 "to remain resident on it."));
971 template <
typename Derived>
972 template <
typename MemorySpace>
973 inline bool &MirroredStorage<Derived>::residency_flag()
const
975 if constexpr (std::is_same_v<MemorySpace, HostSpace>)
976 return host_resident_;
978 return default_resident_;
982 template <
typename Derived>
983 inline Derived &MirroredStorage<Derived>::derived()
985 return static_cast<Derived &
>(*this);
989 template <
typename Derived>
990 inline const Derived &MirroredStorage<Derived>::derived()
const
992 return static_cast<const Derived &
>(*this);
996 template <
typename T>
997 template <
typename InitializedMemorySpace>
1000 InitializedMemorySpace)
1004 initialize_storage<InitializedMemorySpace>();
1011 template <
typename T>
1012 template <
typename InitializedMemorySpace>
1014 const std::size_t
size,
1016 InitializedMemorySpace)
1024 template <
typename T>
1025 template <
typename InitializedMemorySpace>
1028 InitializedMemorySpace)
1039 initialize_storage<InitializedMemorySpace>();
1046 template <
typename T>
1054 template <
typename T>
1055 template <
typename InitializedMemorySpace>
1056 void Mirrored<T>::initialize_storage()
1058 static_assert(std::is_same_v<InitializedMemorySpace, HostSpace> ||
1059 std::is_same_v<InitializedMemorySpace, DefaultSpace>,
1060 "Unexpected memory space");
1067 !std::is_same_v<InitializedMemorySpace, HostSpace>) {
1069 deallocate_storage<HostSpace>();
1070 allocate_storage<DefaultSpace>();
1076 deallocate_storage<DefaultSpace>();
1077 allocate_storage<HostSpace>();
1084 !have_separate_memory_spaces);
1089 template <
typename T>
1090 template <
typename MemorySpace>
1093 this->
template prepare_write_access<MemorySpace>();
1095 return storage<MemorySpace>().data();
1099 template <
typename T>
1100 template <
typename MemorySpace>
1103 this->
template prepare_read_access<MemorySpace>();
1105 return storage<MemorySpace>().data();
1109 template <
typename T>
1110 template <
typename MemorySpace>
1111 inline auto Mirrored<T>::storage() const -> KokkosView<MemorySpace> &
1113 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1114 std::is_same_v<MemorySpace, DefaultSpace>,
1115 "Unexpected memory space");
1122 !std::is_same_v<MemorySpace, HostSpace>)
1129 template <
typename T>
1130 template <
typename MemorySpace>
1131 inline void Mirrored<T>::allocate_storage()
const
1134 storage<MemorySpace>() = KokkosView<MemorySpace>(label_, size_);
1136 storage<MemorySpace>() = KokkosView<MemorySpace>(label_);
1140 template <
typename T>
1141 template <
typename To,
typename From>
1142 inline void Mirrored<T>::deep_copy_storage()
const
1144 Kokkos::deep_copy( storage<To>(), storage<From>());
1148 template <
typename T>
1149 template <
typename MemorySpace>
1150 inline void Mirrored<T>::deallocate_storage()
1152 storage<MemorySpace>() = KokkosView<MemorySpace>();
void set_transfer_policy(const TransferPolicy transfer_policy)
MirroredStorage()=default
void copy_to_memory_space() const
void prepare_write_access()
void reset_residency(const bool host_resident, const bool default_resident)
TransferPolicy transfer_policy() const
void prepare_read_access() const
void move_to_memory_space()
static constexpr bool is_array
std::remove_pointer_t< T > value_type
Mirrored(const std::string &label="mirrored array", const std::size_t size=0, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers, InitializedMemorySpace={})
Mirrored(const std::string &label="mirrored object", const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers, InitializedMemorySpace={})
void reinit(const std::size_t size, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers, InitializedMemorySpace={})
DEAL_II_HOST_DEVICE_ALWAYS_INLINE const auto & view() const
SelectView(const Object &object)
auto make_select_view(const Object &object)
std::conditional_t< std::is_same_v< MemorySpace, dealii::MemorySpace::Host >, dealii::MemorySpace::Default, dealii::MemorySpace::Host > other_space_t
constexpr unsigned int warp_size
std::conditional_t< have_separate_memory_spaces, dealii::MemorySpace::Default, dealii::MemorySpace::Host > selected_memory_space_t
constexpr bool performs_implicit_transfers(const TransferPolicy policy)
constexpr bool have_separate_memory_spaces
@ implicit_transfers_default_resident
@ implicit_transfers_host_resident