Skip to content

Commit

Permalink
Optimize memory layout for the new ABI reducing block_header size to …
Browse files Browse the repository at this point in the history
…a single word and store string length outside the block_header.
  • Loading branch information
igaztanaga committed Sep 24, 2024
1 parent 9da11df commit 94bc4e1
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 60 deletions.
123 changes: 77 additions & 46 deletions include/boost/interprocess/detail/segment_manager_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
// container/detail
#include <boost/container/detail/type_traits.hpp> //alignment_of
#include <boost/container/detail/minimal_char_traits_header.hpp>
#include <boost/container/detail/placement_new.hpp>
// intrusive
#include <boost/intrusive/pointer_traits.hpp>
// move/detail
Expand Down Expand Up @@ -80,11 +81,15 @@ class mem_algo_deallocator
template<class size_type>
struct block_header
{
private:
const size_type m_value_bytes;
const unsigned short m_num_char;
const unsigned char m_value_alignment;
const unsigned char m_alloc_type_sizeof_char;

public:
typedef std::size_t name_len_t;

block_header(size_type val_bytes
,size_type val_alignment
,unsigned char al_type
Expand All @@ -96,30 +101,34 @@ struct block_header
, m_value_alignment((unsigned char)val_alignment)
, m_alloc_type_sizeof_char( (unsigned char)((al_type << 5u) | ((unsigned char)szof_char & 0x1F)) )
{};

template<std::size_t>
size_type total_size() const
size_type total_anonymous_size() const
{
if(alloc_type() != anonymous_type){
return name_offset() + (m_num_char+1u)*sizeof_char();
}
else{
return this->value_offset() + m_value_bytes;
}
return this->value_offset() + m_value_bytes;
}

size_type value_bytes() const
{ return m_value_bytes; }
template<std::size_t, class>
size_type total_named_size(std::size_t namelen) const
{
(void)namelen;
BOOST_ASSERT(namelen == m_num_char);
return name_offset() + (m_num_char+1u)*sizeof_char();
}

template<std::size_t , class Header>
size_type total_size_with_header() const
template<std::size_t, class, class Header>
size_type total_named_size_with_header(std::size_t namelen) const
{
BOOST_ASSERT(namelen == m_num_char);
return get_rounded_size
( size_type(sizeof(Header))
, size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))
+ this->template total_size<0>();
+ this->template total_named_size<0, char>(namelen);
}

size_type value_bytes() const
{ return m_value_bytes; }

unsigned char alloc_type() const
{ return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }

Expand Down Expand Up @@ -187,6 +196,9 @@ struct block_header
static size_type front_space()
{ return 0u; }

void store_name_length(std::size_t)
{}

private:
size_type value_offset() const
{
Expand Down Expand Up @@ -242,66 +254,78 @@ struct prefix_offsets<MemAlignment, BlockHeader, void>
template<class size_type>
struct block_header
{
const size_type m_value_bytes;
const unsigned short m_num_char;
const unsigned char m_alloc_type_sizeof_char;
private:
const size_type m_alloc_type : 2;
const size_type m_value_bytes : sizeof(size_type)*CHAR_BIT - 2u;

public:
typedef unsigned short name_len_t;

BOOST_STATIC_CONSTEXPR size_type value_mask = ~size_type(0) >> 2u;

block_header(size_type val_bytes
,size_type
,unsigned char al_type
,std::size_t szof_char
,std::size_t num_char
,std::size_t
,std::size_t
)
: m_value_bytes(val_bytes)
, m_num_char((unsigned short)num_char)
, m_alloc_type_sizeof_char( (unsigned char)((al_type << 5u) | ((unsigned char)szof_char & 0x1F)) )
: m_alloc_type(al_type & 3u)
, m_value_bytes(val_bytes& (value_mask))
{};

template<std::size_t MemAlignment>
size_type total_size() const
size_type total_anonymous_size() const
{
BOOST_CONSTEXPR_OR_CONST std::size_t block_header_prefix =
prefix_offsets<MemAlignment, block_header, void>::block_header_prefix;
if(alloc_type() != anonymous_type){
return block_header_prefix + name_offset() + (m_num_char+1u)*sizeof_char();
}
else{
return block_header_prefix + this->value_offset() + m_value_bytes;
}
return block_header_prefix + this->value_offset() + m_value_bytes;
}

template<std::size_t MemAlignment, class Header>
size_type total_size_with_header() const
template<std::size_t MemAlignment, class CharType>
size_type total_named_size(std::size_t namelen) const
{
BOOST_CONSTEXPR_OR_CONST std::size_t block_header_prefix =
prefix_offsets<MemAlignment, block_header, void>::block_header_prefix;
return block_header_prefix
+ name_offset< ::boost::move_detail::alignment_of<CharType>::value>()
+ (namelen + 1u) * sizeof(CharType);
}

template<std::size_t MemAlignment, class CharType, class Header>
size_type total_named_size_with_header(std::size_t namelen) const
{
BOOST_CONSTEXPR_OR_CONST std::size_t block_header_prefix =
prefix_offsets<MemAlignment, block_header, Header>::block_header_prefix;
return block_header_prefix + name_offset() + (m_num_char + 1u) * sizeof_char();
return block_header_prefix
+ name_offset< ::boost::move_detail::alignment_of<CharType>::value>()
+ (namelen + 1u) * sizeof(CharType);
}

size_type value_bytes() const
{ return m_value_bytes; }

unsigned char alloc_type() const
{ return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }

unsigned char sizeof_char() const
{ return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
{ return m_alloc_type; }

template<class CharType>
CharType *name() const
{
return const_cast<CharType*>(move_detail::force_ptr<const CharType*>
(reinterpret_cast<const char*>(this) + name_offset()));
(reinterpret_cast<const char*>(this) +
this->template name_offset< ::boost::move_detail::alignment_of<CharType>::value>()));
}

unsigned short name_length() const
{ return m_num_char; }

void *value() const
name_len_t name_length() const
{
return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
if(m_alloc_type == anonymous_type)
return 0;
return *(move_detail::force_ptr<const name_len_t*>
(reinterpret_cast<const char*>(this) + this->name_length_offset()));
}

void *value() const
{ return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset())); }

template<class T>
static block_header *block_header_from_value(T *value)
{
Expand Down Expand Up @@ -346,20 +370,27 @@ struct block_header

template<std::size_t MemAlignment, class Header>
static size_type front_space()
{ return prefix_offsets<MemAlignment, block_header, Header>::front_space; }

void store_name_length(name_len_t namelen)
{
return prefix_offsets<MemAlignment, block_header, Header>::front_space;
::new( reinterpret_cast<char*>(this) + this->name_length_offset()
, boost_container_new_t()
) name_len_t(namelen);
}

private:

static size_type value_offset()
{
return size_type(sizeof(block_header));
}
{ return size_type(sizeof(block_header)); }

template<std::size_t CharAlign>
size_type name_offset() const
{ return get_rounded_size(this->name_length_offset()+sizeof(name_len_t), CharAlign); }

size_type name_length_offset() const
{
return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char()));
return this->value_offset() + get_rounded_size(m_value_bytes, ::boost::move_detail::alignment_of<name_len_t>::value);
}
};

Expand Down
27 changes: 13 additions & 14 deletions include/boost/interprocess/segment_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ class segment_manager
, 0);

//Check if there is enough memory
const std::size_t total_size = block_info.template total_size<alloc_alignment>();
const std::size_t total_size = block_info.template total_anonymous_size<alloc_alignment>();
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
void *ptr_struct = this->allocate(total_size, nothrow<>::get());
#else
Expand Down Expand Up @@ -757,7 +757,7 @@ class segment_manager

//Call destructors and free memory
//Build scoped ptr to avoid leaks with destructor exception
priv_destroy_n(object, ctrl_data->m_value_bytes/sizeof(T));
priv_destroy_n(object, ctrl_data->value_bytes()/sizeof(T));

BOOST_CONSTEXPR_OR_CONST std::size_t t_alignment =
boost::move_detail::alignment_of<T>::value;
Expand Down Expand Up @@ -807,15 +807,15 @@ class segment_manager
{
boost::interprocess::allocation_type type = ctrl_data->alloc_type();
if(type == anonymous_type){
BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
(type == unique_type && ctrl_data->m_num_char != 0) );
BOOST_ASSERT(ctrl_data->name_length() == 0);
return 0;
}

BOOST_ASSERT(ctrl_data->name_length() != 0);
CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());

//Sanity checks
BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
BOOST_ASSERT(ctrl_data->name_length() == std::char_traits<CharType>::length(name));
return name;
}

Expand Down Expand Up @@ -870,10 +870,9 @@ class segment_manager
block_header_t *ctrl_data = priv_block_header_from_it(it, is_intrusive_t());

//Sanity check
BOOST_ASSERT((ctrl_data->m_value_bytes % sizeof(T)) == 0);
BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
BOOST_ASSERT((ctrl_data->value_bytes() % sizeof(T)) == 0);
ret_ptr = ctrl_data->value();
length = ctrl_data->m_value_bytes/ sizeof(T);
length = ctrl_data->value_bytes()/ sizeof(T);
}
return static_cast<T*>(ret_ptr);
}
Expand Down Expand Up @@ -939,8 +938,7 @@ class segment_manager
block_header_t *ctrl_data = priv_block_header_from_it(it, is_intrusive_t());

//Sanity checks
BOOST_ASSERT((ctrl_data->m_value_bytes % sizeof(T)) == 0);
BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
BOOST_ASSERT((ctrl_data->value_bytes() % sizeof(T)) == 0);

//Erase node from index
index.erase(it);
Expand All @@ -963,7 +961,7 @@ class segment_manager
}

//Call destructors and free memory
priv_destroy_n(static_cast<T*>(ctrl_data->value()), ctrl_data->m_value_bytes/sizeof(T));
priv_destroy_n(static_cast<T*>(ctrl_data->value()), ctrl_data->value_bytes()/sizeof(T));

//Destroy the headers
ctrl_data->~block_header_t();
Expand Down Expand Up @@ -1048,7 +1046,7 @@ class segment_manager

//Allocate and construct the headers
BOOST_IF_CONSTEXPR(is_node_index_t::value || is_intrusive_t::value){
const size_type total_size = block_info.template total_size_with_header<alloc_alignment, index_data_t>();
const size_type total_size = block_info.template total_named_size_with_header<alloc_alignment, CharT, index_data_t>(namelen);
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
buffer_ptr = this->allocate(total_size, nothrow<>::get());
#else
Expand All @@ -1062,7 +1060,7 @@ class segment_manager
hdr = block_header_t::template from_first_header(reinterpret_cast<index_data_t*>((void*)((char*)buffer_ptr+front_space)));
}
else{
const size_type total_size = block_info.template total_size<alloc_alignment>();
const size_type total_size = block_info.template total_named_size<alloc_alignment, CharT>(namelen);
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
buffer_ptr = this->allocate(total_size, nothrow<>::get());
#else
Expand All @@ -1087,6 +1085,7 @@ class segment_manager
void *ptr = hdr->value();

//Copy name to memory segment and insert data
hdr->store_name_length(static_cast<typename block_header_t::name_len_t>(namelen));
CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
std::char_traits<CharT>::copy(name_ptr, name, namelen+1);

Expand Down

0 comments on commit 94bc4e1

Please sign in to comment.