diff --git a/ACE/ace/Malloc_T.cpp b/ACE/ace/Malloc_T.cpp old mode 100644 new mode 100755 index 8f1467423601a..2f43aa2379014 --- a/ACE/ace/Malloc_T.cpp +++ b/ACE/ace/Malloc_T.cpp @@ -14,6 +14,7 @@ #include "ace/ACE.h" #include "ace/OS_NS_string.h" #include +#include ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -177,6 +178,499 @@ ACE_Dynamic_Cached_Allocator::free (void * ptr) this->free_list_.add ((ACE_Cached_Mem_Pool_Node *) ptr); } +template +ACE_Cascaded_Dynamic_Cached_Allocator::ACE_Cascaded_Dynamic_Cached_Allocator + (size_t initial_n_chunks, size_t chunk_size) + : initial_n_chunks_ (initial_n_chunks), + chunk_size_ (chunk_size), + chunk_sum_ (0) +{ + ACE_ASSERT (this->chunk_size_ > 0); + + comb_alloc_ptr tmp; + // If ACE_NEW fails, the hierarchy_ will be reconstructed when malloc API is called. + ACE_NEW (tmp, comb_alloc_type (this->initial_n_chunks_, this->chunk_size_)); + + // Consider the exception of vector push_back call. + std::unique_ptr smart_ptr (tmp); + // Has strong exception safety guarantee for call of push_back. + this->hierarchy_.push_back (smart_ptr.get ()); + + // Increase the chunk sum if all points having potential risk of exception is passed. + this->chunk_sum_ += smart_ptr->pool_depth (); + + smart_ptr.release (); +} + +template +ACE_Cascaded_Dynamic_Cached_Allocator::~ACE_Cascaded_Dynamic_Cached_Allocator () +{ + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + delete this->hierarchy_[h]; + } + + this->hierarchy_.clear (); +} + +template void * +ACE_Cascaded_Dynamic_Cached_Allocator::malloc (size_t nbytes) +{ + // Check if size requested fits within pre-determined size. + if (nbytes > this->chunk_size_) + return nullptr; + + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, nullptr)); + + size_t const size = this->hierarchy_.size (); + if (size == 0) + return nullptr; + + // Only the first and last child allocator maybe has free chunks, the others are empty. + void* ptr = this->hierarchy_[0]->malloc (nbytes); + if (ptr != nullptr) + return ptr; + + // The code will possibly be optimized by compiler when using const var. + size_t const lastAllocatorPos = size - 1; + if (lastAllocatorPos > 0) + { + ptr = this->hierarchy_[lastAllocatorPos]->malloc (nbytes); + if (ptr != nullptr) + return ptr; + } + + // Need alloc a new child allocator. + comb_alloc_ptr tmp; + ACE_NEW_RETURN (tmp, comb_alloc_type (this->initial_n_chunks_ * (1 << size), + this->chunk_size_), + nullptr); + + // Consider the exception of vector push_back call. + std::unique_ptr smart_ptr (tmp); + // Has strong exception safety guarantee for call of push_back. + this->hierarchy_.push_back (smart_ptr.get ()); + + // Increase the chunk sum if all points having potential risk of exception is passed. + this->chunk_sum_ += smart_ptr->pool_depth (); + ptr = smart_ptr->malloc (nbytes); + smart_ptr.release (); + + return ptr; +} + +template void * +ACE_Cascaded_Dynamic_Cached_Allocator::calloc (size_t nbytes, + char initial_value) +{ + // Check if size requested fits within pre-determined size. + if (nbytes > this->chunk_size_) + return nullptr; + + // No need any lock. + void *ptr = malloc(nbytes); + if (ptr != nullptr) + ACE_OS::memset (ptr, initial_value, this->chunk_size_); + + return ptr; +} + +template void * +ACE_Cascaded_Dynamic_Cached_Allocator::calloc (size_t, size_t, char) +{ + ACE_NOTSUP_RETURN (nullptr); +} + +template void +ACE_Cascaded_Dynamic_Cached_Allocator::free (void * ptr) +{ + if (ptr == nullptr) + return; + + ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_)); + + ACE_ASSERT (this->hierarchy_.size () > 0); + + // Use first allocator as a free chunk manager for all allocators when chunk freed. + if (this->hierarchy_.size () != 0) + this->hierarchy_[0]->free (ptr); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::remove () +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::bind (const char *, void *, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::trybind (const char *, void *&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::find (const char *, void *&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::find (const char *) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::unbind (const char *) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::unbind (const char *, void *&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::sync (ssize_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::sync (void *, size_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::protect (ssize_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template int +ACE_Cascaded_Dynamic_Cached_Allocator::protect (void *, size_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template size_t +ACE_Cascaded_Dynamic_Cached_Allocator::pool_depth () +{ + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0)); + + size_t const size = this->hierarchy_.size (); + if (size == 0) + return 0; + + // Only the first and last child allocator maybe has non-zero value, the others have zero value. + size_t pool_depth = this->hierarchy_[0]->pool_depth (); + + if (size > 1) + pool_depth += this->hierarchy_[size - 1]->pool_depth (); + + return pool_depth; +} + +template void +ACE_Cascaded_Dynamic_Cached_Allocator::dump () const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Cascaded_Dynamic_Cached_Allocator::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("initial_n_chunks_ = %u\n"), this->initial_n_chunks_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("chunk_size_ = %u\n"), this->chunk_size_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("chunk_sum_ = %u\n"), this->chunk_sum_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("hierarchy_ size = %u\n"), this->hierarchy_.size ())); + + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + this->hierarchy_[h]->dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + } + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Cascaded_Multi_Size_Based_Allocator::ACE_Cascaded_Multi_Size_Based_Allocator +(size_t initial_n_chunks, size_t initial_chunk_size, size_t min_initial_n_chunks) + : initial_n_chunks_ (initial_n_chunks), + min_initial_n_chunks_ (min_initial_n_chunks), + initial_chunk_size_ (initial_chunk_size) +{ + ACE_ASSERT (this->initial_chunk_size_ > 0); + + comb_alloc_ptr tmp; + // If ACE_NEW fails, the hierarchy_ will be reconstructed when malloc API is called. + // Notice: need one octet to record hierarchy pos. + ACE_NEW (tmp, comb_alloc_type (this->initial_n_chunks_, + this->initial_chunk_size_ + sizeof(comb_chunk_header_type)) + ); + + // Consider the exception of vector push_back call. + std::unique_ptr smart_ptr (tmp); + this->hierarchy_.push_back (smart_ptr.get ()); + + smart_ptr.release (); +} + +template +ACE_Cascaded_Multi_Size_Based_Allocator::~ACE_Cascaded_Multi_Size_Based_Allocator () +{ + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + if (this->hierarchy_[h] != nullptr) + delete this->hierarchy_[h]; + } + + this->hierarchy_.clear (); +} + +template +void* ACE_Cascaded_Multi_Size_Based_Allocator::malloc (size_t nbytes) +{ + // Will be assigned by lately Binary Search process. + size_t chunk_size; + + // Use Binary Search to find minimal pos that value is bigger than nbytes. + size_t m = 0; + size_t l = 0; + size_t h = this->hierarchy_.size (); + + while (l <= h) + { + m = (l + h) / 2; + chunk_size = this->initial_chunk_size_ << m; + + if (chunk_size >= nbytes) + { + // End loop. + if (m == 0) + break; + + h = m - 1; + } + else + { + l = m + 1; + } + } + + // Not in hierarchy or less than nbytes when Binary Search. + while (chunk_size < nbytes) + { + // Equal to this->initial_chunk_size_ << (m + 1). + chunk_size <<= 1; + ++m; + } + + if (m > ACE_OCTET_MAX) + return nullptr; + + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, nullptr)); + + if (m < this->hierarchy_.size () && this->hierarchy_[m] != nullptr) + { + void *ptr = this->hierarchy_[m]->malloc(nbytes); + if (ptr == nullptr) + return nullptr; + + *static_cast (ptr) = static_cast (m); + return static_cast (ptr) + 1; + } + + // The found pos maybe nullptr or beyond the current hierarchy_ size. + if (m >= this->hierarchy_.size ()) + { + // Has strong exception safety guarantee for call of resize, maybe throw. + this->hierarchy_.resize (m + 1, nullptr); + } + + size_t const reinitial_n_chunks = this->initial_n_chunks_ >> m; + comb_alloc_ptr newly_alloc; + // Notice: need one octet to record hierarchy pos. + ACE_NEW_RETURN (newly_alloc, + comb_alloc_type (reinitial_n_chunks > this->min_initial_n_chunks_ ? reinitial_n_chunks : this->min_initial_n_chunks_, + chunk_size + sizeof(comb_chunk_header_type)), + nullptr); + + this->hierarchy_[m] = newly_alloc; + void *ptr = newly_alloc->malloc (nbytes); + if (ptr == nullptr) + return nullptr; + + *static_cast (ptr) = static_cast (m); + return static_cast (ptr) + 1; +} + +template +void* ACE_Cascaded_Multi_Size_Based_Allocator::calloc (size_t nbytes, char initial_value) +{ + // No need any lock. + void *ptr = malloc (nbytes); + if (ptr != nullptr) + ACE_OS::memset (ptr, initial_value, nbytes); + + return ptr; +} + +template +void* ACE_Cascaded_Multi_Size_Based_Allocator::calloc (size_t, size_t, char) +{ + ACE_NOTSUP_RETURN (nullptr); +} + +template +void ACE_Cascaded_Multi_Size_Based_Allocator::free (void* ptr) +{ + if (ptr == nullptr) + return; + + ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_)); + + ACE_ASSERT (this->hierarchy_.size () > 0); + + void* const hdr_ptr = static_cast (ptr) - 1; + size_t const h = *static_cast (hdr_ptr); + + if (h < this->hierarchy_.size () && this->hierarchy_[h] != nullptr) + this->hierarchy_[h]->free (hdr_ptr); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::remove () +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::bind (const char*, void*, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::trybind (const char*, void*&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::find (const char*, void*&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::find (const char*) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::unbind (const char*) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::unbind (const char*, void*&) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::sync (ssize_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::sync (void*, size_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::protect (ssize_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +int ACE_Cascaded_Multi_Size_Based_Allocator::protect (void*, size_t, int) +{ + ACE_NOTSUP_RETURN (-1); +} + +template +size_t ACE_Cascaded_Multi_Size_Based_Allocator::pool_depth () +{ + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0)); + + size_t pool_depth = 0; + + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + if (this->hierarchy_[h] != nullptr) + pool_depth += this->hierarchy_[h]->pool_depth (); + } + + return pool_depth; +} + +template +size_t ACE_Cascaded_Multi_Size_Based_Allocator::pool_sum () +{ + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0)); + + size_t pool_sum = 0; + + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + if (this->hierarchy_[h] != nullptr) + pool_sum += this->hierarchy_[h]->pool_sum (); + } + + return pool_sum; +} + +template +void ACE_Cascaded_Multi_Size_Based_Allocator::dump () const +{ +#if defined(ACE_HAS_DUMP) + ACE_TRACE ("ACE_Cascaded_Multi_Size_Based_Allocator::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("initial_n_chunks_ = %u\n"), this->initial_n_chunks_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("min_initial_n_chunks_ = %u\n"), this->min_initial_n_chunks_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("chunk_size_ = %u\n"), this->initial_chunk_size_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("hierarchy_ size = %u\n"), this->hierarchy_.size ())); + + for (size_t h = 0; h < this->hierarchy_.size (); h++) + { + if (this->hierarchy_[h] != nullptr) + { + this->hierarchy_[h]->dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + } + } + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + ACE_ALLOC_HOOK_DEFINE_Tmcc (ACE_Malloc_T) template void * diff --git a/ACE/ace/Malloc_T.h b/ACE/ace/Malloc_T.h old mode 100644 new mode 100755 index 62775b798cbdb..6718a2c80c5ce --- a/ACE/ace/Malloc_T.h +++ b/ACE/ace/Malloc_T.h @@ -5,7 +5,8 @@ * @file Malloc_T.h * * @author Douglas C. Schmidt and - * Irfan Pyarali + * Irfan Pyarali and + * smithAchang */ //========================================================================== @@ -15,6 +16,7 @@ #include "ace/Malloc.h" /* Need ACE_Control_Block */ #include "ace/Malloc_Base.h" /* Need ACE_Allocator */ +#include "ace/Null_Mutex.h" /* Need ACE_Null_Mutex */ #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once @@ -24,6 +26,8 @@ #include "ace/Free_List.h" #include "ace/Guard_T.h" +#include + ACE_BEGIN_VERSIONED_NAMESPACE_DECL /** @@ -203,6 +207,222 @@ class ACE_Dynamic_Cached_Allocator : public ACE_New_Allocator size_t chunk_size_; }; +/** + * @class ACE_Cascaded_Dynamic_Cached_Allocator + * + * @brief A size-based allocator that caches blocks for quicker access, + * but with a hierarchy of cascaded, nested allocators + * + * This class enables caching of dynamically allocated, + * fixed-size chunks. Notice that the @a chunk_size + * must be greater than or equal to sizeof (void*) for + * this to work properly. + * + * Notice that when the latest allocator is empty, the allocator will create a fresh + * @a ACE_Dynamic_Cached_Allocator allocator again with + * init_n_chunks * ( 1 << the sum of current allocators ) as it's constructor parameter, + * so all the allocators will form a cascaded hierarchy. + + * This class can be configured flexibly with different types of + * ACE_LOCK strategies that support the @a ACE_Thread_Mutex and + * @a ACE_Process_Mutex constructor API. + * + * @sa ACE_Dynamic_Cached_Allocator + */ +template +class ACE_Cascaded_Dynamic_Cached_Allocator : public ACE_Allocator +{ +public: + // Useful STL-style traits. + using comb_alloc_type = ACE_Dynamic_Cached_Allocator; + using comb_alloc_ptr = comb_alloc_type*; + + /// Create a cached memory pool with @a initial_n_chunks chunks + /// each with @a chunk_size size. + ACE_Cascaded_Dynamic_Cached_Allocator (size_t initial_n_chunks, size_t chunk_size); + + /// Clear things up. + ~ACE_Cascaded_Dynamic_Cached_Allocator (); + + /** + * Get a chunk of memory from free list cache. Note that @a nbytes is + * only checked to make sure that it's less or equal to @a chunk_size, + * and is otherwise ignored since malloc() always returns a pointer to an + * item of @a chunk_size size. + */ + virtual void *malloc (size_t nbytes); + + /** + * Get a chunk of memory from free list cache, giving them + * @a initial_value. Note that @a nbytes is only checked to make sure + * that it's less or equal to @a chunk_size, and is otherwise ignored + * since calloc() always returns a pointer to an item of @a chunk_size. + */ + virtual void *calloc (size_t nbytes, char initial_value = '\0'); + + /// This method is a no-op and just returns 0 since the free list + /// only works with fixed sized entities. + virtual void *calloc (size_t n_elem, size_t elem_size, char initial_value = '\0'); + + /// Return a chunk of memory back to free list cache. + virtual void free (void *ptr); + + /// Dump the state of this object. + virtual void dump () const; + + /// These methods are no-ops. + virtual int remove (); + virtual int bind (const char *name, void *pointer, int duplicates = 0); + virtual int trybind (const char *name, void *&pointer); + virtual int find (const char *name, void *&pointer); + virtual int find (const char *name); + virtual int unbind (const char *name); + virtual int unbind (const char *name, void *&pointer); + virtual int sync (ssize_t len = -1, int flags = MS_SYNC); + virtual int sync (void *addr, size_t len, int flags = MS_SYNC); + virtual int protect (ssize_t len = -1, int prot = PROT_RDWR); + virtual int protect (void *addr, size_t len, int prot = PROT_RDWR); + + /// Return the number of chunks available in the hierarchy. + size_t pool_depth (); + + /// Return the sum of chunks including used and freed in the hierarchy. + size_t pool_sum (); + + /// Returns a reference to the lock used to provide mutual exclusion to + /// the allocator hierarchy. + ACE_LOCK &mutex (); + +private: + /// Synchronization variable for API. + ACE_LOCK mutex_; + + /// Remember how we allocate the memory so we can clear things up later. + std::vector hierarchy_; + + /// Remember the size of initial n_chunks for creating fresh allocator in future. + const size_t initial_n_chunks_; + + /// Remember the size of our chunks for creating fresh allocator in future. + const size_t chunk_size_; + + /// Remember the sum of our chunks including used and freed + size_t chunk_sum_; +}; + +/** + * @class ACE_Cascaded_Multi_Size_Based_Allocator + * + * @brief A allocator nests a vector of various size-based allocators using @a ACE_Cascaded_Dynamic_Cached_Allocator + * forming a allocator hierarchy, so, it will has 'infinite' space as your host. + * This allocator will decrease the complicated management overhead of @a ACE_Malloc + * when it has a very long linked list, but with various, random chunk size by a cost of O(1). + * + * Notice that the @a chunk_size must be greater than or equal to sizeof (void*) for + * this to work properly. + * + * Notice when requested memory space can't be meet, the allocator will create a fresh + * @a ACE_Cascaded_Dynamic_Cached_Allocator allocator again with + * init_n_chunks as its constructor parameter, but decreased according to its level order, + * chunk_size as its constructor parameter, but increased according to its level order, + * so all the allocators will form a cascaded hierarchy. + + * This class can be configured flexibly with different types of + * ACE_LOCK strategies that support the @a ACE_Thread_Mutex and @a + * ACE_Process_Mutex constructor API. + * + * @sa ACE_Cascaded_Dynamic_Cached_Allocator + */ +template +class ACE_Cascaded_Multi_Size_Based_Allocator : public ACE_Allocator +{ +public: + // Useful STL-style traits. + using comb_alloc_type = ACE_Cascaded_Dynamic_Cached_Allocator; + using comb_alloc_ptr = comb_alloc_type*; + + /// Create a cached memory pool with @a initial_n_chunks and @a initial_chunk_size as pool starting base + /// and @a min_initial_n_chunks as a adjustable threshold. + /// When creating a fresh @a ACE_Cascaded_Dynamic_Cached_Allocator, its constructor parameter initial_n_chunks + /// will be decreased by @a initial_chunk_size is be shifted right according to its level order, + /// but initial_n_chunks must be greater than or equal to @a min_initial_n_chunks, + /// and its another constructor parameter chunk_size will be increased + /// by @a initial_chunk_size is be shifted left according to its level order e.g. greater than previous level + + ACE_Cascaded_Multi_Size_Based_Allocator (size_t initial_n_chunks, size_t initial_chunk_size, size_t min_initial_n_chunks = 1); + + /// Clear things up. + ~ACE_Cascaded_Multi_Size_Based_Allocator (); + + /** + * Get a chunk of memory from free list cache. Note that @a nbytes is + * only checked to make sure that it's less or equal to @a chunk_size, + * and is otherwise ignored since malloc() always returns a pointer to an + * item of @a chunk_size size. + */ + virtual void* malloc (size_t nbytes); + + /** + * Get a chunk of memory from free list cache, giving them + * @a initial_value. Note that @a nbytes is only checked to make sure + * that it's less or equal to @a chunk_size, and is otherwise ignored + * since calloc() always returns a pointer to an item of @a chunk_size. + */ + virtual void* calloc (size_t nbytes, char initial_value = '\0'); + + /// This method is a no-op and just returns 0 since the free list + /// only works with fixed sized entities. + virtual void* calloc (size_t n_elem, size_t elem_size, char initial_value = '\0'); + + /// Return a chunk of memory back to free list cache. + virtual void free (void* ptr); + + /// Dump the state of this object. + virtual void dump () const; + + /// These methods are no-ops. + virtual int remove (); + virtual int bind (const char* name, void* pointer, int duplicates = 0); + virtual int trybind (const char* name, void*& pointer); + virtual int find (const char* name, void*& pointer); + virtual int find (const char* name); + virtual int unbind (const char* name); + virtual int unbind (const char* name, void*& pointer); + virtual int sync (ssize_t len = -1, int flags = MS_SYNC); + virtual int sync (void* addr, size_t len, int flags = MS_SYNC); + virtual int protect (ssize_t len = -1, int prot = PROT_RDWR); + virtual int protect (void* addr, size_t len, int prot = PROT_RDWR); + + /// Return the number of chunks available in the hierarchy. + size_t pool_depth (); + + /// Return the sum of chunks including used and freed in the hierarchy. + size_t pool_sum (); + + /// Returns a reference to the lock used to provide mutual exclusion to + /// the allocator hierarchy. + ACE_LOCK& mutex (); + +private: + /// Chunk control header type. + typedef ACE_UINT8 comb_chunk_header_type; + + /// Synchronization variable for API. + ACE_LOCK mutex_; + + /// Remember how we allocate the memory so we can clear things up later. + std::vector hierarchy_; + + /// Remember the size of initial n_chunks for creating fresh allocator in future. + const size_t initial_n_chunks_; + + /// Remember the min size of initial n_chunks for creating fresh allocator in future. + const size_t min_initial_n_chunks_; + + /// Remember the initial size of our chunks for creating fresh allocator in future. + const size_t initial_chunk_size_; +}; + /** * @class ACE_Allocator_Adapter * diff --git a/ACE/ace/Malloc_T.inl b/ACE/ace/Malloc_T.inl index c66d0edfc69c5..a2f71a64de8fa 100644 --- a/ACE/ace/Malloc_T.inl +++ b/ACE/ace/Malloc_T.inl @@ -38,6 +38,26 @@ ACE_Dynamic_Cached_Allocator::pool_depth () return this->free_list_.size (); } +template ACE_INLINE size_t +ACE_Cascaded_Dynamic_Cached_Allocator::pool_sum () +{ + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0)); + + return this->chunk_sum_; +} + +template ACE_INLINE ACE_LOCK & +ACE_Cascaded_Dynamic_Cached_Allocator::mutex () +{ + return this->mutex_; +} + +template +ACE_INLINE ACE_LOCK& ACE_Cascaded_Multi_Size_Based_Allocator::mutex () +{ + return this->mutex_; +} + template ACE_INLINE int ACE_Malloc_T::ref_counter () { diff --git a/ACE/tests/Allocator_Cascaded_Test.cpp b/ACE/tests/Allocator_Cascaded_Test.cpp new file mode 100755 index 0000000000000..38243af50c8d1 --- /dev/null +++ b/ACE/tests/Allocator_Cascaded_Test.cpp @@ -0,0 +1,542 @@ +// ============================================================================ +// ============================================================================ +// +// = LIBRARY +// tests +// +// = DESCRIPTION +// This program tests the basic APIs supported in +// , and demonstrates how to use it. +// +// = AUTHOR +// Smith Achang +// +// ============================================================================ + +#include "ace/Malloc_T.h" +#include "test_config.h" +#include +#include +#include + +#define ACE_TEST_EXCEPTION_RETURN(expression, message) \ +do \ +{ \ + if (expression) \ + { \ + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT_CHAR_TO_TCHAR (message)), 1);\ + } \ +} \ +while (0) + +#define ACE_ASSERT_RETURN(expression, message) \ +do \ +{ \ + if (!(expression)) \ + { \ + ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT_CHAR_TO_TCHAR (message)), 1); \ + } \ +} \ +while (0) + +#define DELTA(level, initial_n_chunks, min_initial_n_chunks) \ + (initial_n_chunks >> level) > min_initial_n_chunks ? (initial_n_chunks >> level) : min_initial_n_chunks + +static int +run_cascaded_allocator_test () +{ + ACE_DEBUG ((LM_INFO, "%C begin to run ...\n", __func__)); + + size_t const initial_n_chunks = 1; + size_t const chunk_size = sizeof(void*) + 7; + + void *ptr, *ptr1, *ptr2; + size_t nbytes = chunk_size; + size_t pool_sum, old_pool_sum, pool_depth, old_pool_depth; + char initial_value = '\0'; + + ACE_Cascaded_Dynamic_Cached_Allocator alloc (initial_n_chunks, chunk_size); + pool_sum = alloc.pool_sum (); + ACE_TEST_EXCEPTION_RETURN (pool_sum != initial_n_chunks, " initial pool sum must be initial_n_chunks\n"); + + ACE_DEBUG ((LM_INFO, "%C will test unsupported API ...\n", __func__)); + ptr = alloc.calloc (1, chunk_size, initial_value); + ACE_TEST_EXCEPTION_RETURN (ptr != nullptr, + " pool must return nullptr for calloc(size_t n_elem, size_t elem_size, char initial_value) call\n"); + ACE_TEST_EXCEPTION_RETURN(alloc.pool_depth() != initial_n_chunks, + " initial pool depth must keep unchanged for call of unsupported API\n"); + + ACE_DEBUG ((LM_INFO, "%C will test supported calloc API ...\n", __func__)); + ptr = alloc.calloc (nbytes + 1, initial_value); + ACE_TEST_EXCEPTION_RETURN (ptr != nullptr, + " pool must return nullptr for calloc call with bigger nbytes parameter\n"); + ACE_TEST_EXCEPTION_RETURN (alloc.pool_depth () != initial_n_chunks, + " initial pool depth must keep unchanged for call of unsupported API\n"); + + ptr = alloc.calloc (nbytes); + ACE_TEST_EXCEPTION_RETURN (ptr == nullptr, " pool must return valid ptr for calloc call with normal nbytes\n"); + ACE_TEST_EXCEPTION_RETURN (*static_cast (ptr) != 0, " calloc call will clear the memory to zero\n"); + alloc.free (ptr); + + ACE_DEBUG ((LM_INFO, "%C will test supported malloc API ...\n", __func__)); + ptr = alloc.malloc (nbytes + 1); + ACE_TEST_EXCEPTION_RETURN (ptr != nullptr, + " pool must return nullptr for malloc call with bigger nbytes parameter\n"); + + ptr = alloc.malloc(nbytes); + ACE_TEST_EXCEPTION_RETURN (ptr == nullptr, + " pool must return valid ptr for calloc call with normal nbytes\n"); + ACE_TEST_EXCEPTION_RETURN (alloc.pool_depth () != 0, " initial pool depth must be zero\n"); + alloc.free(ptr); + ACE_TEST_EXCEPTION_RETURN (alloc.pool_depth () != initial_n_chunks, + " initial pool depth must be initial_n_chunks after free\n"); + + ACE_DEBUG ((LM_INFO, "%C will test cascaded allocator ...\n", __func__)); + ptr = alloc.malloc (nbytes); + ACE_TEST_EXCEPTION_RETURN (ptr == nullptr, + " pool must return valid ptr, cascaded pool must support to alloc more times firstly\n"); + + ptr1 = alloc.malloc (nbytes); + ACE_TEST_EXCEPTION_RETURN (ptr1 == nullptr, + " pool must return valid ptr, cascaded pool must support to alloc more times secondly\n"); + pool_depth = alloc.pool_depth (); + ACE_TEST_EXCEPTION_RETURN (pool_depth != 1, + " cascaded pool depth must support to alloc twice\n"); + + old_pool_depth = alloc.pool_depth(); + ptr2 = alloc.malloc (nbytes); + ACE_TEST_EXCEPTION_RETURN (ptr2 == nullptr, + " pool must return valid ptr, cascaded pool must support to alloc more times thirdly\n"); + pool_depth = alloc.pool_depth(); + ACE_TEST_EXCEPTION_RETURN (pool_depth != ((2*initial_n_chunks) - old_pool_depth - 1), + " cascaded pool depth must support to alloc three times\n"); + + old_pool_sum = pool_sum; + pool_sum = alloc.pool_sum (); + ACE_TEST_EXCEPTION_RETURN (pool_sum < old_pool_sum, + " cascaded pool sum must be bigger than that of initial pool\n"); + ACE_TEST_EXCEPTION_RETURN (pool_sum != (initial_n_chunks + (2 * initial_n_chunks)), + " cascaded pool sum must be as expected, pool has been enlarged\n"); + + alloc.free (ptr); + alloc.free (ptr1); + alloc.free (ptr2); + + ACE_TEST_EXCEPTION_RETURN (alloc.pool_depth () != (initial_n_chunks + (2 * initial_n_chunks)), + " cascaded pool depth must be three after having freed all malloc ptrs\n"); + + ACE_DEBUG ((LM_INFO, "%C will test cascaded allocator deeply ...\n", __func__)); + old_pool_sum = alloc.pool_sum (); + size_t const totalAllocSum = 8 * 1024; + char cmpvalues[chunk_size]; + char initial_cmp_value = initial_value; + std::vector ptrs; + for (size_t i = 0; i < totalAllocSum; ++i, ++initial_cmp_value) + { + ACE_OS::memset (cmpvalues, initial_cmp_value, chunk_size); + ptr = alloc.calloc (nbytes, initial_cmp_value); + ACE_TEST_EXCEPTION_RETURN (ptr == nullptr, + " pool must return valid ptr for deeply calloc api test with normal nbytes\n"); + ACE_TEST_EXCEPTION_RETURN (ACE_OS::memcmp (ptr, cmpvalues, chunk_size) != 0, + " calloc call must set the memory content as expected\n"); + ptrs.push_back (ptr); + } + + pool_sum = alloc.pool_sum(); + ACE_TEST_EXCEPTION_RETURN (pool_sum <= old_pool_sum, + " pool sum must greater than old pool sum after alloc many chunks for deeply test\n"); + + for (size_t i = 0; i < ptrs.size (); ++i) + { + alloc.free (ptrs[i]); + } + + pool_depth = alloc.pool_depth(); + ACE_TEST_EXCEPTION_RETURN (pool_depth != pool_sum, + " pool depth must equal to pool sum after all chunks has been freed for deeply test\n"); + + for (size_t i = 0; i < totalAllocSum; ++i, ++initial_cmp_value) + { + ACE_OS::memset (cmpvalues, initial_cmp_value, chunk_size); + ptr = alloc.calloc (nbytes, initial_cmp_value); + ACE_TEST_EXCEPTION_RETURN (ptr == nullptr, + " pool must return valid ptr for deeply calloc api test2 with normal nbytes\n"); + ACE_TEST_EXCEPTION_RETURN (ACE_OS::memcmp (ptr, cmpvalues, chunk_size) != 0, + " deeply calloc api test2 must set the memory content as expected\n"); + alloc.free (ptr); + } + + return 0; +} + +static int +run_cascaded_multi_size_based_allocator_basic_test () +{ + ACE_DEBUG ((LM_INFO, "%C begin to run ...\n", __func__)); + + size_t const initial_n_chunks = 11; + size_t const min_initial_n_chunks = 2; + size_t const initial_chunk_size = sizeof (void*) + 5; + size_t const nbytes = initial_chunk_size; + + std::vector ptrs; + void *ptr; + size_t pool_sum, pool_depth; + + char const initial_value = '\0'; + + ACE_Cascaded_Multi_Size_Based_Allocator alloc (initial_n_chunks, initial_chunk_size, min_initial_n_chunks); + pool_sum = alloc.pool_sum (); + ACE_ASSERT_RETURN (pool_sum == initial_n_chunks, " initial pool sum must be initial_n_chunks\n"); + + ACE_DEBUG ((LM_INFO, "%C will test unsupported API ...\n", __func__)); + ptr = alloc.calloc (1, sizeof (void*), initial_value); + ACE_ASSERT_RETURN (ptr == nullptr, + " pool must return nullptr for calloc(size_t n_elem, size_t elem_size, char initial_value) call\n"); + + ptr = alloc.calloc (nbytes, initial_value); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr for calloc(size_t nbytes, char initial_value) call\n"); + char zeros[nbytes] = {}; + ACE_ASSERT_RETURN (ACE_OS::memcmp (ptr, zeros, nbytes) == 0, + " the memory returned by calloc(size_t nbytes, char initial_value) must all be zero!\n"); + alloc.free (ptr); + + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == initial_n_chunks, + " initial pool depth must keep unchanged for call of unsupported API\n"); + + ptr = alloc.malloc (nbytes); + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == (initial_n_chunks - 1), + " initial pool depth must decrease by one\n"); + alloc.free (ptr); + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == initial_n_chunks, + " initial pool depth must restore to initial_n_chunks after free\n"); + + ACE_DEBUG ((LM_INFO, "%C will test first level cascaded allocator ...\n", __func__)); + + for (size_t i = 0; i < (2 * initial_n_chunks); ++i) + { + ptr = alloc.malloc (nbytes); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr, cascaded pool must support to alloc more times firstly\n"); + ptrs.push_back (ptr); + } + + pool_sum = alloc.pool_sum (); + ACE_ASSERT_RETURN (pool_sum == (3 * initial_n_chunks), + " cascaded pool only has two levels, so the pool sum must be 3*initial_n_chunks after alloced 2 * initial_n_chunks times\n"); + + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == (initial_n_chunks), + " cascaded pool only has two levels, so the pool depth must be initial_n_chunks after alloced 2 * initial_n_chunks times\n"); + + for (size_t i = 0; i < ptrs.size(); ++i) + { + alloc.free (ptrs[i]); + } + + pool_sum = alloc.pool_sum (); + ACE_ASSERT_RETURN (pool_sum == (3 * initial_n_chunks), + " first size-based cascaded allocator only has two levels, so the pool sum must be 3*initial_n_chunks after all freed\n"); + + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == (3 * initial_n_chunks), + " first size-based cascaded allocator only has two levels, so the pool depth must be initial_n_chunks after all freed\n"); + + return 0; +} + +static int +run_cascaded_multi_size_based_allocator_hierarchy_test () +{ + ACE_DEBUG ((LM_INFO, "%C begin to run ...\n", __func__)); + + size_t const initial_n_chunks = 11; + size_t const min_initial_n_chunks = 2; + size_t const initial_chunk_size = sizeof (void*) + 5; + + void *ptr; + size_t pool_sum, old_pool_sum, pool_depth, old_pool_depth; + size_t level = 0, delta; + size_t nbytes = initial_chunk_size; + + ACE_Cascaded_Multi_Size_Based_Allocator alloc (initial_n_chunks, initial_chunk_size, min_initial_n_chunks); + ACE_DEBUG ((LM_INFO, "%C Only test the basic malloc API ...\n", __func__)); + ptr = alloc.malloc (nbytes); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr when requesting initial chunk_size\n"); + alloc.free (ptr); + + ACE_DEBUG ((LM_INFO, "%C Will trigger the creation of nested allocator on next level ...\n", __func__)); + level = 1; + old_pool_sum = alloc.pool_sum (); + old_pool_depth = alloc.pool_depth (); + nbytes = initial_chunk_size << level; + ptr = alloc.malloc (nbytes ); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr when requesting 2 * chunk_size\n"); + + pool_sum = alloc.pool_sum (); + delta = DELTA (level, initial_n_chunks, min_initial_n_chunks); + ACE_ASSERT_RETURN (pool_sum == (old_pool_sum + delta), + " pool sum must increase as delta\n"); + + alloc.free (ptr); + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == (old_pool_depth + delta), + " pool depth must increase as delta\n"); + + ACE_DEBUG ((LM_INFO, "%C Will trigger the creation of allocator on more lowwer level ...\n", __func__)); + level = 11; + old_pool_sum = alloc.pool_sum (); + old_pool_depth = alloc.pool_depth (); + nbytes = initial_chunk_size << level; + ptr = alloc.malloc (nbytes); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr when requesting chunk_size << 11\n"); + + pool_sum = alloc.pool_sum (); + delta = DELTA (level, initial_n_chunks, min_initial_n_chunks); + ACE_ASSERT_RETURN (pool_sum == (old_pool_sum + delta), + " pool sum must increase as delta only created request level\n"); + + alloc.free (ptr); + pool_depth = alloc.pool_depth (); + ACE_ASSERT_RETURN (pool_depth == (old_pool_depth + delta), + " pool depth must increase as delta only created request level\n"); + + for (size_t i = 2; i < level; ++i) + { + std::stringstream ss; + old_pool_sum = alloc.pool_sum (); + old_pool_depth = alloc.pool_depth (); + nbytes = initial_chunk_size << i; + ptr = alloc.malloc (nbytes); + ss << " pool must return valid ptr when requesting chunk_size: << " << nbytes << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + + ss.str (""); + pool_sum = alloc.pool_sum (); + delta = DELTA (i, initial_n_chunks, min_initial_n_chunks); + ss << " pool sum must increase as delta: " << delta << " because only created request level: " << i << std::endl; + ACE_ASSERT_RETURN (pool_sum == (old_pool_sum + delta), ss.str().c_str()); + + ss.str (""); + alloc.free (ptr); + pool_depth = alloc.pool_depth (); + ss << " pool depth must increase as delta: " << delta << " because only created request level: " << i << std::endl; + ACE_ASSERT_RETURN (pool_depth == (old_pool_depth + delta), ss.str().c_str()); + } + + ACE_DEBUG ((LM_INFO, "%C Only test the basic calloc API ...\n", __func__)); + char initial_value = '\0'; + size_t const CMP_ARRAY_LEN = initial_chunk_size + 1024; + char cmpvalues[CMP_ARRAY_LEN]; + for (nbytes = initial_chunk_size; nbytes < CMP_ARRAY_LEN; ++nbytes, ++initial_value) + { + ACE_OS::memset (cmpvalues, initial_value, nbytes); + ptr = alloc.calloc (nbytes, initial_value); + ACE_ASSERT_RETURN (ptr != nullptr, + " pool must return valid ptr when calling calloc API with various valid chunk_size\n"); + ACE_ASSERT_RETURN ( + ACE_OS::memcmp (ptr, cmpvalues, nbytes) == 0, + " pool return memory must be the same as cmpvalues when calling calloc API with various valid chunk_size\n"); + alloc.free (ptr); + } + + return 0; +} + +static int +run_cascaded_multi_size_based_allocator_hierarchy_free_test () +{ + ACE_DEBUG ((LM_INFO, "%C begin to run ...\n", __func__)); + + size_t const initial_n_chunks = 11; + size_t const min_initial_n_chunks = 2; + size_t const chunk_size = sizeof (void*) + 5; + + void *ptr; + size_t level = 3; + size_t nbytes = chunk_size << level; + std::stringstream ss; + + ACE_Cascaded_Multi_Size_Based_Allocator alloc (initial_n_chunks, chunk_size, min_initial_n_chunks); + ACE_DEBUG ((LM_INFO, "%C Only test the basic malloc API ...\n", __func__)); + ptr = alloc.malloc (nbytes); + ss << " level: " << level << " size-based cascaded allocator must return valid ptr when requesting normal chunk_size: " << nbytes << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + alloc.free (ptr); + + for (size_t i = 3; i < 6; ++i) + { + size_t pool_sum, old_pool_sum, pool_depth, old_pool_depth; + level = i; + ACE_DEBUG ((LM_INFO, "%C test level: %u size-based cascaded allocator ...\n", __func__, level)); + nbytes = chunk_size << level; + ptr = alloc.malloc (nbytes); + ss.str (""); + ss << " level: " << level + << " size-based cascaded allocator must return valid ptr when requesting normal chunk_size: " << nbytes + << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + alloc.free (ptr); + + ACE_DEBUG ((LM_INFO, "%C test free pos API for level: %u ...\n", __func__, level)); + old_pool_depth = alloc.pool_depth (); + old_pool_sum = alloc.pool_sum (); + std::vector ptrs; + size_t delta = DELTA (level, initial_n_chunks, min_initial_n_chunks); + for (size_t j = 0; j < delta; ++j) + { + ptr = alloc.malloc (nbytes); + ss.str (""); + ss << " level: " << level + << " size-based cascaded allocator must return valid ptr when requesting normal chunk_size: " << nbytes + << " at loop: " << j << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + ptrs.push_back (ptr); + } + + for (size_t k = 0; k < ptrs.size (); ++k) + alloc.free (ptrs[k]); + + ptrs.clear (); + + ACE_DEBUG ((LM_INFO, "%C test level: %u size-based cascaded allocator has freed all initial chunks, when alloc again, the pool sum must not changed ...\n", __func__, level)); + ptr = alloc.malloc (nbytes); + pool_depth = alloc.pool_depth (); + pool_sum = alloc.pool_sum (); + ss.str (""); + ss << " level: " << level << " pool depth: " << old_pool_depth <<" must keep unchanged" << std::endl; + ACE_ASSERT_RETURN (old_pool_depth == (pool_depth + 1), ss.str().c_str()); + + ss.str (""); + ss << " level: " << level << " pool sum: " << old_pool_sum << " must keep unchanged" << std::endl; + ACE_ASSERT_RETURN (old_pool_sum == pool_sum, ss.str().c_str()); + alloc.free (ptr); + } + + return 0; +} + +static int +run_cascaded_multi_size_based_allocator_hierarchy_differential_test () +{ + ACE_DEBUG ((LM_INFO, "%C begin to run ...\n", __func__)); + + size_t const initial_n_chunks = 11; + size_t const min_initial_n_chunks = 2; + size_t const chunk_size = sizeof (void*) + 5; + + ACE_Cascaded_Multi_Size_Based_Allocator alloc (initial_n_chunks, chunk_size, min_initial_n_chunks); + ACE_DEBUG ((LM_INFO, "%C Only test the hierarchy differential ...\n", __func__)); + + for (size_t i = 3; i < 6; ++i) + { + size_t pool_sum, old_pool_sum, pool_depth, old_pool_depth, delta; + std::stringstream ss; + size_t level = i; + old_pool_depth = alloc.pool_depth (); + old_pool_sum = alloc.pool_sum (); + + ACE_DEBUG ((LM_INFO, "%C test level: %u size-based cascaded allocator ...\n", __func__, level)); + size_t nbytes = chunk_size << level; + void *ptr = alloc.malloc (nbytes); + ss.str (""); + ss << " level: " << level + << " size-based cascaded allocator must return valid ptr when requesting normal chunk_size: " << nbytes + << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + + if (i == 3) + { + pool_depth = alloc.pool_depth (); + pool_sum = alloc.pool_sum (); + delta = DELTA (level, initial_n_chunks, min_initial_n_chunks); + + ss.str (""); + ss << " level: " << (level) << " must be created, pool depth must increased by " << delta << std::endl; + ACE_ASSERT_RETURN ((old_pool_depth + delta - 1) == pool_depth, ss.str().c_str()); + + ss.str (""); + ss << " level: " << (level) << " must be created, pool sum must increased by " << delta << std::endl; + ACE_ASSERT_RETURN ((old_pool_sum + delta) == pool_sum, ss.str().c_str()); + alloc.free (ptr); + } + + ACE_DEBUG ((LM_INFO, "%C test alloc bytes greater than level: %u ...\n", __func__, level)); + old_pool_depth = alloc.pool_depth (); + old_pool_sum = alloc.pool_sum (); + + size_t const next_level = level + 1; + delta = DELTA (next_level, initial_n_chunks, min_initial_n_chunks); + ptr = alloc.malloc (nbytes + 1); + alloc.free (ptr); + pool_depth = alloc.pool_depth (); + pool_sum = alloc.pool_sum (); + + ss.str (""); + ss << " next level: " << next_level << " must be created, pool depth must increased by " << delta << std::endl; + ACE_ASSERT_RETURN ((old_pool_depth + delta) == pool_depth, ss.str().c_str()); + + ss.str (""); + ss << " next level: " << next_level << " must be created, pool sum must increased by " << delta << std::endl; + ACE_ASSERT_RETURN ((old_pool_sum + delta) == pool_sum, ss.str().c_str()); + + size_t const next_nbytes = chunk_size << next_level; + old_pool_depth = alloc.pool_depth (); + old_pool_sum = alloc.pool_sum (); + std::vector ptrs; + for (size_t j = nbytes + 1; j < next_nbytes; ++j) + { + ptr = alloc.malloc (j); + ss.str (""); + ss << " level: " << next_level + << " size-based cascaded allocator must return valid ptr when requesting normal chunk_size: " << j + << std::endl; + ACE_ASSERT_RETURN (ptr != nullptr, ss.str().c_str()); + ptrs.push_back (ptr); + } + + for (size_t k = 0; k < ptrs.size(); ++k) + { + alloc.free (ptrs[k]); + } + ptrs.clear (); + + ss.str (""); + ss << " next level: " << next_level << " pool depth must unchanged" << std::endl; + ACE_ASSERT_RETURN ((old_pool_depth) == pool_depth, ss.str().c_str()); + + ss.str (""); + ss << " next level: " << next_level << " pool sum must unchanged" << std::endl; + ACE_ASSERT_RETURN ((old_pool_sum) == pool_sum, ss.str().c_str()); + } + + return 0; +} + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Allocator_Cascaded_Test")); + + int retval = 0; + + ACE_DEBUG ((LM_INFO, "%C Run the tests for Cascaded_Allocator ...\n", __func__)); + retval += run_cascaded_allocator_test(); + + ACE_DEBUG ((LM_INFO, "%C Run the tests for Cascaded_Multi_Size_Based_Allocator ...\n", __func__)); + retval += run_cascaded_multi_size_based_allocator_basic_test(); + retval += run_cascaded_multi_size_based_allocator_hierarchy_test (); + retval += run_cascaded_multi_size_based_allocator_hierarchy_free_test (); + retval += run_cascaded_multi_size_based_allocator_hierarchy_differential_test (); + + ACE_END_TEST; + + return retval; +} diff --git a/ACE/tests/run_test.lst b/ACE/tests/run_test.lst index c8b018e3eb6cd..118c1ce71dd72 100644 --- a/ACE/tests/run_test.lst +++ b/ACE/tests/run_test.lst @@ -16,6 +16,7 @@ ACE_Init_Test: MFC ACE_Test Aio_Platform_Test +Allocator_Cascaded_Test Arg_Shifter_Test ARGV_Test Array_Map_Test diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc index c98a938e1844a..5e216233b1e66 100644 --- a/ACE/tests/tests.mpc +++ b/ACE/tests/tests.mpc @@ -145,6 +145,14 @@ project(Aio Platform Test) : acetest { } } +project(Allocator Cascaded Test) : acetest { + avoids += ace_for_tao + exename = Allocator_Cascaded_Test + Source_Files { + Allocator_Cascaded_Test.cpp + } +} + project(Arg Shifter Test) : acetest { exename = Arg_Shifter_Test Source_Files {