Memory pool usage tracking + size optimization

This commit is contained in:
Pavel Kirienko
2015-06-22 21:02:41 +03:00
parent ba2f7de9d8
commit e99120c257
4 changed files with 59 additions and 30 deletions
+48 -28
View File
@@ -26,13 +26,13 @@ public:
virtual void* allocate(std::size_t size) = 0;
virtual void deallocate(const void* ptr) = 0;
virtual std::size_t getNumBlocks() const = 0;
virtual uint16_t getNumBlocks() const = 0;
};
/**
* Classic implementation of a pool allocator (Meyers).
*/
template <std::size_t PoolSize, std::size_t BlockSize>
template <std::size_t PoolSize, uint8_t BlockSize>
class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable
{
union Node
@@ -50,18 +50,29 @@ class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable
Node _aligner3;
} pool_;
uint16_t used_;
uint16_t max_used_;
public:
static const unsigned NumBlocks = unsigned(PoolSize / BlockSize);
static const uint16_t NumBlocks = PoolSize / BlockSize;
PoolAllocator();
virtual void* allocate(std::size_t size);
virtual void deallocate(const void* ptr);
virtual std::size_t getNumBlocks() const { return NumBlocks; }
virtual uint16_t getNumBlocks() const { return NumBlocks; }
unsigned getNumFreeBlocks() const;
unsigned getNumUsedBlocks() const { return NumBlocks - getNumFreeBlocks(); }
/**
* Return the number of blocks that are currently allocated/unallocated.
*/
uint16_t getNumUsedBlocks() const { return used_; }
uint16_t getNumFreeBlocks() const { return static_cast<uint16_t>(NumBlocks - used_); }
/**
* Returns the maximum number of blocks that were ever allocated at the same time.
*/
uint16_t getPeakNumUsedBlocks() const { return max_used_; }
};
/**
@@ -70,13 +81,13 @@ public:
class LimitedPoolAllocator : public IPoolAllocator
{
IPoolAllocator& allocator_;
const std::size_t max_blocks_;
std::size_t used_blocks_;
const uint16_t max_blocks_;
uint16_t used_blocks_;
public:
LimitedPoolAllocator(IPoolAllocator& allocator, std::size_t max_blocks)
: allocator_(allocator)
, max_blocks_(max_blocks)
, max_blocks_(static_cast<uint16_t>(min<std::size_t>(max_blocks, 0xFFFFU)))
, used_blocks_(0)
{
UAVCAN_ASSERT(max_blocks_ > 0);
@@ -85,7 +96,7 @@ public:
virtual void* allocate(std::size_t size);
virtual void deallocate(const void* ptr);
virtual std::size_t getNumBlocks() const;
virtual uint16_t getNumBlocks() const;
};
// ----------------------------------------------------------------------------
@@ -93,10 +104,18 @@ public:
/*
* PoolAllocator<>
*/
template <std::size_t PoolSize, std::size_t BlockSize>
PoolAllocator<PoolSize, BlockSize>::PoolAllocator()
: free_list_(reinterpret_cast<Node*>(pool_.bytes))
template <std::size_t PoolSize, uint8_t BlockSize>
const uint16_t PoolAllocator<PoolSize, BlockSize>::NumBlocks;
template <std::size_t PoolSize, uint8_t BlockSize>
PoolAllocator<PoolSize, BlockSize>::PoolAllocator() :
free_list_(reinterpret_cast<Node*>(pool_.bytes)),
used_(0),
max_used_(0)
{
// The limit is imposed by the width of the pool usage tracking variables.
StaticAssert<((PoolSize / BlockSize) <= 0xFFFFU)>::check();
(void)std::memset(pool_.bytes, 0, PoolSize);
for (unsigned i = 0; (i + 1) < (NumBlocks - 1 + 1); i++) // -Werror=type-limits
{
@@ -106,42 +125,43 @@ PoolAllocator<PoolSize, BlockSize>::PoolAllocator()
free_list_[NumBlocks - 1].next = NULL;
}
template <std::size_t PoolSize, std::size_t BlockSize>
template <std::size_t PoolSize, uint8_t BlockSize>
void* PoolAllocator<PoolSize, BlockSize>::allocate(std::size_t size)
{
if (free_list_ == NULL || size > BlockSize)
{
return NULL;
}
void* pmem = free_list_;
free_list_ = free_list_->next;
// Statistics
UAVCAN_ASSERT(used_ < NumBlocks);
used_++;
if (used_ > max_used_)
{
max_used_ = used_;
}
return pmem;
}
template <std::size_t PoolSize, std::size_t BlockSize>
template <std::size_t PoolSize, uint8_t BlockSize>
void PoolAllocator<PoolSize, BlockSize>::deallocate(const void* ptr)
{
if (ptr == NULL)
{
return;
}
Node* p = static_cast<Node*>(const_cast<void*>(ptr));
p->next = free_list_;
free_list_ = p;
}
template <std::size_t PoolSize, std::size_t BlockSize>
unsigned PoolAllocator<PoolSize, BlockSize>::getNumFreeBlocks() const
{
unsigned num = 0;
Node* p = free_list_;
while (p)
{
num++;
UAVCAN_ASSERT(num <= NumBlocks);
p = p->next;
}
return num;
// Statistics
UAVCAN_ASSERT(used_ > 0);
used_--;
}
}