Skip to content

Commit

Permalink
perf: No longer store capacity+allocator/memory_begin in ElementLocator
Browse files Browse the repository at this point in the history
  • Loading branch information
Tradias committed Oct 12, 2024
1 parent 5b4a056 commit 27fb2a1
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 131 deletions.
12 changes: 12 additions & 0 deletions contiguous.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="cntgs::detail::UnmanagedVector&lt;*&gt;">
<DisplayString>{{ size={size_} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>size_</Size>
<ValuePointer>data_</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ list(
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/sizeGetter.hpp"
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/tuple.hpp"
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/typeTraits.hpp"
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/unmanagedVector.hpp"
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/utility.hpp"
"${CMAKE_CURRENT_LIST_DIR}/cntgs/detail/vectorTraits.hpp")
set_target_properties(cntgs PROPERTIES CNTGS_SOURCE_FILES "${CNTGS_SOURCE_FILES}")
Expand Down
155 changes: 81 additions & 74 deletions src/cntgs/detail/elementLocator.hpp

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/cntgs/detail/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

namespace cntgs::detail
{
using Byte = std::underlying_type_t<std::byte>;
using Byte = unsigned char;

template <class Allocator, class T>
using RebindTraits = typename std::allocator_traits<Allocator>::template rebind_traits<T>;

template <std::size_t N>
struct Aligned
Expand Down
53 changes: 25 additions & 28 deletions src/cntgs/detail/parameterTraits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,20 @@ struct ParameterTraits<cntgs::AlignAs<T, Alignment>>
static constexpr AlignedSizeInMemory aligned_size_in_memory(std::size_t offset, std::size_t alignment,
std::size_t) noexcept
{
const auto [new_offset, size] = [&]
std::size_t new_offset{};
std::size_t size{};
if (alignment < ALIGNMENT)
{
const auto alignment_offset = detail::align(offset, alignment) + ALIGNMENT - alignment;
size = alignment_offset - offset + VALUE_BYTES;
new_offset = VALUE_BYTES;
}
else
{
if (alignment < ALIGNMENT)
{
auto alignment_offset = detail::align(offset, alignment);
alignment_offset += ALIGNMENT - alignment;
const auto size = alignment_offset - offset + VALUE_BYTES;
offset = {};
const auto new_offset = offset + VALUE_BYTES;
return std::pair{new_offset, size};
}
const auto alignment_offset = detail::align_if<(PreviousTrailingAlignment < ALIGNMENT), ALIGNMENT>(offset);
const auto size = alignment_offset - offset + VALUE_BYTES;
const auto new_offset = offset + size;
return std::pair{new_offset, size};
}();
size = alignment_offset - offset + VALUE_BYTES;
new_offset = offset + size;
}
const auto padding_offset = detail::align_if<(TRAILING_ALIGNMENT < NextAlignment), NextAlignment>(new_offset);
return {new_offset, size, padding_offset - new_offset, (std::max)(alignment, ALIGNMENT)};
}
Expand Down Expand Up @@ -389,22 +387,21 @@ struct ParameterTraits<cntgs::FixedSize<cntgs::AlignAs<T, Alignment>>> : BaseCon
static constexpr AlignedSizeInMemory aligned_size_in_memory(std::size_t offset, std::size_t alignment,
std::size_t fixed_size) noexcept
{
const auto [new_offset, size] = [&]
const auto value_size = VALUE_BYTES * fixed_size;
std::size_t new_offset{};
std::size_t size{};
if (alignment < ALIGNMENT)
{
const auto alignment_offset = detail::align(offset, alignment) + ALIGNMENT - alignment;
size = alignment_offset - offset + value_size;
new_offset = value_size;
}
else
{
if (alignment < ALIGNMENT)
{
auto alignment_offset = detail::align(offset, alignment);
alignment_offset += ALIGNMENT - alignment;
const auto size = alignment_offset - offset + VALUE_BYTES * fixed_size;
offset = {};
const auto new_offset = offset + VALUE_BYTES * fixed_size;
return std::pair{new_offset, size};
}
const auto alignment_offset = detail::align_if<(PreviousTrailingAlignment < ALIGNMENT), ALIGNMENT>(offset);
const auto size = alignment_offset - offset + VALUE_BYTES * fixed_size;
const auto new_offset = offset + size;
return std::pair{new_offset, size};
}();
size = alignment_offset - offset + value_size;
new_offset = offset + size;
}
const auto padding_offset = detail::align_if<(TRAILING_ALIGNMENT < NextAlignment), NextAlignment>(new_offset);
return {new_offset, size, padding_offset - new_offset, (std::max)(alignment, ALIGNMENT)};
}
Expand Down
74 changes: 74 additions & 0 deletions src/cntgs/detail/unmanagedVector.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2024 Dennis Hezel

#ifndef CNTGS_DETAIL_UNMANAGEDVECTOR_HPP
#define CNTGS_DETAIL_UNMANAGEDVECTOR_HPP

#include "cntgs/detail/memory.hpp"

#include <cstddef>
#include <cstring>

namespace cntgs::detail
{
template <class T>
class UnmanagedVector
{
private:
T* data_{};
std::size_t size_{};

public:
UnmanagedVector() = default;

UnmanagedVector(const UnmanagedVector& other) = delete;

constexpr UnmanagedVector(UnmanagedVector&& other) noexcept
: data_(std::exchange(other.data_, nullptr)), size_(std::exchange(other.size_, 0))
{
}

UnmanagedVector& operator=(const UnmanagedVector& other) = delete;

constexpr UnmanagedVector& operator=(UnmanagedVector&& other) noexcept
{
data_ = std::exchange(other.data_, nullptr);
size_ = std::exchange(other.size_, 0);
return *this;
}

[[nodiscard]] constexpr bool empty() const noexcept { return size_ == 0; }

[[nodiscard]] constexpr std::size_t size() const noexcept { return size_; }

[[nodiscard]] constexpr T* data() const noexcept { return data_; }

[[nodiscard]] constexpr T* begin() const noexcept { return data_; }

[[nodiscard]] constexpr T* end() const noexcept { return data_ + size_; }

[[nodiscard]] constexpr T& operator[](std::size_t i) const noexcept { return data_[i]; }

constexpr void resize_from_capacity(std::size_t new_size) noexcept { size_ = new_size; }

constexpr void put_back(T&& value) noexcept
{
data_[size_] = std::move(value);
++size_;
}

template <class Allocator>
constexpr void reserve(std::size_t capacity, const Allocator& allocator)
{
using Traits = RebindTraits<Allocator, T>;
typename Traits::allocator_type alloc(allocator);
auto* const new_mem = Traits::allocate(alloc, capacity);
if (!empty())
{
std::memcpy(new_mem, data_, size_ * sizeof(T));
}
data_ = new_mem;
}
};
} // namespace cntgs::detail

#endif // CNTGS_DETAIL_UNMANAGEDVECTOR_HPP
59 changes: 36 additions & 23 deletions src/cntgs/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class BasicContiguousVector<cntgs::Options<Option...>, Parameter...>
using ElementTraits = detail::ElementTraitsT<Parameter...>;
using Allocator = typename std::allocator_traits<typename ParsedOptions::Allocator>::template rebind_alloc<
typename ElementTraits::StorageElementType>;
using ElementLocator = detail::ElementLocatorT<Allocator, Parameter...>;
using ElementLocatorAndFixedSizes = detail::ElementLocatorAndFixedSizes<Allocator, Parameter...>;
using ElementLocator = detail::ElementLocatorT<Parameter...>;
using ElementLocatorAndFixedSizes = detail::ElementLocatorAndFixedSizes<Parameter...>;
using AllocatorTraits = std::allocator_traits<Allocator>;
using StorageType = detail::AllocatorAwarePointer<Allocator>;
using StorageElementType = typename ElementTraits::StorageElementType;
Expand Down Expand Up @@ -261,9 +261,9 @@ class BasicContiguousVector<cntgs::Options<Option...>, Parameter...>

[[nodiscard]] constexpr const std::byte* data_begin() const noexcept { return data(); }

[[nodiscard]] constexpr std::byte* data_end() noexcept { return locator_->data_end(); }
[[nodiscard]] constexpr std::byte* data_end() noexcept { return locator_->data_end(memory_begin()); }

[[nodiscard]] constexpr const std::byte* data_end() const noexcept { return locator_->data_end(); }
[[nodiscard]] constexpr const std::byte* data_end() const noexcept { return locator_->data_end(memory_begin()); }

[[nodiscard]] constexpr size_type size() const noexcept { return locator_->size(memory_begin()); }

Expand Down Expand Up @@ -378,33 +378,38 @@ class BasicContiguousVector<cntgs::Options<Option...>, Parameter...>
{
const auto new_memory_size =
locator_->calculate_new_memory_size(new_max_element_count, new_varying_size_bytes, locator_.fixed_sizes());
StorageType new_memory{new_memory_size, get_allocator()};
BasicContiguousVector::insert_into<true>(*locator_, new_max_element_count,
reinterpret_cast<std::byte*>(new_memory.get()), *this);
auto new_memory = ElementTraits::template allocate_memory<StorageType>(new_memory_size, get_allocator());
ElementLocator other_locator{*locator_,
memory_begin(),
max_element_count_,
reinterpret_cast<std::byte*>(new_memory.get()),
new_max_element_count,
get_allocator()};
BasicContiguousVector::insert_into<true>(other_locator, new_max_element_count, new_memory, *this);
max_element_count_ = new_max_element_count;
*locator_ = std::move(other_locator);
memory_.reset(std::move(new_memory));
}

template <bool IsDestruct = false, class Self = BasicContiguousVector>
static void insert_into(ElementLocator& locator, size_type new_max_element_count, std::byte* new_memory, Self& from)
static void insert_into(ElementLocator& locator, size_type, StorageType& new_memory, Self& from)
{
static constexpr auto USE_MOVE = !std::is_const_v<Self>;
static constexpr auto IS_TRIVIAL =
USE_MOVE ? ListTraits::IS_TRIVIALLY_MOVE_CONSTRUCTIBLE : ListTraits::IS_TRIVIALLY_COPY_CONSTRUCTIBLE;
auto* const mem = reinterpret_cast<std::byte*>(new_memory.get());
if constexpr (IS_TRIVIAL && (!IsDestruct || ListTraits::IS_TRIVIALLY_DESTRUCTIBLE))
{
locator.trivially_copy_into(from.memory_begin(), new_memory);
from.locator_->trivially_copy_into(from.memory_begin(), mem);
}
else
{
ElementLocator new_locator{detail::move_if<USE_MOVE>(locator), from.memory_begin(), new_max_element_count,
new_memory};
BasicContiguousVector::uninitialized_construct_if_non_trivial<USE_MOVE>(from, new_memory, new_locator);
std::memcpy(mem, from.memory_begin(), from.data_end() - from.memory_begin());
BasicContiguousVector::uninitialized_construct_if_non_trivial<USE_MOVE>(from, mem, locator);
if constexpr (IsDestruct)
{
from.destruct();
}
locator = std::move(new_locator);
}
}

Expand Down Expand Up @@ -486,42 +491,50 @@ class BasicContiguousVector<cntgs::Options<Option...>, Parameter...>
}
else
{
auto other_locator = std::move(other.locator_);
if (other.memory_consumption() > memory_consumption())
{
// allocate memory first because it might throw
StorageType new_memory{other.memory_consumption(), get_allocator()};
ElementLocatorAndFixedSizes other_locator{
other.locator_, other.memory_begin(),
other.max_element_count_, reinterpret_cast<std::byte*>(new_memory.get()),
other.max_element_count_, get_allocator()};
destruct();
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_,
reinterpret_cast<std::byte*>(new_memory.get()), other);
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, new_memory, other);
memory_ = std::move(new_memory);
locator_ = std::move(other_locator);
}
else
{
ElementLocatorAndFixedSizes other_locator{other.locator_, other.memory_begin(),
other.max_element_count_, memory_begin(),
other.max_element_count_, get_allocator()};
destruct();
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_begin(), other);
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_, other);
locator_ = std::move(other_locator);
}
max_element_count_ = other.max_element_count_;
locator_ = std::move(other_locator);
}
}
}

auto copy_construct_locator(const BasicContiguousVector& other)
{
auto other_locator = other.locator_;
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_begin(), other);
ElementLocatorAndFixedSizes other_locator{other.locator_, other.memory_begin(), other.max_element_count_,
memory_begin(), other.max_element_count_, get_allocator()};
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_, other);
return other_locator;
}

void copy_assign(const BasicContiguousVector& other)
{
destruct();
memory_ = other.memory_;
auto other_locator = other.locator_;
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_begin(), other);
ElementLocatorAndFixedSizes other_locator{other.locator_, other.memory_begin(), other.max_element_count_,
memory_begin(), other.max_element_count_, get_allocator()};
BasicContiguousVector::insert_into(*other_locator, other.max_element_count_, memory_, other);
max_element_count_ = other.max_element_count_;
locator_ = other_locator;
locator_ = std::move(other_locator);
}

template <class... TOption>
Expand Down
6 changes: 4 additions & 2 deletions test/codeGen/reference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ struct ReferenceFixedSizeVector
{
return;
}
using Traits = std::allocator_traits<std::allocator<char>>;
Traits::allocator_type alloc{};
const auto new_capacity = new_max_element_count * byte_size_per_node;
auto new_memory = std::allocator<char>{}.allocate(new_capacity);
auto new_memory = Traits::allocate(alloc, new_capacity);
std::memcpy(new_memory, memory, capacity * byte_size_per_node);
std::allocator<char>{}.deallocate(memory, capacity);
Traits::deallocate(alloc, memory, capacity);
capacity = new_capacity;
memory = new_memory;
}
Expand Down
13 changes: 11 additions & 2 deletions test/test-vector-alignment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ TEST_CASE("ContiguousVector: TwoVaryingAligned size() and capacity()")
TEST_CASE("ContiguousVector: OneFixedAligned size(), capacity() and memory_consumption()")
{
TestMemoryResource resource;
OneFixedAligned<TestAllocator<>> v{2, {FLOATS1.size()}, resource.get_allocator()};
Checked<OneFixedAligned<TestAllocator<>>, 32> v{2, {FLOATS1.size()}, resource.get_allocator()};
v.emplace_back(10u, FLOATS1);
check_size1_and_capacity2(v);
v.emplace_back(10u, FLOATS1);
Expand All @@ -51,7 +51,6 @@ TEST_CASE("ContiguousVector: OneFixedAligned size(), capacity() and memory_consu
const auto expected = 2 * test::align(size, 32);
CHECK_EQ(expected, v.memory_consumption());
CHECK_EQ(expected, resource.bytes_allocated);
check_all_memory_is_used(v, 32);
}

TEST_CASE("ContiguousVector: TwoFixedAligned size() and capacity()")
Expand All @@ -73,6 +72,16 @@ TEST_CASE("ContiguousVector: OneFixedOneVaryingAligned size() and capacity()")
check_size1_and_capacity2(v);
}

TEST_CASE("ContiguousVector: OneFixedAligned emplace_back->reserve->emplace_back")
{
Checked<OneFixedAligned<>> v{1, {FLOATS1.size()}};
v.emplace_back(1u, FLOATS1);
v.reserve(2);
v.emplace_back(2u, FLOATS1);
check_equal_using_get(v[0], 1u, FLOATS1);
check_equal_using_get(v[1], 2u, FLOATS1);
}

TEST_CASE("ContiguousVector: PlainAligned emplace_back() and subscript operator")
{
Checked<PlainAligned, 8> vector{5};
Expand Down
2 changes: 1 addition & 1 deletion test/test-vector-emplace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ TEST_CASE("ContiguousVector: std::string OneFixed emplace_back->reserve->emplace

TEST_CASE("ContiguousVector: trivial OneFixed emplace_back->reserve->emplace_back")
{
cntgs::ContiguousVector<cntgs::FixedSize<float>, int> vector{1, {FLOATS1.size()}};
Checked<cntgs::ContiguousVector<cntgs::FixedSize<float>, int>> vector{1, {FLOATS1.size()}};
vector.emplace_back(FLOATS1, 42);
vector.reserve(2);
vector.emplace_back(FLOATS1, 84);
Expand Down

0 comments on commit 27fb2a1

Please sign in to comment.