Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cascaded allocator #2113

Open
wants to merge 46 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bd320b1
can compiled successfully on Windows Plat
smithAchang Sep 3, 2023
37dc8f4
Allocator_Cascaded_Test.cpp增加
smithAchang Sep 3, 2023
c61b9be
add the 2*sum(Allocator of hierarchy) testing case
smithAchang Sep 4, 2023
6166f88
bin/fuzz.pl find trailing whitespace
smithAchang Sep 4, 2023
32d3d1f
bin/fuzz.pl find trailing whitespace 2
smithAchang Sep 4, 2023
e2a5511
compiler error
smithAchang Sep 4, 2023
6835890
dsfdsdfMerge branch 'cascadedAllocator' of github.com:smithAchang/ACE…
smithAchang Sep 4, 2023
150eb7b
use std::vector
smithAchang Sep 4, 2023
089af45
linux compiling error & fix issue
smithAchang Sep 5, 2023
ac87bd4
according the routine of test framework
smithAchang Sep 5, 2023
b71f82d
key design comment for free API
smithAchang Sep 5, 2023
34abb6e
fix space indent & const member field
smithAchang Sep 5, 2023
cf39680
using instead of typedef, will be fitter for template declaration
smithAchang Sep 5, 2023
78e7165
remove duplicate empty lines
smithAchang Sep 5, 2023
e5e55bc
free protected when malloc in constructor failed
smithAchang Sep 5, 2023
00016bf
1. add assert for free API
smithAchang Sep 5, 2023
912d9db
add comments for ACE_NEW fail in constructor
smithAchang Sep 6, 2023
833bc87
Merge branch 'master' into cascadedAllocator
smithAchang Sep 6, 2023
40675b0
fix ""One line, indent is always 2 spaces
smithAchang Sep 7, 2023
148734d
Merge branch 'cascadedAllocator' of github.com:smithAchang/ACE_TAO in…
smithAchang Sep 7, 2023
6e9a17c
for g++ -fno-implicit-templates consideration
smithAchang Sep 8, 2023
d065069
implement the dump API
smithAchang Sep 16, 2023
eba85a4
fix for statement of dump API
smithAchang Sep 16, 2023
1e1862d
fix trailing whitespace
smithAchang Sep 16, 2023
0f26ecb
add hierarchy_.size () for dump API
smithAchang Sep 18, 2023
4a7fcd0
1、fix some coding style using this keyword to distinguish vars
smithAchang Sep 22, 2023
cf686b3
add the pool_sum api
smithAchang Sep 22, 2023
4c27ab0
1、fix constructor description
smithAchang Sep 23, 2023
8210ac0
1、split ACE_NEW* with empty line, the macro function may end the flow
smithAchang Sep 23, 2023
e8d9b51
1、fix unsupported API return nullptr
smithAchang Sep 25, 2023
63e543f
add deeply test case for calloc API
smithAchang Sep 26, 2023
d4e7d14
modify growth strategy to exponential growth when hierarchy grows fo…
smithAchang Sep 29, 2023
874d9cb
keep the consistent to cascaded malloc branch
smithAchang Sep 29, 2023
92066a1
add exception safety for the growth of chunk sum
smithAchang Sep 29, 2023
4a9c114
fix the exception safety for calling vector push_back API
smithAchang Sep 29, 2023
8450156
Using std::unique_ptr will be more exception-safe literally
smithAchang Sep 29, 2023
0c8067c
delete defence codes
smithAchang Sep 29, 2023
cc4053c
delete unused temp stack var
smithAchang Sep 29, 2023
ac5f611
fix invalid document of class
smithAchang Sep 29, 2023
fec93be
fix coding style of comment
smithAchang Oct 8, 2023
42b409e
fix for right const coding style
smithAchang Oct 8, 2023
a837b5d
format using clang-format
smithAchang Oct 8, 2023
c9ead44
fix for coding style of function call
smithAchang Oct 8, 2023
021ef62
optimization for cascaded allocator considering the character that on…
smithAchang Jan 13, 2024
92c3499
Merge branch 'master' into cascadedAllocator
smithAchang Jan 13, 2024
b84e0c4
modify the branch judgement of the last allocator using const var
smithAchang Apr 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ACE/MPC
Submodule MPC added at 307f1f
215 changes: 215 additions & 0 deletions ACE/ace/Malloc_T.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,221 @@ ACE_Dynamic_Cached_Allocator<ACE_LOCK>::free (void * ptr)
this->free_list_.add ((ACE_Cached_Mem_Pool_Node<char> *) ptr);
}

template <class ACE_LOCK>
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialize tmp

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the temp var will be assigned or call flow is ended by ACE_NEW macro

Should it be initialized?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the temp var will be assigned or call flow is ended by ACE_NEW macro

Should it be initialized?

// 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_));
smithAchang marked this conversation as resolved.
Show resolved Hide resolved

// Consider the exception of vector push_back call
this->hierarchy_.push_back(tmp);
if (0 == this->hierarchy_.size())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when push_back fails it will throw, maybe use std::unique_ptr?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These APIs have strong exception safety guarantee, so there is no need to use std::unique_ptr.

Is it true ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, I can see the result of these calls to judge whether potential exceptions have occurred

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://en.cppreference.com/w/cpp/language/exceptions, push_back can throw, when it does the state of the std::vector is guaranteed at that moment, but it will not just return. The exception should go back to the caller to my idea, your allocator should not leak when push_back (or any operation it uses) throws

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when using unique_ptr the check after the push_back seems invalid

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used std::unique_ptr for idiom in new commit

But for a vector of pointer, I think sdt::vector can keep strong exception guarantee.

If an exception is thrown (which can be due to Allocator::allocate() or element copy/move constructor/assignment), this > function has no effect ([strong exception guarantee]> (https://en.cppreference.com/w/cpp/language/exceptions#Exception_safety)).


Strong exception guarantee — If the function throws an exception, the state of the program is rolled back to the state > just before the function call (for example, [std::vector::push_back]>(https://en.cppreference.com/w/cpp/container/vector/push_back)).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, Your idea is right!

The APIs provide strong exception guarantee, but not Nothrow

I will delete the defence codes

{
delete tmp;
return;
}

// Increase the chunk sum if all points having potential risk of exception is passed.
this->chunk_sum_ += tmp->pool_depth ();
}

template <class ACE_LOCK>
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::~ACE_Cascaded_Dynamic_Cached_Allocator ()
{
for (size_t h = 0; h < this->hierarchy_.size(); h++)
{
delete this->hierarchy_[h];
}

this->hierarchy_.clear();
}

template <class ACE_LOCK> void *
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::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));

void * ptr = nullptr;

for (size_t h = 0; h < this->hierarchy_.size(); h++)
{
ptr = this->hierarchy_[h]->malloc(nbytes);
if(ptr != nullptr)
break;
}

if(ptr == nullptr)
{
comb_alloc_ptr tmp;
ACE_NEW_RETURN (tmp, comb_alloc_type(this->initial_n_chunks_ * (1 << this->hierarchy_.size()),
this->chunk_size_),
nullptr);

// Consider the exception of vector push_back call
const auto old_size = this->hierarchy_.size();
this->hierarchy_.push_back(tmp);
if (old_size == this->hierarchy_.size())
{
delete tmp;
return nullptr;
}

// Increase the chunk sum if all points having potential risk of exception is passed.
this->chunk_sum_ += tmp->pool_depth ();
ptr = tmp->malloc(nbytes);
}

return ptr;
}

template <class ACE_LOCK> void *
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::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 <class ACE_LOCK> void *
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::calloc (size_t, size_t, char)
{
ACE_NOTSUP_RETURN (nullptr);
}

template <class ACE_LOCK> void
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::free (void * ptr)
{
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 (ptr != nullptr && this->hierarchy_.size() > 0)
this->hierarchy_[0]->free(ptr);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::remove ()
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::bind (const char *, void *, int)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::trybind (const char *, void *&)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::find (const char *, void *&)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::find (const char *)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::unbind (const char *)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::unbind (const char *, void *&)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::sync (ssize_t, int)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::sync (void *, size_t, int)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::protect (ssize_t, int)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> int
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::protect (void *, size_t, int)
{
ACE_NOTSUP_RETURN (-1);
}

template <class ACE_LOCK> size_t
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::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++)
{
pool_depth += this->hierarchy_[h]->pool_depth();
}

return pool_depth;
}

template <class ACE_LOCK> void
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::dump () const
{
#if defined (ACE_HAS_DUMP)
ACE_TRACE ("ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::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 */
}

ACE_ALLOC_HOOK_DEFINE_Tmcc (ACE_Malloc_T)

template <class MALLOC> void *
Expand Down
109 changes: 108 additions & 1 deletion ACE/ace/Malloc_T.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* @file Malloc_T.h
*
* @author Douglas C. Schmidt <[email protected]> and
* Irfan Pyarali <[email protected]>
* Irfan Pyarali <[email protected]> and
* smithAchang <[email protected]>
*/
//==========================================================================

Expand All @@ -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
Expand All @@ -24,6 +26,8 @@
#include "ace/Free_List.h"
#include "ace/Guard_T.h"

#include <vector>

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

/**
Expand Down Expand Up @@ -203,6 +207,109 @@ 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 <code> sizeof (void*) </code> 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
* <code> init_n_chunks* the sum of current allocators </code> 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_LOCK>
class ACE_Cascaded_Dynamic_Cached_Allocator : public ACE_Allocator
{
public:
// Useful STL-style traits.
using comb_alloc_type = ACE_Dynamic_Cached_Allocator<ACE_Null_Mutex>;
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 ();
smithAchang marked this conversation as resolved.
Show resolved Hide resolved
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<comb_alloc_ptr> 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_Allocator_Adapter
*
Expand Down
14 changes: 14 additions & 0 deletions ACE/ace/Malloc_T.inl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ ACE_Dynamic_Cached_Allocator<ACE_LOCK>::pool_depth ()
return this->free_list_.size ();
}

template <class ACE_LOCK> ACE_INLINE size_t
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::pool_sum ()
{
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0));

return this->chunk_sum_;
}

template <class ACE_LOCK> ACE_INLINE ACE_LOCK &
ACE_Cascaded_Dynamic_Cached_Allocator<ACE_LOCK>::mutex ()
{
return this->mutex_;
}

template <ACE_MEM_POOL_1, class ACE_LOCK, class ACE_CB> ACE_INLINE int
ACE_Malloc_T<ACE_MEM_POOL_2, ACE_LOCK, ACE_CB>::ref_counter ()
{
Expand Down
Loading