Splitted up map_insdel_item_string test
[libcds.git] / tests / unit / map2 / map_insdel_item_string.h
1 //$$CDS-header$$
2
3 #include "map2/map_types.h"
4 #include "cppunit/thread.h"
5
6 #include <vector>
7
8 namespace map2 {
9
10 #   define TEST_MAP(X)         void X() { test<MapTypes<key_type, value_type>::X >()    ; }
11 #   define TEST_MAP_NOLF(X)    void X() { test_nolf<MapTypes<key_type, value_type>::X >()    ; }
12 #   define TEST_MAP_EXTRACT(X)  TEST_MAP(X)
13 #   define TEST_MAP_NOLF_EXTRACT(X) TEST_MAP_NOLF(X)
14
15     class Map_InsDel_Item_string: public CppUnitMini::TestCase
16     {
17         static size_t  c_nMapSize;      // map size
18         static size_t  c_nThreadCount;  // thread count
19         static size_t  c_nGoalItem;
20         static size_t  c_nAttemptCount; // count of SUCCESS insert/delete for each thread
21         static size_t  c_nMaxLoadFactor;// maximum load factor
22         static bool    c_bPrintGCState;
23
24         typedef CppUnitMini::TestCase Base;
25         typedef std::string  key_type;
26         typedef size_t  value_type;
27
28         const std::vector<std::string> *  m_parrString;
29
30         template <class Map>
31         class Inserter: public CppUnitMini::TestThread
32         {
33             Map&     m_Map;
34
35             virtual Inserter *    clone()
36             {
37                 return new Inserter( *this );
38             }
39         public:
40             size_t  m_nInsertSuccess;
41             size_t  m_nInsertFailed;
42
43         public:
44             Inserter( CppUnitMini::ThreadPool& pool, Map& rMap )
45                 : CppUnitMini::TestThread( pool )
46                 , m_Map( rMap )
47             {}
48             Inserter( Inserter& src )
49                 : CppUnitMini::TestThread( src )
50                 , m_Map( src.m_Map )
51             {}
52
53             Map_InsDel_Item_string&  getTest()
54             {
55                 return reinterpret_cast<Map_InsDel_Item_string&>( m_Pool.m_Test );
56             }
57
58             virtual void init() { cds::threading::Manager::attachThread()   ; }
59             virtual void fini() { cds::threading::Manager::detachThread()   ; }
60
61             virtual void test()
62             {
63                 Map& rMap = m_Map;
64
65                 m_nInsertSuccess =
66                     m_nInsertFailed = 0;
67
68                 size_t nGoalItem = c_nGoalItem;
69                 std::string strGoal = (*getTest().m_parrString)[nGoalItem];
70
71                 for ( size_t nAttempt = 0; nAttempt < c_nAttemptCount; ) {
72                     if ( rMap.insert( strGoal, nGoalItem )) {
73                         ++m_nInsertSuccess;
74                         ++nAttempt;
75                     }
76                     else
77                         ++m_nInsertFailed;
78                 }
79             }
80         };
81
82         template <class Map>
83         class Deleter: public CppUnitMini::TestThread
84         {
85             Map&     m_Map;
86
87             struct erase_cleaner {
88                 void operator ()(std::pair<typename Map::key_type const, typename Map::mapped_type>& val )
89                 {
90                     val.second = 0;
91                 }
92                 // for boost::container::flat_map
93                 void operator ()(std::pair< typename std::remove_const< typename Map::key_type >::type, typename Map::mapped_type>& val )
94                 {
95                     val.second = 0;
96                 }
97                 // for BronsonAVLTreeMap
98                 void operator()( typename Map::key_type const& /*key*/, typename Map::mapped_type& val )
99                 {
100                     val = 0;
101                 }
102             };
103
104             virtual Deleter *    clone()
105             {
106                 return new Deleter( *this );
107             }
108         public:
109             size_t  m_nDeleteSuccess;
110             size_t  m_nDeleteFailed;
111
112         public:
113             Deleter( CppUnitMini::ThreadPool& pool, Map& rMap )
114                 : CppUnitMini::TestThread( pool )
115                 , m_Map( rMap )
116             {}
117             Deleter( Deleter& src )
118                 : CppUnitMini::TestThread( src )
119                 , m_Map( src.m_Map )
120             {}
121
122             Map_InsDel_Item_string&  getTest()
123             {
124                 return reinterpret_cast<Map_InsDel_Item_string&>( m_Pool.m_Test );
125             }
126
127             virtual void init() { cds::threading::Manager::attachThread()   ; }
128             virtual void fini() { cds::threading::Manager::detachThread()   ; }
129
130             virtual void test()
131             {
132                 Map& rMap = m_Map;
133
134                 m_nDeleteSuccess =
135                     m_nDeleteFailed = 0;
136
137                 size_t nGoalItem = c_nGoalItem;
138                 std::string strGoal = (*getTest().m_parrString)[nGoalItem];
139
140                 for ( size_t nAttempt = 0; nAttempt < c_nAttemptCount; ) {
141                     if ( rMap.erase( strGoal, erase_cleaner() )) {
142                         ++m_nDeleteSuccess;
143                         ++nAttempt;
144                     }
145                     else
146                         ++m_nDeleteFailed;
147                 }
148             }
149         };
150
151     protected:
152
153         template <class Map>
154         void do_test( Map& testMap )
155         {
156             typedef Inserter<Map>       InserterThread;
157             typedef Deleter<Map>        DeleterThread;
158             cds::OS::Timer    timer;
159
160             // Fill the map
161             CPPUNIT_MSG( "  Fill map (" << c_nMapSize << " items)...");
162             timer.reset();
163             for ( size_t i = 0; i < c_nMapSize; ++i ) {
164                 CPPUNIT_ASSERT_EX( testMap.insert( (*m_parrString)[i], i ), i );
165             }
166             CPPUNIT_MSG( "   Duration=" << timer.duration() );
167
168             CPPUNIT_MSG( "  Insert/delete the key " << c_nGoalItem << " (" << c_nAttemptCount << " successful times)...");
169             CppUnitMini::ThreadPool pool( *this );
170             pool.add( new InserterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
171             pool.add( new DeleterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
172             pool.run();
173             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
174
175             size_t nInsertSuccess = 0;
176             size_t nInsertFailed = 0;
177             size_t nDeleteSuccess = 0;
178             size_t nDeleteFailed = 0;
179             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
180                 InserterThread * pThread = dynamic_cast<InserterThread *>( *it );
181                 if ( pThread ) {
182                     CPPUNIT_CHECK( pThread->m_nInsertSuccess == c_nAttemptCount );
183                     nInsertSuccess += pThread->m_nInsertSuccess;
184                     nInsertFailed += pThread->m_nInsertFailed;
185                 }
186                 else {
187                     DeleterThread * p = static_cast<DeleterThread *>( *it );
188                     CPPUNIT_CHECK( p->m_nDeleteSuccess == c_nAttemptCount );
189                     nDeleteSuccess += p->m_nDeleteSuccess;
190                     nDeleteFailed += p->m_nDeleteFailed;
191                 }
192             }
193             CPPUNIT_CHECK_EX( nInsertSuccess == nDeleteSuccess, "nInsertSuccess=" << nInsertSuccess << ", nDeleteSuccess=" << nDeleteSuccess );
194             CPPUNIT_MSG( "    Totals: Ins fail=" << nInsertFailed << " Del fail=" << nDeleteFailed );
195
196             // Check if the map contains all items
197             CPPUNIT_MSG( "    Check if the map contains all items" );
198             timer.reset();
199             for ( size_t i = 0; i < c_nMapSize; ++i ) {
200                 CPPUNIT_CHECK_EX( testMap.find( (*m_parrString)[i] ), "Key \"" << (*m_parrString)[i] << "\" not found" );
201             }
202             CPPUNIT_MSG( "    Duration=" << timer.duration() );
203
204             check_before_cleanup( testMap );
205
206             testMap.clear();
207             additional_check( testMap );
208             print_stat( testMap );
209             additional_cleanup( testMap );
210         }
211
212         template <class Map>
213         void test()
214         {
215             m_parrString = &CppUnitMini::TestCase::getTestStrings();
216             if ( c_nMapSize > m_parrString->size() )
217                 c_nMapSize = m_parrString->size();
218             if ( c_nGoalItem > m_parrString->size() )
219                 c_nGoalItem = m_parrString->size() / 2;
220
221             CPPUNIT_MSG( "Thread count= " << c_nThreadCount
222                 << " pass count=" << c_nAttemptCount
223                 << " map size=" << c_nMapSize
224                 );
225
226             for ( size_t nLoadFactor = 1; nLoadFactor <= c_nMaxLoadFactor; nLoadFactor *= 2 ) {
227                 CPPUNIT_MSG( "Load factor=" << nLoadFactor );
228                 Map  testMap( c_nMapSize, nLoadFactor );
229                 do_test( testMap );
230                 if ( c_bPrintGCState )
231                     print_gc_state();
232             }
233         }
234
235         template <typename Map>
236         void test_nolf()
237         {
238             m_parrString = &CppUnitMini::TestCase::getTestStrings();
239             if ( c_nMapSize > m_parrString->size() )
240                 c_nMapSize = m_parrString->size();
241             if ( c_nGoalItem > m_parrString->size() )
242                 c_nGoalItem = m_parrString->size() / 2;
243
244             CPPUNIT_MSG( "Thread count= " << c_nThreadCount
245                 << " pass count=" << c_nAttemptCount
246                 << " map size=" << c_nMapSize
247                 );
248
249             Map testMap;
250             do_test( testMap );
251             if ( c_bPrintGCState )
252                 print_gc_state();
253         }
254
255         void setUpParams( const CppUnitMini::TestCfg& cfg );
256
257         void run_MichaelMap(const char *in_name, bool invert = false);
258         void run_SplitList(const char *in_name, bool invert = false);
259         void run_SkipListMap(const char *in_name, bool invert = false);
260         void run_StripedMap(const char *in_name, bool invert = false);
261         void run_RefinableMap(const char *in_name, bool invert = false);
262         void run_CuckooMap(const char *in_name, bool invert = false);
263         void run_EllenBinTreeMap(const char *in_name, bool invert = false);
264         void run_BronsonAVLTreeMap(const char *in_name, bool invert = false);
265
266         virtual void myRun(const char *in_name, bool invert = false);
267
268 #   include "map2/map_defs.h"
269         CDSUNIT_DECLARE_MichaelMap
270         CDSUNIT_DECLARE_SplitList
271         CDSUNIT_DECLARE_SkipListMap
272         CDSUNIT_DECLARE_EllenBinTreeMap
273         CDSUNIT_DECLARE_BronsonAVLTreeMap
274         CDSUNIT_DECLARE_StripedMap
275         CDSUNIT_DECLARE_RefinableMap
276         CDSUNIT_DECLARE_CuckooMap
277         //CDSUNIT_DECLARE_StdMap  // very slow!
278     };
279 } // namespace map2