17#ifndef dealii_aligned_vector_h
18#define dealii_aligned_vector_h
30#include <boost/version.hpp>
31#if BOOST_VERSION >= 106400
32# include <boost/serialization/array_wrapper.hpp>
34# include <boost/serialization/array.hpp>
36#include <boost/serialization/split_member.hpp>
234 template <
typename ForwardIterator>
350 const unsigned int root_process);
436 template <
class Archive>
438 save(Archive &ar,
const unsigned int version)
const;
445 template <
class Archive>
447 load(Archive &ar,
const unsigned int version);
455 template <
class Archive>
457 serialize(Archive &archive,
const unsigned int version);
461 BOOST_SERIALIZATION_SPLIT_MEMBER()
506 template <
typename T>
510 160000 /
sizeof(
T) + 1;
523 const T *
const source_end,
524 T *
const destination)
529 Assert(source_end == source_begin || destination !=
nullptr,
531 const std::size_t size = source_end - source_begin;
544 const std::size_t
end)
const override
553 if (std::is_trivial<T>::value ==
true)
558 for (std::size_t i =
begin; i <
end; ++i)
573 template <
typename T>
577 160000 /
sizeof(
T) + 1;
591 T *
const destination)
596 Assert(source_end == source_begin || destination !=
nullptr,
598 const std::size_t size = source_end - source_begin;
611 const std::size_t
end)
const override
619 if (std::is_trivial<T>::value ==
true)
626 for (std::size_t i =
begin; i <
end; ++i)
647 template <
typename T,
bool initialize_memory>
651 160000 /
sizeof(
T) + 1;
660 T *
const destination)
672 if (std::is_trivial<T>::value ==
true &&
673 std::is_same<T, long double>::value ==
false)
675 const unsigned char zero[
sizeof(
T)] = {};
679 if (std::memcmp(
zero,
680 static_cast<const void *
>(&element),
695 const std::size_t
end)
const override
707 begin,
end, std::integral_constant<bool, initialize_memory>());
718 const std::size_t
end,
719 std::integral_constant<bool, false>)
const
721 for (std::size_t i =
begin; i <
end; ++i)
728 const std::size_t
end,
729 std::integral_constant<bool, true>)
const
731 for (std::size_t i =
begin; i <
end; ++i)
749 template <
typename T,
bool initialize_memory>
754 160000 /
sizeof(
T) + 1;
779 const std::size_t
end)
const override
785 if (std::is_trivial<T>::value ==
true)
791 begin,
end, std::integral_constant<bool, initialize_memory>());
800 const std::size_t
end,
801 std::integral_constant<bool, false>)
const
803 for (std::size_t i =
begin; i <
end; ++i)
810 const std::size_t
end,
811 std::integral_constant<bool, true>)
const
813 for (std::size_t i =
begin; i <
end; ++i)
827 , used_elements_end(
nullptr)
828 , allocated_elements_end(
nullptr)
836 , used_elements_end(
nullptr)
837 , allocated_elements_end(
nullptr)
848 , used_elements_end(
nullptr)
849 , allocated_elements_end(
nullptr)
853 used_elements_end = allocated_elements_end;
855 vec.used_elements_end,
866 *
this = std::move(vec);
876 resize_fast(vec.used_elements_end - vec.elements.get());
878 vec.used_elements_end,
897 elements =
decltype(elements)(vec.elements.release(), [
this](
T *ptr) {
902 if (std::is_trivial<T>::value ==
false)
903 for (
T *p = this->used_elements_end - 1; p >= ptr; --p)
911 used_elements_end = vec.used_elements_end;
912 allocated_elements_end = vec.allocated_elements_end;
914 vec.used_elements_end =
nullptr;
915 vec.allocated_elements_end =
nullptr;
930 else if (new_size == old_size)
932 else if (new_size < old_size)
937 if (std::is_trivial<T>::value ==
false)
938 for (
T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
940 used_elements_end = elements.get() + new_size;
946 used_elements_end = elements.get() + new_size;
950 if (std::is_trivial<T>::value ==
false)
952 new_size - old_size, elements.get() + old_size);
966 else if (new_size == old_size)
968 else if (new_size < old_size)
973 if (std::is_trivial<T>::value ==
false)
974 for (
T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
976 used_elements_end = elements.get() + new_size;
982 used_elements_end = elements.get() + new_size;
986 new_size - old_size, elements.get() + old_size);
1000 else if (new_size == old_size)
1002 else if (new_size < old_size)
1007 if (std::is_trivial<T>::value ==
false)
1008 for (
T *p = used_elements_end - 1; p >= elements.get() + new_size; --p)
1010 used_elements_end = elements.get() + new_size;
1016 used_elements_end = elements.get() + new_size;
1021 elements.get() + old_size);
1031 const size_type old_size = used_elements_end - elements.get();
1032 const size_type old_allocated_size = allocated_elements_end - elements.get();
1033 if (new_allocated_size > old_allocated_size)
1039 std::max(new_allocated_size, 2 * old_allocated_size);
1045 reinterpret_cast<void **
>(&new_data_ptr), 64, new_size *
sizeof(
T));
1052 auto deleter = [
this](
T *ptr) {
1057 if (std::is_trivial<T>::value ==
false)
1058 for (
T *p = this->used_elements_end - 1; p >= ptr; --p)
1066 if (new_allocated_size > 0)
1068 elements.get() + old_size,
1079 elements =
decltype(elements)(new_data_ptr, deleter);
1080 used_elements_end = elements.get() + old_size;
1081 allocated_elements_end = elements.get() + new_size;
1083 else if (new_allocated_size == 0)
1103 used_elements_end =
nullptr;
1104 allocated_elements_end =
nullptr;
1114 if (used_elements_end == allocated_elements_end)
1116 if (std::is_trivial<T>::value ==
false)
1117 new (used_elements_end++)
T(in_data);
1119 *used_elements_end++ = in_data;
1129 T *field = used_elements_end - 1;
1140 const T *field = used_elements_end - 1;
1147template <
typename ForwardIterator>
1151 const unsigned int old_size = size();
1155 if (std::is_trivial<T>::value ==
false)
1156 new (used_elements_end)
T;
1157 *used_elements_end = *
begin;
1185 const unsigned int root_process)
1187# ifdef DEAL_II_WITH_MPI
1188# if DEAL_II_MPI_VERSION_GTE(3, 0)
1196 used_elements_end =
nullptr;
1197 allocated_elements_end =
nullptr;
1221 MPI_Comm shmem_group_communicator_temp;
1222 int ierr = MPI_Comm_split_type(communicator,
1223 MPI_COMM_TYPE_SHARED,
1226 &shmem_group_communicator_temp);
1231 ierr = MPI_Comm_split(shmem_group_communicator_temp,
1234 &shmem_group_communicator);
1243 ierr = MPI_Comm_free(&shmem_group_communicator_temp);
1245 const bool is_shmem_root =
1279 const int ierr = MPI_Comm_split(communicator,
1281 (is_shmem_root ? 0 : 1),
1283 &shmem_roots_communicator);
1292 const unsigned int shmem_roots_root_rank = 0;
1293 const bool is_shmem_roots_root =
1295 shmem_roots_communicator) == shmem_roots_root_rank));
1302 if (std::is_trivial<T>::value)
1314 shmem_roots_root_rank);
1315 if (is_shmem_roots_root ==
false)
1319 int ierr = MPI_Bcast(elements.get(),
1320 sizeof(
T) * new_size,
1322 shmem_roots_root_rank,
1323 shmem_roots_communicator);
1340 shmem_roots_root_rank);
1344 shmem_roots_root_rank);
1350 const int ierr = MPI_Comm_free(&shmem_roots_communicator);
1395 MPI_Win shmem_window;
1397 const MPI_Aint align_by = 64;
1398 const MPI_Aint alloc_size =
1400 (size() *
sizeof(
T) + (align_by - 1)),
1404 const int disp_unit = (is_shmem_root ? size() : 1);
1409 ierr = MPI_Info_create(&mpi_info);
1411 ierr = MPI_Info_set(mpi_info,
1412 "mpi_minimum_memory_alignment",
1415 ierr = MPI_Win_allocate_shared((is_shmem_root ? alloc_size : 0),
1418 shmem_group_communicator,
1423 ierr = MPI_Info_free(&mpi_info);
1448 unsigned int array_size =
1450 if (is_shmem_root ==
false)
1453 MPI_Aint alloc_size;
1454 const int ierr = MPI_Win_shared_query(
1455 shmem_window, MPI_PROC_NULL, &alloc_size, &disp_unit, &base_ptr);
1462 array_size = disp_unit;
1476 std::size_t available_space = alloc_size;
1477 void * base_ptr_backup = base_ptr;
1478 T * aligned_shmem_pointer =
static_cast<T *
>(
1479 std::align(align_by, array_size *
sizeof(
T), base_ptr, available_space));
1509 aligned_shmem_pointer =
static_cast<T *
>(base_ptr_backup);
1517 if (std::is_trivial<T>::value ==
true)
1518 std::memcpy(aligned_shmem_pointer, elements.get(),
sizeof(
T) * size());
1520 for (std::size_t i = 0; i < size(); ++i)
1521 new (&aligned_shmem_pointer[i])
T(std::move(elements[i]));
1526 MPI_Barrier(shmem_group_communicator);
1546 decltype(elements)(aligned_shmem_pointer,
1549 aligned_shmem_pointer,
1550 shmem_group_communicator,
1551 shmem_window](
T *)
mutable {
1553 for (
unsigned int i = 0; i < array_size; ++i)
1554 aligned_shmem_pointer[i].~
T();
1557 ierr = MPI_Win_free(&shmem_window);
1560 ierr = MPI_Comm_free(&shmem_group_communicator);
1568 used_elements_end = elements.get() + array_size;
1569 allocated_elements_end = used_elements_end;
1577 std::accumulate(packed_data.begin(), packed_data.end(),
int(0));
1609 T *this_element_pointer = elements.release();
1611 elements =
decltype(elements)(vec.elements.release(), [
this](
T *ptr) {
1616 if (std::is_trivial<T>::value ==
false)
1617 for (
T *p = this->used_elements_end - 1; p >= ptr; --p)
1624 vec.elements =
decltype(vec.elements)(this_element_pointer, [&vec](
T *ptr) {
1629 if (std::is_trivial<T>::value ==
false)
1630 for (
T *p = vec.used_elements_end - 1; p >= ptr; --p)
1637 std::swap(used_elements_end, vec.used_elements_end);
1638 std::swap(allocated_elements_end, vec.allocated_elements_end);
1647 return used_elements_end == elements.get();
1656 return used_elements_end - elements.get();
1665 return allocated_elements_end - elements.get();
1675 return elements[index];
1685 return elements[index];
1690template <
typename T>
1694 return elements.get();
1699template <
typename T>
1703 return elements.get();
1712 return elements.get();
1721 return used_elements_end;
1730 return elements.get();
1739 return used_elements_end;
1745template <
class Archive>
1752 ar &boost::serialization::make_array(elements.get(), vec_size);
1758template <
class Archive>
1768 ar &boost::serialization::make_array(elements.get(), vec_size);
1769 used_elements_end = elements.get() + vec_size;
1780 for (
const T *t = elements.get(); t != used_elements_end; ++t)
1782 memory +=
sizeof(
T) * (allocated_elements_end - used_elements_end);
1799 if (lhs.size() != rhs.size())
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
size_type memory_consumption() const
void resize_fast(const size_type new_size)
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 swap(AlignedVector< T > &vec)
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)
const value_type * const_pointer
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
std::unique_ptr< T[], std::function< void(T *)> > elements
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
const value_type * const_iterator
void replicate_across_communicator(const MPI_Comm &communicator, const unsigned int root_process)
void resize(const size_type new_size)
void load(Archive &ar, const unsigned int version)
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
AlignedVectorCopy(const T *const source_begin, const T *const source_end, 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::integral_constant< bool, true >) const
void default_construct_or_assign(const std::size_t begin, const std::size_t end, std::integral_constant< bool, false >) const
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
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
AlignedVectorMove(T *const source_begin, T *const source_end, T *const destination)
static const std::size_t minimum_parallel_grain_size
void copy_construct_or_assign(const std::size_t begin, const std::size_t end, std::integral_constant< bool, false >) const
void copy_construct_or_assign(const std::size_t begin, const std::size_t end, std::integral_constant< bool, true >) const
AlignedVectorSet(const std::size_t size, const T &element, 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)
std::string to_string(const T &t)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static const types::blas_int zero
types::global_dof_index size_type
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
void swap(MemorySpaceData< Number, MemorySpace > &, MemorySpaceData< Number, MemorySpace > &)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
T broadcast(const MPI_Comm &comm, const T &object_to_send, const unsigned int root_process=0)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
T min(const T &t, const MPI_Comm &mpi_communicator)
T max(const T &t, const 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)
static const unsigned int invalid_unsigned_int
::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