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>
239 template <
typename ForwardIterator>
355 const unsigned int root_process);
443 template <
class Archive>
445 save(Archive &ar,
const unsigned int version)
const;
452 template <
class Archive>
454 load(Archive &ar,
const unsigned int version);
462 template <
class Archive>
464 serialize(Archive &archive,
const unsigned int version);
468 BOOST_SERIALIZATION_SPLIT_MEMBER()
478 "Changing the vector after a call to "
479 "replicate_across_communicator() is not allowed.");
488 const size_t new_size,
489 const size_t new_allocated_size);
592#ifdef DEAL_II_WITH_MPI
601 const bool is_shmem_root,
602 T *aligned_shmem_pointer,
604 MPI_Win shmem_window);
646#ifdef DEAL_II_WITH_MPI
746 template <
typename T>
751 160000 /
sizeof(T) + 1;
764 const T *
const source_end,
765 T *
const destination)
770 Assert(source_end == source_begin || destination !=
nullptr,
772 const std::size_t size = source_end - source_begin;
785 const std::size_t end)
const override
794 if (std::is_trivial_v<T> ==
true)
796 static_cast<const void *
>(
source_ + begin),
797 (end - begin) *
sizeof(T));
799 for (std::size_t i = begin; i < end; ++i)
815 template <
typename T>
820 160000 /
sizeof(T) + 1;
834 T *
const destination)
839 Assert(source_end == source_begin || destination !=
nullptr,
841 const std::size_t size = source_end - source_begin;
854 const std::size_t end)
const override
862 if (std::is_trivial_v<T> ==
true)
864 static_cast<void *
>(
source_ + begin),
865 (end - begin) *
sizeof(T));
869 for (std::size_t i = begin; i < end; ++i)
896 template <
typename T,
bool initialize_memory>
900 160000 /
sizeof(T) + 1;
909 T *
const destination)
921 if (std::is_trivial_v<T> ==
true &&
922 std::is_same_v<T, long double> ==
false)
924 const unsigned char zero[
sizeof(T)] = {};
928 if (std::memcmp(zero,
929 static_cast<const void *
>(&element),
944 const std::size_t end)
const override
953 (end - begin) *
sizeof(T));
957 std::bool_constant<initialize_memory>());
968 const std::size_t end,
969 std::bool_constant<false>)
const
971 for (std::size_t i = begin; i < end; ++i)
978 const std::size_t end,
979 std::bool_constant<true>)
const
981 for (std::size_t i = begin; i < end; ++i)
1000 template <
typename T,
bool initialize_memory>
1005 160000 /
sizeof(T) + 1;
1030 const std::size_t end)
const override
1036 if (std::is_trivial_v<T> ==
true)
1039 (end - begin) *
sizeof(T));
1043 std::bool_constant<initialize_memory>());
1052 const std::size_t end,
1053 std::bool_constant<false>)
const
1055 for (std::size_t i = begin; i < end; ++i)
1062 const std::size_t end,
1063 std::bool_constant<true>)
const
1065 for (std::size_t i = begin; i < end; ++i)
1077template <
typename T>
1079 : deleter_action_object(nullptr)
1080 , owning_aligned_vector(owning_object)
1084# ifdef DEAL_II_WITH_MPI
1086template <
typename T>
1088 const bool is_shmem_root,
1089 T *aligned_shmem_pointer,
1091 MPI_Win shmem_window)
1092 : deleter_action_object(
1093 std::make_unique<MPISharedMemDeleterAction>(is_shmem_root,
1094 aligned_shmem_pointer,
1095 shmem_group_communicator,
1097 , owning_aligned_vector(owning_object)
1102template <
typename T>
1108 if (deleter_action_object ==
nullptr)
1112 Assert(owning_aligned_vector->used_elements_end !=
nullptr,
1115 if (std::is_trivial_v<T> ==
false)
1116 for (T *p = owning_aligned_vector->used_elements_end - 1; p >= ptr;
1125 deleter_action_object->delete_array(owning_aligned_vector, ptr);
1130template <
typename T>
1135 owning_aligned_vector = new_aligned_vector_ptr;
1139# ifdef DEAL_II_WITH_MPI
1141template <
typename T>
1144 T *aligned_shmem_pointer,
1146 MPI_Win shmem_window)
1147 : is_shmem_root(is_shmem_root)
1148 , aligned_shmem_pointer(aligned_shmem_pointer)
1149 , shmem_group_communicator(shmem_group_communicator)
1150 , shmem_window(shmem_window)
1155template <
typename T>
1172 if (std::is_trivial_v<T> ==
false)
1177 ierr = MPI_Win_free(&shmem_window);
1188 : elements(nullptr, Deleter(this))
1189 , used_elements_end(nullptr)
1190 , allocated_elements_end(nullptr)
1192 , replicated_across_communicator(false)
1200 : elements(nullptr, Deleter(this))
1201 , used_elements_end(nullptr)
1202 , allocated_elements_end(nullptr)
1204 , replicated_across_communicator(false)
1215 : elements(nullptr, Deleter(this))
1216 , used_elements_end(nullptr)
1217 , allocated_elements_end(nullptr)
1219 , replicated_across_communicator(false)
1223 reserve(vec.
size());
1224 used_elements_end = allocated_elements_end;
1237 *
this = std::move(vec);
1260 used_elements_end = elements.get() + new_size;
1279 elements = std::move(vec.
elements);
1280 elements.get_deleter().reset_owning_object(
this);
1298 const size_type old_size = size();
1302 else if (new_size == old_size)
1305 else if (new_size < old_size)
1310 if (std::is_trivial_v<T> ==
false)
1311 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1313 used_elements_end = elements.get() + new_size;
1319 used_elements_end = elements.get() + new_size;
1323 if (std::is_trivial_v<T> ==
false)
1325 new_size - old_size, elements.get() + old_size);
1335 const size_type old_size = size();
1339 else if (new_size == old_size)
1342 else if (new_size < old_size)
1347 if (std::is_trivial_v<T> ==
false)
1348 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1350 used_elements_end = elements.get() + new_size;
1356 used_elements_end = elements.get() + new_size;
1360 new_size - old_size, elements.get() + old_size);
1370 const size_type old_size = size();
1374 else if (new_size == old_size)
1377 else if (new_size < old_size)
1382 if (std::is_trivial_v<T> ==
false)
1383 for (T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1385 used_elements_end = elements.get() + new_size;
1391 used_elements_end = elements.get() + new_size;
1395 new_size - old_size, init, elements.get() + old_size);
1404 const size_t new_size,
1405 const size_t new_allocated_size)
1412 new_size *
sizeof(T));
1419 Deleter deleter(
this);
1422 if (new_allocated_size > 0)
1424 elements.get() + old_size,
1436 elements =
decltype(elements)(new_data_ptr, std::move(deleter));
1437 used_elements_end = elements.get() + old_size;
1438 allocated_elements_end = elements.get() + new_size;
1447 const size_type old_size = used_elements_end - elements.get();
1448 const size_type old_allocated_size = allocated_elements_end - elements.get();
1449 if (new_allocated_size > old_allocated_size)
1454 const size_type new_size =
1455 std::max(new_allocated_size, 2 * old_allocated_size);
1457 allocate_and_move(old_size, new_size, new_allocated_size);
1459 else if (new_allocated_size == 0)
1473 Assert(replicated_across_communicator ==
false,
1474 ExcAlignedVectorChangeAfterReplication());
1476 const size_type used_size = used_elements_end - elements.get();
1477 const size_type allocated_size = allocated_elements_end - elements.get();
1478 if (allocated_size > used_size)
1479 allocate_and_move(used_size, used_size, used_size);
1496 used_elements_end =
nullptr;
1497 allocated_elements_end =
nullptr;
1507 if (used_elements_end == allocated_elements_end)
1508 reserve(
std::max(2 * capacity(),
static_cast<size_type
>(16)));
1509 if (std::is_trivial_v<T> ==
false)
1510 new (used_elements_end++) T(in_data);
1512 *used_elements_end++ = in_data;
1522 T *field = used_elements_end - 1;
1533 const T *field = used_elements_end - 1;
1540template <
typename ForwardIterator>
1544 const size_type old_size = size();
1545 reserve(old_size + (end - begin));
1548 if (std::is_trivial_v<T> ==
false)
1549 new (used_elements_end) T;
1550 *used_elements_end = *
begin;
1580 const unsigned int root_process)
1582# ifdef DEAL_II_WITH_MPI
1588 const size_type new_size =
1603 used_elements_end =
nullptr;
1604 allocated_elements_end =
nullptr;
1628 MPI_Comm shmem_group_communicator_temp;
1629 int ierr = MPI_Comm_split_type(communicator,
1630 MPI_COMM_TYPE_SHARED,
1633 &shmem_group_communicator_temp);
1638 ierr = MPI_Comm_split(shmem_group_communicator_temp,
1641 &shmem_group_communicator);
1652 const bool is_shmem_root =
1686 const int ierr = MPI_Comm_split(communicator,
1688 (is_shmem_root ? 0 : 1),
1690 &shmem_roots_communicator);
1699 const unsigned int shmem_roots_root_rank = 0;
1700 const bool is_shmem_roots_root =
1702 shmem_roots_communicator) == shmem_roots_root_rank));
1709 if (std::is_trivial_v<T>)
1718 const size_type new_size =
1721 shmem_roots_root_rank);
1722 if (is_shmem_roots_root ==
false)
1726 int ierr = MPI_Bcast(elements.get(),
1727 sizeof(T) * new_size,
1729 shmem_roots_root_rank,
1730 shmem_roots_communicator);
1747 shmem_roots_root_rank);
1751 shmem_roots_root_rank);
1787 MPI_Win shmem_window;
1789 const MPI_Aint align_by = 64;
1790 const MPI_Aint alloc_size =
1792 (size() *
sizeof(T) + (align_by - 1)),
1799 ierr = MPI_Info_create(&mpi_info);
1801 ierr = MPI_Info_set(mpi_info,
1802 "mpi_minimum_memory_alignment",
1803 std::to_string(align_by).c_str());
1805 ierr = MPI_Win_allocate_shared((is_shmem_root ? alloc_size : 0),
1808 shmem_group_communicator,
1813 ierr = MPI_Info_free(&mpi_info);
1836 if (is_shmem_root ==
false)
1839 MPI_Aint alloc_size;
1840 const int ierr = MPI_Win_shared_query(
1841 shmem_window, MPI_PROC_NULL, &alloc_size, &disp_unit, &base_ptr);
1861 std::size_t available_space = alloc_size;
1862 void *base_ptr_backup = base_ptr;
1863 T *aligned_shmem_pointer =
static_cast<T *
>(
1864 std::align(align_by, new_size *
sizeof(T), base_ptr, available_space));
1894 aligned_shmem_pointer =
static_cast<T *
>(base_ptr_backup);
1902 if (std::is_trivial_v<T> ==
true)
1903 std::memcpy(aligned_shmem_pointer, elements.get(),
sizeof(T) * size());
1905 for (std::size_t i = 0; i < size(); ++i)
1906 new (&aligned_shmem_pointer[i]) T(std::move(elements[i]));
1911 const int ierr = MPI_Barrier(shmem_group_communicator);
1931 elements =
decltype(elements)(aligned_shmem_pointer,
1934 aligned_shmem_pointer,
1935 shmem_group_communicator,
1942 used_elements_end = elements.get() + new_size;
1943 allocated_elements_end = used_elements_end;
1949 replicated_across_communicator =
true;
1952 std::accumulate(packed_data.begin(), packed_data.end(),
int(0));
1972 elements.get_deleter().reset_owning_object(
this);
1973 vec.
elements.get_deleter().reset_owning_object(&vec);
1986 return used_elements_end == elements.get();
1995 return used_elements_end - elements.get();
2004 return allocated_elements_end - elements.get();
2014 return elements[
index];
2024 return elements[
index];
2029template <
typename T>
2033 return elements.get();
2038template <
typename T>
2042 return elements.get();
2051 return elements.get();
2060 return used_elements_end;
2069 return elements.get();
2078 return used_elements_end;
2084template <
class Archive>
2088 size_type vec_size = size();
2091 ar &boost::serialization::make_array(elements.get(), vec_size);
2097template <
class Archive>
2101 size_type vec_size = 0;
2107 ar &boost::serialization::make_array(elements.get(), vec_size);
2108 used_elements_end = elements.get() + vec_size;
2118 size_type memory =
sizeof(*this);
2119 for (
const T *t = elements.get(); t != used_elements_end; ++t)
2121 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
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)
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
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
AlignedVectorCopyConstruct(const T *const source_begin, const T *const source_end, T *const destination)
static const std::size_t minimum_parallel_grain_size
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)
static const std::size_t minimum_parallel_grain_size
AlignedVectorMoveConstruct(T *const source_begin, T *const source_end, T *const destination)
virtual void apply_to_subrange(const std::size_t begin, const std::size_t end) const override
#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 & ExcAlignedVectorChangeAfterReplication()
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)
std::enable_if_t< is_mpi_type< T >==false, T > broadcast(const MPI_Comm comm, const T &object_to_send, const unsigned int root_process=0)
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)
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