1578495044025bcee21d390e62a881fec2858f7c
[libcds.git] / tests / unit / map2 / map_insdel_item_int.h
1 //$$CDS-header$$
2
3 #include "map2/map_type.h"
4 #include "cppunit/thread.h"
5
6 #include <vector>
7
8 namespace map2 {
9
10 #define TEST_CASE(TAG, X)  void X();
11
12     class Map_InsDel_Item_int: public CppUnitMini::TestCase
13     {
14     public:
15         size_t  c_nMapSize = 1000000;       // map size
16         size_t  c_nThreadCount = 4;         // thread count
17         size_t  c_nAttemptCount = 100000;   // count of SUCCESS insert/delete for each thread
18         size_t  c_nMaxLoadFactor = 8;       // maximum load factor
19         bool    c_bPrintGCState = true;
20
21         size_t c_nCuckooInitialSize = 1024; // initial size for CuckooMap
22         size_t c_nCuckooProbesetSize = 16;  // CuckooMap probeset size (only for list-based probeset)
23         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
24
25         size_t c_nMultiLevelMap_HeadBits = 10;
26         size_t c_nMultiLevelMap_ArrayBits = 4;
27
28         size_t  c_nGoalItem;
29         size_t  c_nLoadFactor = 2;  // current load factor
30
31     private:
32         typedef CppUnitMini::TestCase Base;
33         typedef size_t  key_type;
34         typedef size_t  value_type;
35
36         template <class Map>
37         class Inserter: public CppUnitMini::TestThread
38         {
39             Map&     m_Map;
40
41             virtual Inserter *    clone()
42             {
43                 return new Inserter( *this );
44             }
45
46             struct update_func
47             {
48                 void operator()( bool bNew, std::pair<key_type const, value_type>& item )
49                 {
50                     if ( bNew )
51                         item.second = item.first;
52                 }
53                 // for boost::container::flat_map
54                 void operator()( bool bNew, std::pair<key_type, value_type>& item )
55                 {
56                     if ( bNew )
57                         item.second = item.first;
58                 }
59
60                 // for BronsonAVLTreeMap
61                 void operator()( bool bNew, key_type key, value_type& val )
62                 {
63                     if ( bNew )
64                         val = key;
65                 }
66
67                 // for MultiLevelHashMap
68                 void operator()( std::pair<key_type const, value_type>& item, std::pair<key_type const, value_type> * pOld )
69                 {
70                     if ( !pOld )
71                         item.second = item.first;
72                 }
73             };
74
75         public:
76             size_t  m_nInsertSuccess;
77             size_t  m_nInsertFailed;
78
79         public:
80             Inserter( CppUnitMini::ThreadPool& pool, Map& rMap )
81                 : CppUnitMini::TestThread( pool )
82                 , m_Map( rMap )
83             {}
84             Inserter( Inserter& src )
85                 : CppUnitMini::TestThread( src )
86                 , m_Map( src.m_Map )
87             {}
88
89             Map_InsDel_Item_int&  getTest()
90             {
91                 return reinterpret_cast<Map_InsDel_Item_int&>( m_Pool.m_Test );
92             }
93
94             virtual void init() { cds::threading::Manager::attachThread()   ; }
95             virtual void fini() { cds::threading::Manager::detachThread()   ; }
96
97             virtual void test()
98             {
99                 Map& rMap = m_Map;
100
101                 m_nInsertSuccess =
102                     m_nInsertFailed = 0;
103
104                 size_t nGoalItem = getTest().c_nGoalItem;
105                 size_t const nAttemptCount = getTest().c_nAttemptCount;
106
107                 for ( size_t nAttempt = 0; nAttempt < nAttemptCount; ) {
108                     if ( nAttempt % 2  == 0 ) {
109                         if ( rMap.insert( nGoalItem, nGoalItem )) {
110                             ++m_nInsertSuccess;
111                             ++nAttempt;
112                         }
113                         else
114                             ++m_nInsertFailed;
115                     }
116                     else {
117                         std::pair<bool, bool> updateResult = rMap.update( nGoalItem, update_func(), true );
118                         if ( updateResult.second ) {
119                             ++m_nInsertSuccess;
120                             ++nAttempt;
121                         }
122                         else
123                             ++m_nInsertFailed;
124                     }
125                 }
126             }
127         };
128
129         template <class Map>
130         class Deleter: public CppUnitMini::TestThread
131         {
132             Map&     m_Map;
133
134             virtual Deleter *    clone()
135             {
136                 return new Deleter( *this );
137             }
138         public:
139             size_t  m_nDeleteSuccess;
140             size_t  m_nDeleteFailed;
141
142         public:
143             Deleter( CppUnitMini::ThreadPool& pool, Map& rMap )
144                 : CppUnitMini::TestThread( pool )
145                 , m_Map( rMap )
146             {}
147             Deleter( Deleter& src )
148                 : CppUnitMini::TestThread( src )
149                 , m_Map( src.m_Map )
150             {}
151
152             Map_InsDel_Item_int&  getTest()
153             {
154                 return reinterpret_cast<Map_InsDel_Item_int&>( m_Pool.m_Test );
155             }
156
157             virtual void init() { cds::threading::Manager::attachThread()   ; }
158             virtual void fini() { cds::threading::Manager::detachThread()   ; }
159
160             virtual void test()
161             {
162                 Map& rMap = m_Map;
163
164                 m_nDeleteSuccess =
165                     m_nDeleteFailed = 0;
166
167                 size_t nGoalItem = getTest().c_nGoalItem;
168                 size_t const nAttemptCount = getTest().c_nAttemptCount;
169                 for ( size_t nAttempt = 0; nAttempt < nAttemptCount; ) {
170                     if ( rMap.erase( nGoalItem )) {
171                         ++m_nDeleteSuccess;
172                         ++nAttempt;
173                     }
174                     else
175                         ++m_nDeleteFailed;
176                 }
177             }
178         };
179
180     protected:
181
182         template <class Map>
183         void do_test( Map& testMap )
184         {
185             typedef Inserter<Map>       InserterThread;
186             typedef Deleter<Map>        DeleterThread;
187             cds::OS::Timer    timer;
188
189             // Fill the map
190             CPPUNIT_MSG( "  Fill map (" << c_nMapSize << " items)...");
191             timer.reset();
192             {
193                 std::vector<key_type>   v;
194                 v.reserve( c_nMapSize );
195                 for ( size_t i = 0; i < c_nMapSize; ++i )
196                     v.push_back( i );
197                 shuffle( v.begin(), v.end() );
198                 for ( size_t i = 0; i < v.size(); ++i ) {
199                     CPPUNIT_ASSERT( testMap.insert( v[i], v[i] ));
200                 }
201             }
202             CPPUNIT_MSG( "   Duration=" << timer.duration() );
203
204             CPPUNIT_MSG( "  Insert/delete the key " << c_nGoalItem << " (" << c_nAttemptCount << " successful times)...");
205             CppUnitMini::ThreadPool pool( *this );
206             pool.add( new InserterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
207             pool.add( new DeleterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
208             pool.run();
209             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
210
211             size_t nInsertSuccess = 0;
212             size_t nInsertFailed = 0;
213             size_t nDeleteSuccess = 0;
214             size_t nDeleteFailed = 0;
215             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
216                 InserterThread * pThread = dynamic_cast<InserterThread *>( *it );
217                 if ( pThread ) {
218                     CPPUNIT_CHECK( pThread->m_nInsertSuccess == c_nAttemptCount );
219                     nInsertSuccess += pThread->m_nInsertSuccess;
220                     nInsertFailed += pThread->m_nInsertFailed;
221                 }
222                 else {
223                     DeleterThread * p = static_cast<DeleterThread *>( *it );
224                     CPPUNIT_CHECK( p->m_nDeleteSuccess == c_nAttemptCount );
225                     nDeleteSuccess += p->m_nDeleteSuccess;
226                     nDeleteFailed += p->m_nDeleteFailed;
227                 }
228             }
229             CPPUNIT_CHECK( nInsertSuccess == nDeleteSuccess );
230             size_t nGoalItem = c_nGoalItem;
231             CPPUNIT_CHECK( testMap.contains( nGoalItem ));
232
233
234             CPPUNIT_MSG( "    Totals: Ins fail=" << nInsertFailed << " Del fail=" << nDeleteFailed );
235
236             // Check if the map contains all items
237             CPPUNIT_MSG( "    Check if the map contains all items" );
238             timer.reset();
239             for ( size_t i = 0; i < c_nMapSize; ++i ) {
240                 CPPUNIT_CHECK_EX( testMap.contains( i ), "key " << i );
241             }
242             CPPUNIT_MSG( "    Duration=" << timer.duration() );
243
244             check_before_cleanup( testMap );
245
246             testMap.clear();
247             additional_check( testMap );
248             print_stat( testMap );
249             additional_cleanup( testMap );
250         }
251
252         template <class Map>
253         void run_test()
254         {
255             if ( Map::c_bLoadFactorDepended ) {
256                 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
257                     CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
258                     Map testMap( *this );
259                     do_test( testMap );
260                     if ( c_bPrintGCState )
261                         print_gc_state();
262                 }
263             }
264             else {
265                 Map testMap( *this );
266                 do_test<Map>( testMap );
267                 if ( c_bPrintGCState )
268                     print_gc_state();
269             }
270         }
271
272         void setUpParams( const CppUnitMini::TestCfg& cfg );
273
274 #   include "map2/map_defs.h"
275         CDSUNIT_DECLARE_MichaelMap
276         CDSUNIT_DECLARE_SplitList
277         CDSUNIT_DECLARE_SkipListMap
278         CDSUNIT_DECLARE_EllenBinTreeMap
279         CDSUNIT_DECLARE_BronsonAVLTreeMap
280         CDSUNIT_DECLARE_MultiLevelHashMap
281         CDSUNIT_DECLARE_StripedMap
282         CDSUNIT_DECLARE_RefinableMap
283         CDSUNIT_DECLARE_CuckooMap
284         // CDSUNIT_DECLARE_StdMap // very slow!!
285
286         CPPUNIT_TEST_SUITE(Map_InsDel_Item_int)
287             CDSUNIT_TEST_MichaelMap
288             CDSUNIT_TEST_SplitList
289             CDSUNIT_TEST_SkipListMap
290             CDSUNIT_TEST_EllenBinTreeMap
291             CDSUNIT_TEST_BronsonAVLTreeMap
292             CDSUNIT_TEST_MultiLevelHashMap
293             CDSUNIT_TEST_CuckooMap
294             CDSUNIT_TEST_StripedMap
295             CDSUNIT_TEST_RefinableMap
296             // CDSUNIT_TEST_StdMap // very slow!!
297         CPPUNIT_TEST_SUITE_END();
298     };
299 } // namespace map2