corelib/tests/alloc-pool.cc

333 lines
7.3 KiB
C++
Raw Normal View History

#include <lw/lib/Alloc.hh>
#include <lw/lib/Pointers.hh>
#include <cppunit/extensions/HelperMacros.h>
using namespace lw;
class AllocPoolTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( AllocPoolTest );
CPPUNIT_TEST( testUnused );
CPPUNIT_TEST( testAllocPartial );
CPPUNIT_TEST( testAllocFull );
CPPUNIT_TEST( testAllocNewList );
CPPUNIT_TEST( testFreePartialToFree );
CPPUNIT_TEST( testFreePartialToPartial );
CPPUNIT_TEST( testFreeFullToPartial );
CPPUNIT_TEST( testFreeLists );
CPPUNIT_TEST( testFreeFragmented );
CPPUNIT_TEST( testFreeMaxLists );
CPPUNIT_TEST( testReallocation );
CPPUNIT_TEST_SUITE_END( );
public:
void setUp( ) override;
void testUnused( );
void testAllocPartial( );
void testAllocFull( );
void testAllocNewList( );
void testFreePartialToFree( );
void testFreePartialToPartial( );
void testFreeFullToPartial( );
void testFreeLists( );
void testFreeFragmented( );
void testFreeMaxLists( );
void testReallocation( );
};
CPPUNIT_TEST_SUITE_REGISTRATION( AllocPoolTest );
/*----------------------------------------------------------------------------*/
namespace {
class T_Test_
{
public:
static size_t counters[ 256 ];
uint8_t index;
T_Test_( ) = delete;
T_Test_( const uint8_t v ) noexcept
: index( v )
{ counters[ index ] ++; }
T_Test_( T_Test_ const& other ) noexcept
: index( other.index )
{ counters[ index ] ++; }
T_Test_( T_Test_&& other ) noexcept
: index( other.index )
{ counters[ index ] ++; }
~T_Test_( )
{ counters[ index ] --; }
void* operator new( size_t count ) noexcept;
void operator delete( void* object ) noexcept;
static size_t total( ) noexcept
{
size_t sum = 0;
for ( auto i = 0 ; i < 255 ; i ++ ) {
sum += counters[ i ];
}
return sum;
}
};
M_CLASS_POINTERS( Test_ );
size_t T_Test_::counters[ 256 ];
static constexpr size_t PerList_ = 15;
static constexpr size_t MaxFreeLists_ = 4;
static constexpr size_t MFLObjects_ = PerList_ * MaxFreeLists_;
using T_Pool_ = T_PoolAllocator<
sizeof( T_Test_ ) , alignof( T_Test_ ) ,
PerList_ , MaxFreeLists_ >;
static T_OwnPtr< T_Pool_ > Pool_;
void InitPool_( )
{
Pool_ = NewOwned< T_Pool_ >( );
}
void KillPool_( )
{
Pool_.clear( );
}
void* T_Test_::operator new(
const size_t count ) noexcept
{
assert( Pool_ );
return Pool_->allocate( count );
}
void T_Test_::operator delete(
void* object ) noexcept
{
assert( Pool_ );
Pool_->free( object );
}
}
#define M_CHECK_LISTS_( T , F , U ) \
do { \
CPPUNIT_ASSERT_EQUAL( size_t( T ) , Pool_->countFreeLists( ) ); \
CPPUNIT_ASSERT_EQUAL( size_t( F ) , Pool_->countPartialLists( ) ); \
CPPUNIT_ASSERT_EQUAL( size_t( U ) , Pool_->countFullLists( ) ); \
} while ( 0 )
#define M_CHECK_USAGE_( T , F , U ) \
do { \
size_t _t_ , _f_ , _u_; \
Pool_->getUsage( _t_ , _f_ , _u_ ); \
CPPUNIT_ASSERT_EQUAL( size_t( T ) , _t_ ); \
CPPUNIT_ASSERT_EQUAL( size_t( F ) , _f_ ); \
CPPUNIT_ASSERT_EQUAL( size_t( U ) , _u_ ); \
} while ( 0 )
#define M_CHECK_COUNT_( N ) \
CPPUNIT_ASSERT_EQUAL( size_t( N ) , T_Test_::total( ) )
void AllocPoolTest::setUp( )
{
memset( T_Test_::counters , 0 , sizeof( T_Test_::counters ) );
}
/*----------------------------------------------------------------------------*/
void AllocPoolTest::testUnused( )
{
InitPool_( );
M_CHECK_LISTS_( 1 , 0 , 0 );
M_CHECK_USAGE_( PerList_ , PerList_ , 0 );
KillPool_( );
M_CHECK_COUNT_( 0 );
}
/*----------------------------------------------------------------------------*/
void AllocPoolTest::testAllocPartial( )
{
InitPool_( );
{
OP_Test_ test( NewOwned< T_Test_ >( 0 ) );
M_CHECK_COUNT_( 1 );
M_CHECK_LISTS_( 0 , 1 , 0 );
M_CHECK_USAGE_( PerList_ , PerList_ - 1 , 1 );
}
KillPool_( );
M_CHECK_COUNT_( 0 );
}
void AllocPoolTest::testAllocFull( )
{
InitPool_( );
{
OP_Test_ test[ PerList_ ];
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
test[ i ] = NewOwned< T_Test_ >( i );
}
M_CHECK_COUNT_( PerList_ );
M_CHECK_LISTS_( 0 , 0 , 1 );
M_CHECK_USAGE_( PerList_ , 0 , PerList_ );
}
KillPool_( );
M_CHECK_COUNT_( 0 );
}
void AllocPoolTest::testAllocNewList( )
{
InitPool_( );
{
OP_Test_ test[ PerList_ + 1 ];
for ( auto i = 0u ; i <= PerList_ ; i ++ ) {
test[ i ] = NewOwned< T_Test_ >( i );
}
M_CHECK_COUNT_( PerList_ + 1 );
M_CHECK_LISTS_( 0 , 1 , 1 );
M_CHECK_USAGE_( PerList_ * 2 , PerList_ - 1 , PerList_ + 1 );
}
KillPool_( );
M_CHECK_COUNT_( 0 );
}
/*----------------------------------------------------------------------------*/
void AllocPoolTest::testFreePartialToFree( )
{
InitPool_( );
{
OP_Test_ obj( NewOwned< T_Test_ >( 0 ) );
obj.clear( );
M_CHECK_COUNT_( 0 );
M_CHECK_LISTS_( 1 , 0 , 0 );
M_CHECK_USAGE_( PerList_ , PerList_ , 0 );
}
KillPool_( );
}
void AllocPoolTest::testFreePartialToPartial( )
{
InitPool_( );
{
OP_Test_ persist( NewOwned< T_Test_ >( 0 ) );
OP_Test_ test( NewOwned< T_Test_ >( 1 ) );
test.clear( );
M_CHECK_COUNT_( 1 );
M_CHECK_LISTS_( 0 , 1 , 0 );
M_CHECK_USAGE_( PerList_ , PerList_ - 1 , 1 );
}
KillPool_( );
}
void AllocPoolTest::testFreeFullToPartial( )
{
InitPool_( );
{
OP_Test_ objs[ PerList_ ];
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
objs[ i ] = NewOwned< T_Test_ >( i );
}
objs[ PerList_ - 1 ].clear( );
M_CHECK_COUNT_( PerList_ - 1 );
M_CHECK_LISTS_( 0 , 1 , 0 );
M_CHECK_USAGE_( PerList_ , 1 , PerList_ - 1 );
}
KillPool_( );
}
/*----------------------------------------------------------------------------*/
void AllocPoolTest::testFreeLists( )
{
InitPool_( );
{
OP_Test_ obj[ MFLObjects_ ];
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
obj[ i ] = NewOwned< T_Test_ >( i );
}
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
obj[ i ].clear( );
}
M_CHECK_COUNT_( 0 );
M_CHECK_LISTS_( MaxFreeLists_ , 0 , 0 );
M_CHECK_USAGE_( MFLObjects_ , MFLObjects_ , 0 );
}
KillPool_( );
}
void AllocPoolTest::testFreeFragmented( )
{
InitPool_( );
{
OP_Test_ obj[ MFLObjects_ ];
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
obj[ i ] = NewOwned< T_Test_ >( i );
}
for ( auto i = 0u ; i < MaxFreeLists_ ; i ++ ) {
obj[ i * PerList_ ].clear( );
}
M_CHECK_COUNT_( MFLObjects_ - MaxFreeLists_ );
M_CHECK_LISTS_( 0 , MaxFreeLists_ , 0 );
M_CHECK_USAGE_( MFLObjects_ , MaxFreeLists_ , MFLObjects_ - MaxFreeLists_ );
}
KillPool_( );
}
void AllocPoolTest::testFreeMaxLists( )
{
InitPool_( );
{
OP_Test_ obj[ MFLObjects_ + PerList_ ];
for ( auto i = 0u ; i < MFLObjects_ + PerList_ ; i ++ ) {
obj[ i ] = NewOwned< T_Test_ >( i );
}
for ( auto i = 0u ; i < MFLObjects_ + PerList_ ; i ++ ) {
obj[ i ].clear( );
}
M_CHECK_COUNT_( 0 );
M_CHECK_LISTS_( MaxFreeLists_ , 0 , 0 );
M_CHECK_USAGE_( MFLObjects_ , MFLObjects_ , 0 );
}
KillPool_( );
}
/*----------------------------------------------------------------------------*/
void AllocPoolTest::testReallocation( )
{
InitPool_( );
{
OP_Test_ obj[ PerList_ ];
T_Test_* ptr[ PerList_ ];
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
obj[ i ] = NewOwned< T_Test_ >( i );
ptr[ i ] = obj[ i ].get( );
}
for ( auto i = 1u ; i < PerList_ ; i += 2 ) {
obj[ i ].clear( );
}
for ( auto i = 1u ; i < PerList_ ; i += 2 ) {
obj[ i ] = NewOwned< T_Test_ >( i );
CPPUNIT_ASSERT( obj[ i ].get( ) == ptr[ i ] );
}
M_CHECK_LISTS_( 0 , 0 , 1 );
M_CHECK_USAGE_( PerList_ , 0 , PerList_ );
}
KillPool_( );
}