- Modify dlmalloc_allocation_command to use alignment info, this requires modifying the dlmalloc_ext wrapper library.

- Replace all dlmalloc_malloc uses with dlmalloc_allocation_command to support overaligned types in array allocations.
This commit is contained in:
Ion Gaztañaga
2026-01-19 01:06:56 +01:00
parent 1e1741ce63
commit 9201bbf83b
10 changed files with 49 additions and 29 deletions

View File

@@ -14,6 +14,7 @@
#include <boost/container/detail/dlmalloc.hpp>
#include <boost/container/throw_exception.hpp>
#include <boost/container/detail/type_traits.hpp>
#define BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
@@ -71,7 +72,7 @@ void allocation_timing_test(std::size_t num_iterations, std::size_t num_elements
if(min > max)
max = min;
ret = dlmalloc_allocation_command
( m_mode, sizeof(POD)
(m_mode, sizeof(POD), dtl::alignment_of<POD>::value
, min, max, &received_size, addr);
if(!ret.first){
throw_runtime_error("!ret.first)");

View File

@@ -169,7 +169,7 @@ class adaptive_pool
return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
}
else{
return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T)));
return static_cast<pointer>(dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value));
}
}
@@ -346,7 +346,8 @@ class adaptive_pool
std::size_t r_size;
{
void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
}
prefer_in_recvd_out_size = r_size/sizeof(T);
@@ -470,7 +471,7 @@ class private_adaptive_pool
return pointer(static_cast<T*>(m_pool.allocate_node()));
}
else{
return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T)));
return static_cast<pointer>(dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value));
}
}
@@ -600,7 +601,8 @@ class private_adaptive_pool
std::size_t r_size;
{
void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
}
prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -184,7 +184,7 @@ class allocator
(void)hint;
if(count > size_type(-1)/(2u*sizeof(T)))
boost::container::throw_bad_alloc();
void *ret = dlmalloc_malloc(count*sizeof(T));
void *ret = dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value);
if(!ret)
boost::container::throw_bad_alloc();
return static_cast<pointer>(ret);
@@ -359,7 +359,8 @@ class allocator
std::size_t r_size;
{
void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
}
prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -284,6 +284,7 @@ int boost_cont_malloc_check(void);
boost_cont_command_ret_t boost_cont_allocation_command
( allocation_type command
, size_t sizeof_object
, size_t alignof_object
, size_t limit_objects
, size_t preferred_objects
, size_t *received_objects

View File

@@ -75,6 +75,7 @@ BOOST_CONTAINER_DECL int dlmalloc_malloc_check();
BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command
( allocation_type command
, size_t sizeof_object
, size_t alignof_object
, size_t limit_objects
, size_t preferred_objects
, size_t *received_objects

View File

@@ -156,7 +156,7 @@ class node_allocator
return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
}
else{
void *ret = dlmalloc_malloc(count*sizeof(T));
void *ret = dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value);
if(BOOST_UNLIKELY(!ret))
boost::container::throw_bad_alloc();
return static_cast<pointer>(ret);
@@ -338,7 +338,8 @@ class node_allocator
std::size_t r_size;
{
void* reuse_ptr_void = reuse;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse = static_cast<T*>(reuse_ptr_void);
}
prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -79,12 +79,13 @@ BOOST_CONTAINER_DECL int dlmalloc_malloc_check()
BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command
( allocation_type command
, size_t sizeof_object
, size_t alignof_object
, size_t limit_objects
, size_t preferred_objects
, size_t *received_objects
, void *reuse_ptr
)
{ return boost_cont_allocation_command(command, sizeof_object, limit_objects, preferred_objects, received_objects, reuse_ptr); }
{ return boost_cont_allocation_command(command, sizeof_object, alignof_object, limit_objects, preferred_objects, received_objects, reuse_ptr); }
BOOST_CONTAINER_DECL void *dlmalloc_sync_create()
{ return boost_cont_sync_create(); }

View File

@@ -1174,7 +1174,7 @@ void* boost_cont_malloc(size_t bytes)
size_t received_bytes;
ensure_initialization();
return boost_cont_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1, bytes, bytes, &received_bytes, 0).first;
(BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, bytes, bytes, &received_bytes, 0).first;
}
void boost_cont_free(void* mem)
@@ -1341,7 +1341,7 @@ void* boost_cont_alloc
{
//ensure_initialization provided by boost_cont_allocation_command
return boost_cont_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1, minbytes, preferred_bytes, received_bytes, 0).first;
(BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, minbytes, preferred_bytes, received_bytes, 0).first;
}
void boost_cont_multidealloc(boost_cont_memchain *pchain)
@@ -1373,7 +1373,7 @@ int boost_cont_malloc_check(void)
boost_cont_command_ret_t boost_cont_allocation_command
(allocation_type command, size_t sizeof_object, size_t limit_size
(allocation_type command, size_t sizeof_object, size_t alignof_object, size_t limit_size
, size_t preferred_size, size_t *received_size, void *reuse_ptr)
{
boost_cont_command_ret_t ret = { 0, 0 };
@@ -1416,12 +1416,15 @@ boost_cont_command_ret_t boost_cont_allocation_command
}
if(command & BOOST_CONTAINER_ALLOCATE_NEW){
void *addr = mspace_malloc_lockless(ms, preferred_size);
if(!addr) addr = mspace_malloc_lockless(ms, limit_size);
disable_lock(ms);
void *addr = mspace_memalign(ms, alignof_object, preferred_size);
if(!addr) addr = mspace_memalign(ms, alignof_object, limit_size);
if(addr){
s_allocated_memory += chunksize(mem2chunk(addr));
*received_size = DL_SIZE_IMPL(addr);
}
enable_lock(ms);
ret.first = addr;
ret.second = 0;
if(addr){

View File

@@ -112,12 +112,12 @@ bool test_allocation_shrink()
; ++i){
std::size_t try_received_size = 0;
void* try_result = dlmalloc_allocation_command
( BOOST_CONTAINER_TRY_SHRINK_IN_PLACE, 1, i*2
( BOOST_CONTAINER_TRY_SHRINK_IN_PLACE, 1, 1, i*2
, i, &try_received_size, (char*)buffers[i]).first;
std::size_t received_size = 0;
void* result = dlmalloc_allocation_command
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, i*2
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, 1, i*2
, i, &received_size, (char*)buffers[i]).first;
if(result != try_result)
@@ -174,7 +174,7 @@ bool test_allocation_expand()
std::size_t preferred_size = i*2;
preferred_size = min_size > preferred_size ? min_size : preferred_size;
while(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, min_size
( BOOST_CONTAINER_EXPAND_FWD, 1, 1, min_size
, preferred_size, &received_size, (char*)buffers[i]).first){
//Check received size is bigger than minimum
if(received_size < min_size){
@@ -211,10 +211,10 @@ bool test_allocation_shrink_and_expand()
for(std::size_t i = 0; i != NumIt; ++i){
std::size_t received_size = 0;
void *ptr = dlmalloc_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1u, i, i*2u, &received_size, 0).first;
(BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, i, i*2u, &received_size, 0).first;
if(!ptr){
ptr = dlmalloc_allocation_command
( BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, i*2, &received_size, 0).first;
( BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, 1u, i*2, &received_size, 0).first;
if(!ptr)
break;
}
@@ -230,7 +230,7 @@ bool test_allocation_shrink_and_expand()
bool size_reduced_flag;
if(true == (size_reduced_flag = !!
dlmalloc_allocation_command
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, received_sizes[i]
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, 1, received_sizes[i]
, i, &received_size, (char*)buffers[i]).first)){
if(received_size > std::size_t(received_sizes[i])){
return false;
@@ -250,7 +250,7 @@ bool test_allocation_shrink_and_expand()
std::size_t received_size = 0;
std::size_t request_size = received_sizes[i];
if(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, request_size
( BOOST_CONTAINER_EXPAND_FWD, 1, 1, request_size
, request_size, &received_size, (char*)buffers[i]).first){
if(received_size != request_size){
return false;
@@ -314,7 +314,7 @@ bool test_allocation_deallocation_expand()
preferred_size = min_size > preferred_size ? min_size : preferred_size;
while(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, min_size
( BOOST_CONTAINER_EXPAND_FWD, 1, 1, min_size
, preferred_size, &received_size, (char*)buffers[i]).first){
//Check received size is bigger than minimum
if(received_size < min_size){
@@ -383,7 +383,7 @@ bool test_allocation_with_reuse()
std::size_t min_size = (received_size/sizeof_object + 1u)*sizeof_object;
std::size_t prf_size = (received_size/sizeof_object + (i+1u)*2u)*sizeof_object;
dlmalloc_command_ret_t ret = dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_BWD, sizeof_object, min_size
( BOOST_CONTAINER_EXPAND_BWD, sizeof_object, 1u, min_size
, prf_size, &received_size, (char*)ptr);
//If we have memory, this must be a buffer reuse
if(!ret.first)

View File

@@ -112,10 +112,9 @@ struct GetAllocatorCont
template<class ValueType>
struct apply
{
typedef vector< ValueType
, typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc<ValueType>::type
> type;
typedef typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc<ValueType>::type rebound_allocator_type;
typedef vector< ValueType, rebound_allocator_type> type;
};
};
@@ -127,6 +126,7 @@ int test_cont_variants()
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::moveconstruct_int>::type MyMoveConstructCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::overaligned_copyable_int>::type MyOverAlignCont;
if (test::vector_test<MyCont>())
return 1;
@@ -138,7 +138,11 @@ int test_cont_variants()
return 1;
if (test::vector_test<MyMoveConstructCont>())
return 1;
#if !defined(__cpp_aligned_new) //old std::allocators don't support overaligned types
BOOST_IF_CONSTEXPR(!dtl::is_same<typename MyCont::allocator_type, std::allocator<int> >::value)
#endif
if (test::vector_test<MyOverAlignCont>())
return 1;
return 0;
}
@@ -276,6 +280,11 @@ int main()
std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
return 1;
}
// boost::container::new_allocator
if(test_cont_variants< new_allocator<void> >()){
std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
return 1;
}
{ //Test enum container
typedef vector<Test, std::allocator<Test> > MyEnumCont;