Replacing some integral typedefs with standard types
[libcds.git] / tests / unit / alloc / hoard_threadtest.cpp
1 //$$CDS-header$$
2
3 // Hoard threadtest allocator test
4
5 #include "alloc/michael_allocator.h"
6
7 #include <cds/os/timer.h>
8 #include <cds/os/topology.h>
9
10 #include "cppunit/thread.h"
11
12 namespace memory {
13
14     static size_t s_nPassCount = 1000;
15     static size_t s_nBlockCount = 10000;
16     static size_t s_nMinBlockSize = 16;
17     static size_t s_nMaxBlockSize = 1024;
18     static size_t s_nMaxThreadCount = 32;
19
20     static size_t s_nPassPerThread;
21
22     static size_t s_nCurBlockSize;
23
24 #    define TEST_ALLOC(X, CLASS)            void X() { test< CLASS >( false )    ; }
25 #    define TEST_ALLOC_STAT(X, CLASS)       void X() { test< CLASS >( true )    ; }
26
27     /*
28         In Threadtest, each thread performs s_nPassCount iterations of allocating s_nBlockCount
29         s_nCurBlockSize-byte blocks and then freeing them in order. The benchmarks capture
30         allocator latency and scalability under regular private allocation patterns.
31     */
32     class Hoard_ThreadTest: public CppUnitMini::TestCase
33     {
34         template <class ALLOC>
35         class Thread: public CppUnitMini::TestThread
36         {
37             ALLOC&      m_Alloc;
38             typedef typename ALLOC::value_type  value_type;
39             value_type **     m_arr;
40
41             virtual Thread *    clone()
42             {
43                 return new Thread( *this );
44             }
45         public:
46
47         public:
48             Thread( CppUnitMini::ThreadPool& pool, ALLOC& a )
49                 : CppUnitMini::TestThread( pool )
50                 , m_Alloc( a )
51             {}
52             Thread( Thread& src )
53                 : CppUnitMini::TestThread( src )
54                 , m_Alloc( src.m_Alloc )
55             {}
56
57             Hoard_ThreadTest&  getTest()
58             {
59                 return reinterpret_cast<Hoard_ThreadTest&>( m_Pool.m_Test );
60             }
61
62             virtual void init()
63             {
64                 cds::threading::Manager::attachThread();
65                 m_arr = new value_type *[s_nBlockCount];
66             }
67             virtual void fini()
68             {
69                 delete [] m_arr;
70                 cds::threading::Manager::detachThread();
71             }
72
73             virtual void test()
74             {
75                 size_t nSize = s_nCurBlockSize / sizeof(value_type);
76                 for ( size_t nPass = 0; nPass < s_nPassPerThread; ++nPass ) {
77                     value_type ** pCell = m_arr;
78                     for ( size_t i = 0; i < s_nBlockCount; ++i, ++pCell ) {
79                         *pCell = m_Alloc.allocate( nSize, nullptr );
80                         CPPUNIT_ASSERT( *pCell != nullptr );
81
82                         if ( nSize < 32 )
83                             memset( *pCell, 0, nSize );
84                         else {
85                             memset( *pCell, 0, 16 );
86                             memset( ((char *)(*pCell)) + nSize * sizeof(value_type) - 16, 0, 16 );
87                         }
88
89                         CPPUNIT_ASSERT( (reinterpret_cast<uintptr_t>(*pCell) & (ALLOC::alignment - 1)) == 0 );
90                     }
91                     pCell = m_arr;
92                     for ( size_t i = 0; i < s_nBlockCount; ++i, ++pCell ) {
93                         m_Alloc.deallocate( *pCell, 1 );
94                     }
95                 }
96             }
97         };
98
99         template <class ALLOC>
100         void test( size_t nThreadCount )
101         {
102             ALLOC alloc;
103             cds::OS::Timer    timer;
104
105             CPPUNIT_MSG( "Thread count=" << nThreadCount );
106             s_nPassPerThread = s_nPassCount / nThreadCount;
107
108             CppUnitMini::ThreadPool pool( *this );
109             pool.add( new Thread<ALLOC>( pool, alloc ), nThreadCount );
110             pool.run();
111             CPPUNIT_MSG( "  Duration=" << pool.avgDuration() );
112         }
113
114         template <class ALLOC>
115         void test( bool bStat)
116         {
117             s_nCurBlockSize = s_nMinBlockSize;
118             while ( s_nCurBlockSize <= s_nMaxBlockSize ) {
119                 CPPUNIT_MSG( "Block size=" << s_nCurBlockSize << ", block count=" << s_nBlockCount << ", pass count=" << s_nPassCount << " per thread" );
120                 for ( size_t nThreadCount = 1; nThreadCount <= s_nMaxThreadCount; nThreadCount *= 2 ) {
121                     summary_stat stBegin;
122                     if ( bStat )
123                         ALLOC::stat(stBegin);
124
125                     test<ALLOC>( nThreadCount );
126
127                     summary_stat    stEnd;
128                     if ( bStat ) {
129                         ALLOC::stat( stEnd );
130
131                         std::cout << "\nStatistics:\n"
132                             << stEnd
133 ;
134                         stEnd -= stBegin;
135                         std::cout << "\nDelta statistics:\n"
136                             << stEnd
137 ;
138                     }
139                 }
140                 s_nCurBlockSize *= 2;
141             }
142         }
143
144         void setUpParams( const CppUnitMini::TestCfg& cfg )
145         {
146             s_nPassCount = cfg.getULong( "PassCount", 1000 );
147             s_nBlockCount = cfg.getULong( "BlockCount", 10000 );
148             s_nMinBlockSize = cfg.getULong( "MinBlockSize", 16 );
149             s_nMaxBlockSize = cfg.getULong( "MaxBlockSize", 1024 );
150             s_nMaxThreadCount = cfg.getUInt( "MaxThreadCount", 32 );
151             if ( s_nMaxThreadCount == 0 )
152                 s_nMaxThreadCount = cds::OS::topology::processor_count() * 2;
153         }
154
155         typedef MichaelAlignHeap_Stat<int, 64>      t_MichaelAlignHeap_Stat;
156         typedef MichaelAlignHeap_NoStat<int,64>     t_MichaelAlignHeap_NoStat;
157         typedef system_aligned_allocator<int, 64>   t_system_aligned_allocator;
158
159         TEST_ALLOC_STAT( michael_heap_stat,      MichaelHeap_Stat<int> )
160         TEST_ALLOC( michael_heap_nostat,    MichaelHeap_NoStat<int> )
161         TEST_ALLOC( std_alloc,              std_allocator<int> )
162
163         TEST_ALLOC_STAT( michael_alignheap_stat,     t_MichaelAlignHeap_Stat )
164         TEST_ALLOC( michael_alignheap_nostat,   t_MichaelAlignHeap_NoStat )
165         TEST_ALLOC( system_aligned_alloc,       t_system_aligned_allocator )
166
167         CPPUNIT_TEST_SUITE( Hoard_ThreadTest )
168             CPPUNIT_TEST( std_alloc )
169             CPPUNIT_TEST( michael_heap_stat )
170             CPPUNIT_TEST( michael_heap_nostat )
171
172             CPPUNIT_TEST( system_aligned_alloc )
173             CPPUNIT_TEST( michael_alignheap_stat )
174             CPPUNIT_TEST( michael_alignheap_nostat )
175
176         CPPUNIT_TEST_SUITE_END();
177     };
178
179 }   // namespace memory
180 CPPUNIT_TEST_SUITE_REGISTRATION( memory::Hoard_ThreadTest );