Skip to content

Commit

Permalink
iox-#2044 Make 'FixedPositionContainer' more cache line friendly
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Oct 24, 2023
1 parent 6218702 commit d9c3857
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 48 deletions.
126 changes: 89 additions & 37 deletions iceoryx_dust/container/include/iox/detail/fixed_position_container.inl
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ inline FixedPositionContainer<T, CAPACITY>::FixedPositionContainer() noexcept
{
for (IndexType i = 0; i < CAPACITY;)
{
m_slots[i].status = SlotStatus::FREE;
m_status[i] = SlotStatus::FREE;

IndexType next = static_cast<IndexType>(i + 1U);
m_slots[i].next = next;
m_next[i] = next;
i = next;
}
m_slots[Index::LAST].next = Index::INVALID;
m_next[Index::LAST] = Index::INVALID;

m_begin_free = Index::FIRST;
m_begin_used = Index::INVALID;
Expand All @@ -44,7 +44,7 @@ inline FixedPositionContainer<T, CAPACITY>::~FixedPositionContainer() noexcept
{
for (IndexType i = 0; i < CAPACITY; ++i)
{
if (m_slots[i].status == SlotStatus::USED)
if (m_status[i] == SlotStatus::USED)
{
m_data[i].~T();
}
Expand All @@ -56,18 +56,18 @@ inline void FixedPositionContainer<T, CAPACITY>::clear() noexcept
{
for (IndexType i = 0; i < CAPACITY;)
{
if (m_slots[i].status == SlotStatus::USED)
if (m_status[i] == SlotStatus::USED)
{
m_data[i].~T();
}

m_slots[i].status = SlotStatus::FREE;
m_status[i] = SlotStatus::FREE;

IndexType next = static_cast<IndexType>(i + 1U);
m_slots[i].next = next;
m_next[i] = next;
i = next;
}
m_slots[Index::LAST].next = Index::INVALID;
m_next[Index::LAST] = Index::INVALID;

m_size = 0;
m_begin_free = Index::FIRST;
Expand Down Expand Up @@ -96,8 +96,14 @@ FixedPositionContainer<T, CAPACITY>::emplace(Targs&&... args) noexcept
//
// terminology
//
// slot
//
// +---+
// |S:#| <- slot with status and index of next slot with same status
// | 0 | <- index of current slot
// +---+
// | S | <- current slot status
// +---+
// | # | <- index of next slot with same status
// +---+
// S: slot status; can be F(free) or U(used)
// #: index of next slot with same status; can be a number or I(Index::INVALID) if there are no further slots
Expand All @@ -110,7 +116,11 @@ FixedPositionContainer<T, CAPACITY>::emplace(Targs&&... args) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:1|F:5|U:3|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | F | U | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 1 | 5 | 3 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
// after insertion
// begin_used
Expand All @@ -119,7 +129,11 @@ FixedPositionContainer<T, CAPACITY>::emplace(Targs&&... args) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |U:2|F:5|U:3|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | U | F | U | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 2 | 5 | 3 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
//
// scenario 2 (begin_free is ahead of begin_used)
Expand All @@ -130,7 +144,11 @@ FixedPositionContainer<T, CAPACITY>::emplace(Targs&&... args) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |U:3|F:2|F:5|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | U | F | F | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 3 | 2 | 5 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
// before insertion
// begin_used
Expand All @@ -139,30 +157,34 @@ FixedPositionContainer<T, CAPACITY>::emplace(Targs&&... args) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |U:1|U:3|F:5|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | U | U | F | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 1 | 3 | 5 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +

const auto index = m_begin_free;
m_begin_free = m_slots[m_begin_free].next;
m_begin_free = m_next[m_begin_free];

new (&m_data[index]) T(std::forward<Targs>(args)...);
m_slots[index].status = SlotStatus::USED;
m_status[index] = SlotStatus::USED;
++m_size;

if (index < m_begin_used)
{
m_slots[index].next = m_begin_used;
m_next[index] = m_begin_used;
m_begin_used = index;
}
else
{
iox::cxx::EnsuresWithMsg(index != 0, "Corruption detected!");
for (IndexType i = static_cast<IndexType>(index - 1U);; --i)
{
if (m_slots[i].status == SlotStatus::USED)
if (m_status[i] == SlotStatus::USED)
{
m_slots[index].next = m_slots[i].next;
m_slots[i].next = index;
m_next[index] = m_next[i];
m_next[i] = index;
break;
}
iox::cxx::EnsuresWithMsg(i != 0, "Corruption detected!");
Expand All @@ -178,17 +200,23 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
{
iox::cxx::ExpectsWithMsg(index <= Index::LAST, "Index out of range");

iox::cxx::EnsuresWithMsg(m_slots[index].status == SlotStatus::USED,
iox::cxx::EnsuresWithMsg(m_status[index] == SlotStatus::USED,
"Trying to erase from index pointing to an empty slot!");

const auto it = Iterator{m_slots[index].next, *this};
const auto it = Iterator{m_next[index], *this};

// removing data from the container
//
// terminology
//
// slot
//
// +---+
// | 0 | <- index of current slot
// +---+
// | S | <- current slot status
// +---+
// |S:#| <- slot with status and index of next slot with same status
// | # | <- index of next slot with same status
// +---+
// S: slot status; can be F(free) or U(used)
// #: index of next slot with same status; can be a number or I(Index::INVALID) if there are no further slots
Expand All @@ -201,7 +229,11 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |U:2|F:5|U:3|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | U | F | U | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 2 | 5 | 3 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
// after removal
// begin_free
Expand All @@ -210,7 +242,11 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:1|F:5|U:3|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | F | U | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 1 | 5 | 3 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
//
// scenario 2 (remove at begin_used and remove index is ahead of begin_free)
Expand All @@ -221,7 +257,11 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:2|U:3|F:5|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | U | F | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 2 | 3 | 5 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
// after removal
// begin_free
Expand All @@ -230,7 +270,11 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:1|F:2|F:5|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | F | F | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 1 | 2 | 5 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
//
// scenario 3 (remove ahead of begin_used and begin_free)
Expand All @@ -244,7 +288,11 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | | Index::INVALID
// ᵛ ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:2|U:3|F:5|U:4|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | U | F | U | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 2 | 3 | 5 | 4 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +
// before removal
// begin_free
Expand All @@ -253,14 +301,18 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
// | | Index::INVALID
// ᵛ ᵛ ᵛ
// +---+---+---+---+---+---+ - +
// |F:2|U:4|F:3|F:5|U:I|F:I| |
// | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index
// +---+---+---+---+---+---+ - +
// | F | U | F | F | U | F | | <- status
// +---+---+---+---+---+---+ - +
// | 2 | 4 | 3 | 5 | I | I | | <- next index with same status
// +---+---+---+---+---+---+ - +

m_data[index].~T();
m_slots[index].status = SlotStatus::FREE;
m_status[index] = SlotStatus::FREE;
--m_size;

auto next_used = m_slots[index].next;
auto next_used = m_next[index];
bool is_removed_from_used_list{false};
bool is_added_to_free_list{false};

Expand All @@ -272,7 +324,7 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept

if (index < m_begin_free)
{
m_slots[index].next = m_begin_free;
m_next[index] = m_begin_free;
m_begin_free = index;
is_added_to_free_list = true;
}
Expand All @@ -285,16 +337,16 @@ FixedPositionContainer<T, CAPACITY>::erase(const IndexType index) noexcept
iox::cxx::EnsuresWithMsg(index != 0, "Corruption detected! Index cannot be 0 at this location!");
for (IndexType i = static_cast<IndexType>(index - 1U); !is_removed_from_used_list || !is_added_to_free_list; --i)
{
if (!is_removed_from_used_list && m_slots[i].status == SlotStatus::USED)
if (!is_removed_from_used_list && m_status[i] == SlotStatus::USED)
{
m_slots[i].next = next_used;
m_next[i] = next_used;
is_removed_from_used_list = true;
}

if (!is_added_to_free_list && m_slots[i].status == SlotStatus::FREE)
if (!is_added_to_free_list && m_status[i] == SlotStatus::FREE)
{
m_slots[index].next = m_slots[i].next;
m_slots[i].next = index;
m_next[index] = m_next[i];
m_next[i] = index;
is_added_to_free_list = true;
}

Expand Down Expand Up @@ -383,7 +435,7 @@ template <typename T, uint64_t CAPACITY>
inline typename FixedPositionContainer<T, CAPACITY>::ConstIterator
FixedPositionContainer<T, CAPACITY>::iter_from_index(const IndexType index) const
{
if (index > Index::LAST || m_slots[index].status != SlotStatus::USED)
if (index > Index::LAST || m_status[index] != SlotStatus::USED)
{
return end();
}
Expand Down
17 changes: 6 additions & 11 deletions iceoryx_dust/container/include/iox/fixed_position_container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,6 @@ class FixedPositionContainer final
USED,
};

struct Slot
{
IndexType next{Index::INVALID};
SlotStatus status{SlotStatus::FREE};
};

template <IterMutability ITER_MUTABILITY>
class IteratorBase
{
Expand Down Expand Up @@ -227,7 +221,7 @@ class FixedPositionContainer final
{
if (m_index <= Index::LAST)
{
m_index = m_container.get().m_slots[m_index].next;
m_index = m_container.get().m_next[m_index];
}
return *this;
}
Expand All @@ -249,7 +243,7 @@ class FixedPositionContainer final
IOX_NO_DISCARD Value& operator*() const
{
iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!");
iox::cxx::EnsuresWithMsg(m_container.get().m_slots[m_index].status == SlotStatus::USED,
iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED,
"Invalid access! Slot not in use!");
return m_container.get().m_data[m_index];
}
Expand All @@ -262,7 +256,7 @@ class FixedPositionContainer final
IOX_NO_DISCARD Value* operator->() const
{
iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!");
iox::cxx::EnsuresWithMsg(m_container.get().m_slots[m_index].status == SlotStatus::USED,
iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED,
"Invalid access! Slot not in use!");
return &m_container.get().m_data[m_index];
}
Expand All @@ -275,7 +269,7 @@ class FixedPositionContainer final
IOX_NO_DISCARD Value* to_ptr() const
{
iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!");
iox::cxx::EnsuresWithMsg(m_container.get().m_slots[m_index].status == SlotStatus::USED,
iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED,
"Invalid access! Slot not in use!");
return &m_container.get().m_data[m_index];
}
Expand Down Expand Up @@ -326,7 +320,8 @@ class FixedPositionContainer final

private:
UninitializedArray<T, CAPACITY> m_data;
UninitializedArray<Slot, CAPACITY> m_slots;
UninitializedArray<SlotStatus, CAPACITY> m_status;
UninitializedArray<IndexType, CAPACITY> m_next;
IndexType m_size{0};
IndexType m_begin_free{Index::FIRST};
IndexType m_begin_used{Index::INVALID};
Expand Down

0 comments on commit d9c3857

Please sign in to comment.