Move libcds 1.6.0 from SVN
[libcds.git] / tests / unit / alloc / random.cpp
1 //$$CDS-header$$
2
3 // Random allocator test
4
5 #include "alloc/michael_allocator.h"
6 #include "alloc/random_gen.h"
7
8 #include <cds/os/timer.h>
9 #include <cds/os/topology.h>
10
11 #include "cppunit/thread.h"
12
13 namespace memory {
14
15     static size_t s_nMaxThreadCount = 32;
16     static unsigned int s_nMinBlockSize = 8;
17     static unsigned int s_nMaxBlockSize = 1024;
18     //static size_t s_nBlocksPerThread = 1000;
19     static size_t s_nPassCount = 100000;
20     static size_t s_nDataSize = 1000;
21
22     static size_t s_nPassPerThread;
23
24     struct Item {
25         cds::SpinLock   m_access;
26         char *          m_pszBlock;
27
28         Item()
29             : m_access( false )
30             , m_pszBlock( NULL )
31         {}
32
33         Item& operator =(Item const& i)
34         {
35             m_pszBlock = i.m_pszBlock;
36             return *this;
37         }
38     };
39     typedef std::vector<Item>   item_array;
40
41 #    define TEST_ALLOC(X, CLASS)        void X() { test< CLASS >(false); }
42 #    define TEST_ALLOC_STAT(X, CLASS)   void X() { test< CLASS >(true) ; }
43
44     class Random_Alloc: public CppUnitMini::TestCase
45     {
46         item_array  m_Data;
47
48         template <class ALLOC>
49         class Thread: public CppUnitMini::TestThread
50         {
51             ALLOC&      m_Alloc;
52             typedef typename ALLOC::value_type value_type;
53
54             randomGen<size_t>   m_rndGen;
55
56             virtual Thread *    clone()
57             {
58                 return new Thread( *this );
59             }
60
61         public:
62             Thread( CppUnitMini::ThreadPool& pool, ALLOC& a )
63                 : CppUnitMini::TestThread( pool )
64                 , m_Alloc( a )
65             {}
66             Thread( Thread& src )
67                 : CppUnitMini::TestThread( src )
68                 , m_Alloc( src.m_Alloc )
69             {}
70
71             Random_Alloc&  getTest()
72             {
73                 return reinterpret_cast<Random_Alloc&>( m_Pool.m_Test );
74             }
75
76             virtual void init() { cds::threading::Manager::attachThread()   ; }
77             virtual void fini() { cds::threading::Manager::detachThread()   ; }
78
79             virtual void test()
80             {
81                 item_array& arr = getTest().m_Data;
82                 for ( size_t nPass = 0; nPass < s_nPassPerThread; ) {
83                     size_t nIdx = m_rndGen( size_t(0), s_nDataSize - 1 );
84                     Item & item = arr.at(nIdx);
85                     if ( item.m_access.tryLock() ) {
86                         if ( item.m_pszBlock ) {
87                             m_Alloc.deallocate( item.m_pszBlock, 1 );
88                             item.m_pszBlock = NULL;
89                         }
90                         else {
91                             size_t nSize;
92                             item.m_pszBlock = m_Alloc.allocate( nSize = m_rndGen(s_nMinBlockSize, s_nMaxBlockSize ), NULL );
93
94                             if ( nSize < 32 )
95                                 memset( item.m_pszBlock, 0, nSize );
96                             else {
97                                 memset( item.m_pszBlock, 0, 16 );
98                                 memset( ((char *) item.m_pszBlock) + nSize * sizeof(*item.m_pszBlock) - 16, 0, 16 );
99                             }
100                         }
101                         item.m_access.unlock();
102
103                         ++nPass;
104                     }
105                 }
106             }
107         };
108
109         template <class ALLOC>
110         void test( size_t nThreadCount )
111         {
112             ALLOC alloc;
113
114             CPPUNIT_MSG( "Thread count=" << nThreadCount );
115             s_nPassPerThread = s_nPassCount / nThreadCount;
116
117             CppUnitMini::ThreadPool pool( *this );
118             pool.add( new Thread<ALLOC>( pool, alloc ), nThreadCount );
119
120             cds::OS::Timer    timer;
121             pool.run();
122             CPPUNIT_MSG( "  Duration=" << pool.avgDuration() );
123
124             for ( size_t i = 0; i < m_Data.size(); ++i ) {
125                 if ( m_Data[i].m_pszBlock ) {
126                     alloc.deallocate( m_Data[i].m_pszBlock, 1 );
127                     m_Data[i].m_pszBlock = NULL;
128                 }
129             }
130         }
131
132         template <class ALLOC>
133         void test( bool bStat )
134         {
135             CPPUNIT_MSG( "Block size=" << s_nMinBlockSize << "-" << s_nMaxBlockSize
136                 << ", pass count=" << s_nPassCount << ", data size=" << s_nDataSize );
137
138             m_Data.resize( s_nDataSize );
139
140             for ( size_t nThreadCount = 2; nThreadCount <= s_nMaxThreadCount; nThreadCount *= 2 ) {
141                 summary_stat    stBegin;
142                 if ( bStat )
143                     ALLOC::stat( stBegin );
144
145                 test<ALLOC>( nThreadCount );
146
147                 summary_stat    stEnd;
148                 if ( bStat ) {
149                     ALLOC::stat( stEnd );
150
151                     std::cout << "\nStatistics:\n"
152                         << stEnd
153 ;
154                     stEnd -= stBegin;
155                     std::cout << "\nDelta statistics:\n"
156                         << stEnd
157 ;
158                 }
159             }
160
161             m_Data.resize(0);
162         }
163
164         void setUpParams( const CppUnitMini::TestCfg& cfg )
165         {
166             s_nDataSize = cfg.getULong( "DataSize", 1000 );
167             s_nPassCount = cfg.getULong( "PassCount", 100000 );
168             s_nMinBlockSize = cfg.getUInt( "MinBlockSize", 8 );
169             s_nMaxBlockSize = cfg.getUInt( "MaxBlockSize", 1024 );
170             s_nMaxThreadCount = cfg.getUInt( "MaxThreadCount", 32 );
171             if ( s_nMaxThreadCount == 0 )
172                 s_nMaxThreadCount = cds::OS::topology::processor_count() * 2;
173             if ( s_nMaxThreadCount < 2 )
174                 s_nMaxThreadCount = 2;
175         }
176
177         typedef MichaelAlignHeap_Stat<char, 32>     t_MichaelAlignHeap_Stat;
178         typedef MichaelAlignHeap_NoStat<char,32>    t_MichaelAlignHeap_NoStat;
179         typedef system_aligned_allocator<char, 32>  t_system_aligned_allocator;
180
181         TEST_ALLOC_STAT( michael_heap_stat, MichaelHeap_Stat<char> )
182         TEST_ALLOC( michael_heap_nostat,    MichaelHeap_NoStat<char> )
183         TEST_ALLOC( std_alloc,              std_allocator<char> )
184
185         TEST_ALLOC_STAT( michael_alignheap_stat,t_MichaelAlignHeap_Stat )
186         TEST_ALLOC( michael_alignheap_nostat,   t_MichaelAlignHeap_NoStat )
187         TEST_ALLOC( system_aligned_alloc,       t_system_aligned_allocator )
188
189         CPPUNIT_TEST_SUITE( Random_Alloc )
190             CPPUNIT_TEST( michael_heap_stat )
191             CPPUNIT_TEST( michael_heap_nostat )
192             CPPUNIT_TEST( std_alloc )
193
194             CPPUNIT_TEST( system_aligned_alloc )
195             CPPUNIT_TEST( michael_alignheap_stat )
196             CPPUNIT_TEST( michael_alignheap_nostat )
197
198         CPPUNIT_TEST_SUITE_END();
199     };
200
201 }   // namespace memory
202 CPPUNIT_TEST_SUITE_REGISTRATION( memory::Random_Alloc );