16#ifndef dealii_aligned_vector_h
17#define dealii_aligned_vector_h
29#include <boost/version.hpp>
30#if BOOST_VERSION >= 106400
31# include <boost/serialization/array_wrapper.hpp>
33# include <boost/serialization/array.hpp>
35#include <boost/serialization/split_member.hpp>
90 typename RandomAccessIterator,
91 typename = std::enable_if_t<std::is_convertible_v<
92 typename std::iterator_traits<RandomAccessIterator>::iterator_category,
93 std::random_access_iterator_tag>>>
254 template <
typename ForwardIterator>
267 typename RandomAccessIterator,
268 typename = std::enable_if_t<std::is_convertible_v<
269 typename std::iterator_traits<RandomAccessIterator>::iterator_category,
270 std::random_access_iterator_tag>>>
273 RandomAccessIterator
begin,
274 RandomAccessIterator
end);
388 const unsigned int root_process);
476 template <
class Archive>
478 save(Archive &ar,
const unsigned int version)
const;
485 template <
class Archive>
487 load(Archive &ar,
const unsigned int version);
495 template <
class Archive>
497 serialize(Archive &archive,
const unsigned int version);
501 BOOST_SERIALIZATION_SPLIT_MEMBER()
511 "Changing the vector after a call to "
512 "replicate_across_communicator() is not allowed.");
521 const size_t new_size,
522 const size_t new_allocated_size);
625#ifdef DEAL_II_WITH_MPI
634 const bool is_shmem_root,
635 T *aligned_shmem_pointer,
637 MPI_Win shmem_window);
679#ifdef DEAL_II_WITH_MPI
779 template <
typename RandomAccessIterator,
typename T>
784 160000 /
sizeof(T) + 1;
797 RandomAccessIterator source_end,
798 T *
const destination)
803 Assert(source_end == source_begin || destination !=
nullptr,
805 const std::size_t
size = source_end - source_begin;
818 const std::size_t end)
const override
824 if constexpr (std::is_trivial_v<T> ==
true &&
825 (std::is_same_v<T *, RandomAccessIterator> ||
826 std::is_same_v<const T *, RandomAccessIterator>) ==
true)
829 (end - begin) *
sizeof(T));
831 for (std::size_t i = begin; i < end; ++i)
847 template <
typename RandomAccessIterator,
typename T>
852 160000 /
sizeof(T) + 1;
865 RandomAccessIterator source_end,
866 T *
const destination)
871 Assert(source_end == source_begin || destination !=
nullptr,
873 const std::size_t
size = source_end - source_begin;
886 const std::size_t end)
const override
892 if constexpr (std::is_trivial_v<T> ==
true &&
893 (std::is_same_v<T *, RandomAccessIterator> ||
894 std::is_same_v<const T *, RandomAccessIterator>) ==
true)
897 (end - begin) *
sizeof(T));
901 for (std::size_t i = begin; i < end; ++i)
928 template <
typename T,
bool initialize_memory>
932 160000 /
sizeof(T) + 1;
941 T *
const destination)
953 if constexpr (std::is_trivial_v<T> ==
true &&
954 std::is_same_v<T, long double> ==
false)
956 const unsigned char zero[
sizeof(T)] = {};
957 if (std::memcmp(zero, &element,
sizeof(T)) == 0)
971 const std::size_t end)
const override
974 if constexpr (std::is_trivial_v<T> ==
true)
977 std::memset(
destination_ + begin, 0, (end - begin) *
sizeof(T));
983 std::bool_constant<initialize_memory>());
994 const std::size_t end,
995 std::bool_constant<false>)
const
997 for (std::size_t i = begin; i < end; ++i)
1004 const std::size_t end,
1005 std::bool_constant<true>)
const
1007 for (std::size_t i = begin; i < end; ++i)
1026 template <
typename T,
bool initialize_memory>
1031 160000 /
sizeof(T) + 1;
1056 const std::size_t end)
const override
1059 if constexpr (std::is_trivial_v<T> ==
true)
1060 std::memset(
destination_ + begin, 0, (end - begin) *
sizeof(T));
1064 std::bool_constant<initialize_memory>());
1073 const std::size_t end,
1074 std::bool_constant<false>)
const
1076 for (std::size_t i = begin; i < end; ++i)
1083 const std::size_t end,
1084 std::bool_constant<true>)
const
1086 for (std::size_t i = begin; i < end; ++i)
1098template <
typename T>
1100 : deleter_action_object(nullptr)
1101 , owning_aligned_vector(owning_object)
1105# ifdef DEAL_II_WITH_MPI
1107template <
typename T>
1109 const bool is_shmem_root,
1110 T *aligned_shmem_pointer,
1112 MPI_Win shmem_window)
1113 : deleter_action_object(
1114 std::make_unique<MPISharedMemDeleterAction>(is_shmem_root,
1115 aligned_shmem_pointer,
1116 shmem_group_communicator,
1118 , owning_aligned_vector(owning_object)
1123template <
typename T>
1129 if (deleter_action_object ==
nullptr)
1133 Assert(owning_aligned_vector->used_elements_end !=
nullptr,
1136 if (std::is_trivial_v<T> ==
false)
1137 for (T *p = owning_aligned_vector->used_elements_end - 1; p >= ptr;
1146 deleter_action_object->delete_array(owning_aligned_vector, ptr);
1151template <
typename T>
1156 owning_aligned_vector = new_aligned_vector_ptr;
1160# ifdef DEAL_II_WITH_MPI
1162template <
typename T>
1165 T *aligned_shmem_pointer,
1167 MPI_Win shmem_window)
1168 : is_shmem_root(is_shmem_root)
1169 , aligned_shmem_pointer(aligned_shmem_pointer)
1170 , shmem_group_communicator(shmem_group_communicator)
1171 , shmem_window(shmem_window)
1176template <
typename T>
1193 if (std::is_trivial_v<T> ==
false)
1198 ierr = MPI_Win_free(&shmem_window);
1209 : elements(nullptr, Deleter(this))
1210 , used_elements_end(nullptr)
1211 , allocated_elements_end(nullptr)
1213 , replicated_across_communicator(false)
1220template <
typename RandomAccessIterator,
typename>
1222 RandomAccessIterator end)
1223 : elements(nullptr, Deleter(this))
1224 , used_elements_end(nullptr)
1225 , allocated_elements_end(nullptr)
1226 , replicated_across_communicator(false)
1228 allocate_and_move(0u, end - begin, end - begin);
1229 used_elements_end = allocated_elements_end;
1238 : elements(nullptr, Deleter(this))
1239 , used_elements_end(nullptr)
1240 , allocated_elements_end(nullptr)
1242 , replicated_across_communicator(false)
1253 : elements(nullptr, Deleter(this))
1254 , used_elements_end(nullptr)
1255 , allocated_elements_end(nullptr)
1257 , replicated_across_communicator(false)
1261 reserve(vec.
size());
1262 used_elements_end = allocated_elements_end;
1275 *
this = std::move(vec);
1298 used_elements_end = elements.get() + new_size;
1317 elements = std::move(vec.
elements);
1318 elements.get_deleter().reset_owning_object(
this);
1340 else if (new_size == old_size)
1343 else if (new_size < old_size)
1348 if (std::is_trivial_v<T> ==
false)
1349 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1351 used_elements_end = elements.get() + new_size;
1357 used_elements_end = elements.get() + new_size;
1361 if (std::is_trivial_v<T> ==
false)
1363 new_size - old_size, elements.get() + old_size);
1377 else if (new_size == old_size)
1380 else if (new_size < old_size)
1385 if (std::is_trivial_v<T> ==
false)
1386 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1388 used_elements_end = elements.get() + new_size;
1394 used_elements_end = elements.get() + new_size;
1398 new_size - old_size, elements.get() + old_size);
1412 else if (new_size == old_size)
1415 else if (new_size < old_size)
1420 if (std::is_trivial_v<T> ==
false)
1421 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1423 used_elements_end = elements.get() + new_size;
1429 used_elements_end = elements.get() + new_size;
1433 new_size - old_size, init, elements.get() + old_size);
1442 const size_t new_size,
1443 const size_t new_allocated_size)
1450 new_size *
sizeof(T));
1457 Deleter deleter(
this);
1460 if (new_allocated_size > 0)
1462 elements.get(), elements.get() + old_size, new_data_ptr);
1473 elements =
decltype(elements)(new_data_ptr, std::move(deleter));
1474 used_elements_end = elements.get() + old_size;
1475 allocated_elements_end = elements.get() + new_size;
1484 const size_type old_size = used_elements_end - elements.get();
1485 const size_type old_allocated_size = allocated_elements_end - elements.get();
1486 if (new_allocated_size > old_allocated_size)
1492 std::max(new_allocated_size, 2 * old_allocated_size);
1494 allocate_and_move(old_size, new_size, new_allocated_size);
1496 else if (new_allocated_size == 0)
1510 Assert(replicated_across_communicator ==
false,
1511 ExcAlignedVectorChangeAfterReplication());
1513 const size_type used_size = used_elements_end - elements.get();
1514 const size_type allocated_size = allocated_elements_end - elements.get();
1515 if (allocated_size > used_size)
1516 allocate_and_move(used_size, used_size, used_size);
1533 used_elements_end =
nullptr;
1534 allocated_elements_end =
nullptr;
1544 if (used_elements_end == allocated_elements_end)
1546 if (std::is_trivial_v<T> ==
false)
1547 new (used_elements_end++) T(in_data);
1549 *used_elements_end++ = in_data;
1559 T *field = used_elements_end - 1;
1570 const T *field = used_elements_end - 1;
1577template <
typename ForwardIterator>
1582 reserve(old_size + (end - begin));
1585 if (std::is_trivial_v<T> ==
false)
1586 new (used_elements_end) T;
1587 *used_elements_end = *
begin;
1594template <
typename RandomAccessIterator,
typename>
1597 RandomAccessIterator begin,
1598 RandomAccessIterator end)
1600 Assert(replicated_across_communicator ==
false,
1601 ExcAlignedVectorChangeAfterReplication());
1602 Assert(this->begin() <= position && position <= this->
end(),
1603 ExcMessage(
"The position iterator is not valid."));
1604 const auto offset = position - this->begin();
1608 const size_type new_size = old_size + range_size;
1609 if (range_size != 0)
1614 T *new_data_ptr =
nullptr;
1616 reinterpret_cast<void **
>(&new_data_ptr), 64, new_size *
sizeof(T));
1622 elements.get(), elements.get() + offset, new_data_ptr);
1624 temporary.begin(), temporary.end(), new_data_ptr + offset);
1626 elements.get() + offset,
1627 elements.get() + old_size,
1628 new_data_ptr + offset + range_size);
1630 Deleter deleter(
this);
1631 elements =
decltype(elements)(new_data_ptr, std::move(deleter));
1632 used_elements_end = elements.get() + new_size;
1633 allocated_elements_end = elements.get() + new_size;
1635 return this->begin() + offset;
1664 const unsigned int root_process)
1666# ifdef DEAL_II_WITH_MPI
1687 used_elements_end =
nullptr;
1688 allocated_elements_end =
nullptr;
1712 MPI_Comm shmem_group_communicator_temp;
1713 int ierr = MPI_Comm_split_type(communicator,
1714 MPI_COMM_TYPE_SHARED,
1717 &shmem_group_communicator_temp);
1722 ierr = MPI_Comm_split(shmem_group_communicator_temp,
1725 &shmem_group_communicator);
1736 const bool is_shmem_root =
1770 const int ierr = MPI_Comm_split(communicator,
1772 (is_shmem_root ? 0 : 1),
1774 &shmem_roots_communicator);
1783 const unsigned int shmem_roots_root_rank = 0;
1784 const bool is_shmem_roots_root =
1786 shmem_roots_communicator) == shmem_roots_root_rank));
1793 if (std::is_trivial_v<T>)
1805 shmem_roots_root_rank);
1806 if (is_shmem_roots_root ==
false)
1810 int ierr = MPI_Bcast(elements.get(),
1811 sizeof(T) * new_size,
1813 shmem_roots_root_rank,
1814 shmem_roots_communicator);
1831 shmem_roots_root_rank);
1835 shmem_roots_root_rank);
1871 MPI_Win shmem_window;
1873 const MPI_Aint align_by = 64;
1874 const MPI_Aint alloc_size =
1876 (
size() *
sizeof(T) + (align_by - 1)),
1883 ierr = MPI_Info_create(&mpi_info);
1885 ierr = MPI_Info_set(mpi_info,
1886 "mpi_minimum_memory_alignment",
1887 std::to_string(align_by).c_str());
1889 ierr = MPI_Win_allocate_shared((is_shmem_root ? alloc_size : 0),
1892 shmem_group_communicator,
1897 ierr = MPI_Info_free(&mpi_info);
1920 if (is_shmem_root ==
false)
1923 MPI_Aint alloc_size;
1924 const int ierr = MPI_Win_shared_query(
1925 shmem_window, MPI_PROC_NULL, &alloc_size, &disp_unit, &base_ptr);
1945 std::size_t available_space = alloc_size;
1946 void *base_ptr_backup = base_ptr;
1947 T *aligned_shmem_pointer =
static_cast<T *
>(
1948 std::align(align_by, new_size *
sizeof(T), base_ptr, available_space));
1978 aligned_shmem_pointer =
static_cast<T *
>(base_ptr_backup);
1986 if (std::is_trivial_v<T> ==
true)
1987 std::memcpy(aligned_shmem_pointer, elements.get(),
sizeof(T) *
size());
1989 for (std::size_t i = 0; i <
size(); ++i)
1990 new (&aligned_shmem_pointer[i]) T(std::move(elements[i]));
1995 const int ierr = MPI_Barrier(shmem_group_communicator);
2015 elements =
decltype(elements)(aligned_shmem_pointer,
2018 aligned_shmem_pointer,
2019 shmem_group_communicator,
2026 used_elements_end = elements.get() + new_size;
2027 allocated_elements_end = used_elements_end;
2033 replicated_across_communicator =
true;
2036 std::accumulate(packed_data.begin(), packed_data.end(),
int(0));
2056 elements.get_deleter().reset_owning_object(
this);
2057 vec.
elements.get_deleter().reset_owning_object(&vec);
2070 return used_elements_end == elements.get();
2079 return used_elements_end - elements.get();
2088 return allocated_elements_end - elements.get();
2098 return elements[
index];
2108 return elements[
index];
2113template <
typename T>
2117 return elements.get();
2122template <
typename T>
2126 return elements.get();
2135 return elements.get();
2144 return used_elements_end;
2153 return elements.get();
2162 return used_elements_end;
2168template <
class Archive>
2175 ar &boost::serialization::make_array(elements.get(), vec_size);
2181template <
class Archive>
2191 ar &boost::serialization::make_array(elements.get(), vec_size);
2192 used_elements_end = elements.get() + vec_size;
2203 for (
const T *t = elements.get(); t != used_elements_end; ++t)
2205 memory +=
sizeof(T) * (allocated_elements_end - used_elements_end);
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
virtual ~DeleterActionBase()=default
virtual void delete_array(const AlignedVector< T > *owning_aligned_vector, T *ptr)=0
MPI_Comm shmem_group_communicator
virtual void delete_array(const AlignedVector< T > *aligned_vector, T *ptr)
MPISharedMemDeleterAction(const bool is_shmem_root, T *aligned_shmem_pointer, MPI_Comm shmem_group_communicator, MPI_Win shmem_window)
T * aligned_shmem_pointer
Deleter(AlignedVector< T > *owning_object, const bool is_shmem_root, T *aligned_shmem_pointer, MPI_Comm shmem_group_communicator, MPI_Win shmem_window)
Deleter(AlignedVector< T > *owning_object)
std::unique_ptr< DeleterActionBase > deleter_action_object
void reset_owning_object(const AlignedVector< T > *new_aligned_vector_ptr)
const AlignedVector< T > * owning_aligned_vector
void replicate_across_communicator(const MPI_Comm communicator, const unsigned int root_process)
size_type memory_consumption() const
void resize_fast(const size_type new_size)
std::unique_ptr< T[], Deleter > elements
reference operator[](const size_type index)
void fill(const T &element)
const_iterator end() const
AlignedVector(AlignedVector< T > &&vec) noexcept
void reserve(const size_type new_allocated_size)
void serialize(Archive &archive, const unsigned int version)
bool operator!=(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
const_reference operator[](const size_type index) const
void resize(const size_type new_size, const T &init)
AlignedVector & operator=(AlignedVector< T > &&vec) noexcept
AlignedVector(RandomAccessIterator begin, RandomAccessIterator end)
size_type capacity() const
AlignedVector & operator=(const AlignedVector< T > &vec)
void swap(AlignedVector< T > &vec) noexcept
const value_type * const_pointer
bool replicated_across_communicator
void push_back(const T in_data)
iterator insert(const_iterator position, RandomAccessIterator begin, RandomAccessIterator end)
const_iterator begin() const
AlignedVector(const size_type size, const T &init=T())
T * allocated_elements_end
AlignedVector(const AlignedVector< T > &vec)
const_reference back() const
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
const value_type * const_iterator
void resize(const size_type new_size)
void load(Archive &ar, const unsigned int version)
void allocate_and_move(const size_t old_size, const size_t new_size, const size_t new_allocated_size)
void save(Archive &ar, const unsigned int version) const
void insert_back(ForwardIterator begin, ForwardIterator end)
const value_type & const_reference
const_pointer data() const
AlignedVectorCopyConstruct(RandomAccessIterator source_begin, RandomAccessIterator source_end, T *const destination)
RandomAccessIterator source_
static const std::size_t minimum_parallel_grain_size
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
AlignedVectorDefaultInitialize(const std::size_t size, T *const destination)
static const std::size_t minimum_parallel_grain_size
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
void default_construct_or_assign(const std::size_t begin, const std::size_t end, std::bool_constant< false >) const
void default_construct_or_assign(const std::size_t begin, const std::size_t end, std::bool_constant< true >) const
void copy_construct_or_assign(const std::size_t begin, const std::size_t end, std::bool_constant< false >) const
static const std::size_t minimum_parallel_grain_size
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
void copy_construct_or_assign(const std::size_t begin, const std::size_t end, std::bool_constant< true >) const
AlignedVectorInitialize(const std::size_t size, const T &element, T *const destination)
RandomAccessIterator source_
AlignedVectorMoveConstruct(RandomAccessIterator source_begin, RandomAccessIterator source_end, T *const destination)
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
static const std::size_t minimum_parallel_grain_size
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
#define Assert(cond, exc)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcAlignedVectorChangeAfterReplication()
std::vector< index_type > data
types::global_dof_index size_type
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
T max(const T &t, const MPI_Comm mpi_communicator)
T min(const T &t, const MPI_Comm mpi_communicator)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
void free_communicator(MPI_Comm mpi_communicator)
T broadcast(const MPI_Comm comm, const T &object_to_send, const unsigned int root_process=0)
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
void apply_parallel(const std::size_t begin, const std::size_t end, const std::size_t minimum_parallel_grain_size) const