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>,
654 template <
typename T>
655 static auto create_view(
const Object &
object)
657 if constexpr (std::is_same_v<MemorySpace, dealii::MemorySpace::Host>)
658 return object.
template view<dim, T>();
660 return object.template view<dim, T, MemorySpace>();
664 decltype(create_view<Number>(std::declval<const Object &>()));
666 decltype(create_view<SimdNumber>(std::declval<const Object &>()));
670 : scalar_view_(create_view<Number>(object))
671 , simd_view_(create_view<SimdNumber>(object))
679 template <
typename T>
680 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
const auto &
view()
const
682 if constexpr (std::is_same_v<T, typename get_value_type<T>::type>)
689 ScalarView scalar_view_;
699 template <
int dim,
typename Number,
typename MemorySpace,
typename Object>
714 template <
typename Derived>
715 template <
typename MemorySpace>
718 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
719 std::is_same_v<MemorySpace, DefaultSpace>,
720 "Unexpected memory space");
723 Assert(host_resident_ == default_resident_,
725 "Internal error: the host and default memory spaces coincide "
726 "but the two residency flags do not. There is only a single "
727 "allocation, so the object has to be resident on both memory "
728 "spaces, or on neither of them."));
729 return host_resident_ || default_resident_;
732 return residency_flag<MemorySpace>();
736 template <
typename Derived>
737 template <
typename MemorySpace>
740 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
741 std::is_same_v<MemorySpace, DefaultSpace>,
742 "Unexpected memory space");
748 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
749 return transfer_policy_ ==
753 return transfer_policy_ ==
759 template <
typename Derived>
760 template <
typename MemorySpace>
763 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
764 std::is_same_v<MemorySpace, DefaultSpace>,
765 "Unexpected memory space");
772 Assert(host_resident_ && default_resident_,
774 "Unable to copy to the chosen memory space: the host and "
775 "default memory spaces coincide but the object is not "
776 "resident on them. The object has not been properly "
781 Assert(!is_pinned<MemorySpace>() || is_resident<MemorySpace>(),
783 "Unable to copy to the chosen memory space: the selected "
784 "transfer policy pins the chosen memory space but the object "
785 "is not resident on it. The object has not been properly "
788 if (is_resident<MemorySpace>())
791 using OtherSpace = other_space_t<MemorySpace>;
792 Assert(is_resident<OtherSpace>(),
794 "Unable to copy to the chosen memory space: the object has "
795 "not been properly initialized."));
797 derived().template allocate_storage<MemorySpace>();
798 derived().template deep_copy_storage<MemorySpace, OtherSpace>();
799 residency_flag<MemorySpace>() =
true;
803 template <
typename Derived>
804 template <
typename MemorySpace>
807 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
808 std::is_same_v<MemorySpace, DefaultSpace>,
809 "Unexpected memory space");
817 Assert(host_resident_ && default_resident_,
819 "Unable to move to the chosen memory space: the host and "
820 "default memory spaces coincide but the object is not "
821 "resident on them. The object has not been properly "
826 Assert(!is_pinned<MemorySpace>() || is_resident<MemorySpace>(),
828 "Unable to move to the chosen memory space: the selected "
829 "transfer policy pins the chosen memory space but the object "
830 "is not resident on it. The object has not been properly "
833 using OtherSpace = other_space_t<MemorySpace>;
835 Assert(!is_pinned<OtherSpace>(),
837 "Unable to move to the chosen memory space: the selected "
838 "transfer policy requires the data to remain resident on "
839 "the other memory space."));
841 if (!is_resident<MemorySpace>()) {
842 Assert(is_resident<OtherSpace>(),
844 "Unable to move to the chosen memory space: the object has "
845 "not been properly initialized."));
847 derived().template allocate_storage<MemorySpace>();
848 derived().template deep_copy_storage<MemorySpace, OtherSpace>();
849 residency_flag<MemorySpace>() =
true;
852 if (residency_flag<OtherSpace>()) {
853 derived().template deallocate_storage<OtherSpace>();
854 residency_flag<OtherSpace>() =
false;
859 template <
typename Derived>
862 return transfer_policy_;
866 template <
typename Derived>
872 Assert(!is_pinned<HostSpace>() || is_resident<HostSpace>(),
874 "Unable to select the given transfer policy: the policy pins "
875 "the host memory space but the object is not resident on it. "
876 "Transfer the data to the pinned memory space before selecting "
877 "the transfer policy."));
879 Assert(!is_pinned<DefaultSpace>() || is_resident<DefaultSpace>(),
881 "Unable to select the given transfer policy: the policy pins "
882 "the default memory space but the object is not resident on "
883 "it. Transfer the data to the pinned memory space before "
884 "selecting the transfer policy."));
888 template <
typename Derived>
889 template <
typename MemorySpace>
893 copy_to_memory_space<MemorySpace>();
896 Assert(is_resident<MemorySpace>(),
898 "The chosen memory space is not resident. Either call "
899 "copy_to_memory_space() / move_to_memory_space() prior to "
900 "requesting a view, or select one of the "
901 "TransferPolicy::implicit_transfers* policies."));
906 template <
typename Derived>
907 template <
typename MemorySpace>
911 Assert(!
is_pinned<other_space_t<MemorySpace>>(),
913 "Unable to request a writable view on the chosen memory "
914 "space: the selected transfer policy requires the data to "
915 "remain resident on the other memory space."));
917 move_to_memory_space<MemorySpace>();
920 Assert(is_resident<MemorySpace>(),
922 "The chosen memory space is not resident. Either call "
923 "copy_to_memory_space() / move_to_memory_space() prior to "
924 "requesting a view, or select one of the "
925 "TransferPolicy::implicit_transfers* policies."));
930 template <
typename Derived>
933 const bool default_resident)
936 Assert(host_resident == default_resident,
938 "Unable to reset the residency flags: the host and default "
939 "memory spaces coincide, so there is only a single "
940 "allocation and both flags have to coincide as well."));
943 host_resident_ = host_resident;
944 default_resident_ = default_resident;
946 Assert(!is_pinned<HostSpace>() || is_resident<HostSpace>(),
948 "Unable to reset the residency flags: the selected transfer "
949 "policy pins the host memory space and requires the data to "
950 "remain resident on it."));
952 Assert(!is_pinned<DefaultSpace>() || is_resident<DefaultSpace>(),
954 "Unable to reset the residency flags: the selected transfer "
955 "policy pins the default memory space and requires the data "
956 "to remain resident on it."));
960 template <
typename Derived>
961 template <
typename MemorySpace>
962 inline bool &MirroredStorage<Derived>::residency_flag()
const
964 if constexpr (std::is_same_v<MemorySpace, HostSpace>)
965 return host_resident_;
967 return default_resident_;
971 template <
typename Derived>
972 inline Derived &MirroredStorage<Derived>::derived()
974 return static_cast<Derived &
>(*this);
978 template <
typename Derived>
979 inline const Derived &MirroredStorage<Derived>::derived()
const
981 return static_cast<const Derived &
>(*this);
985 template <
typename T>
986 template <
typename InitializedMemorySpace>
989 InitializedMemorySpace)
993 initialize_storage<InitializedMemorySpace>();
1000 template <
typename T>
1001 template <
typename InitializedMemorySpace>
1003 const std::size_t
size,
1005 InitializedMemorySpace)
1013 template <
typename T>
1014 template <
typename InitializedMemorySpace>
1017 InitializedMemorySpace)
1028 initialize_storage<InitializedMemorySpace>();
1035 template <
typename T>
1043 template <
typename T>
1044 template <
typename InitializedMemorySpace>
1045 void Mirrored<T>::initialize_storage()
1047 static_assert(std::is_same_v<InitializedMemorySpace, HostSpace> ||
1048 std::is_same_v<InitializedMemorySpace, DefaultSpace>,
1049 "Unexpected memory space");
1056 !std::is_same_v<InitializedMemorySpace, HostSpace>) {
1058 deallocate_storage<HostSpace>();
1059 allocate_storage<DefaultSpace>();
1065 deallocate_storage<DefaultSpace>();
1066 allocate_storage<HostSpace>();
1073 !have_separate_memory_spaces);
1078 template <
typename T>
1079 template <
typename MemorySpace>
1082 this->
template prepare_write_access<MemorySpace>();
1084 return storage<MemorySpace>().data();
1088 template <
typename T>
1089 template <
typename MemorySpace>
1092 this->
template prepare_read_access<MemorySpace>();
1094 return storage<MemorySpace>().data();
1098 template <
typename T>
1099 template <
typename MemorySpace>
1100 inline auto Mirrored<T>::storage() const -> KokkosView<MemorySpace> &
1102 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1103 std::is_same_v<MemorySpace, DefaultSpace>,
1104 "Unexpected memory space");
1111 !std::is_same_v<MemorySpace, HostSpace>)
1118 template <
typename T>
1119 template <
typename MemorySpace>
1120 inline void Mirrored<T>::allocate_storage()
const
1123 storage<MemorySpace>() = KokkosView<MemorySpace>(label_, size_);
1125 storage<MemorySpace>() = KokkosView<MemorySpace>(label_);
1129 template <
typename T>
1130 template <
typename To,
typename From>
1131 inline void Mirrored<T>::deep_copy_storage()
const
1133 Kokkos::deep_copy( storage<To>(), storage<From>());
1137 template <
typename T>
1138 template <
typename MemorySpace>
1139 inline void Mirrored<T>::deallocate_storage()
1141 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