382a63e09fcee4cd3e593f7f1d2b4b0f25b8d0d1
[libcds.git] / tests / unit / map2 / map_delodd.cpp
1 //$$CDS-header$$
2
3 #include "cppunit/thread.h"
4 #include "map2/map_types.h"
5 #include <algorithm> // random_shuffle
6
7 namespace map2 {
8
9 #   define TEST_MAP(X)         void X() { test<MapTypes<key_type, value_type>::X >(); }
10 #   define TEST_MAP_EXTRACT(X) void X() { test_extract<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_NOLF_EXTRACT(X) void X() { test_nolf_extract<MapTypes<key_type, value_type>::X >(); }
13
14     namespace {
15         static size_t  c_nMapSize = 1000000         ;  // max map size
16         static size_t  c_nInsThreadCount = 4        ;  // insert thread count
17         static size_t  c_nDelThreadCount = 4        ;  // delete thread count
18         static size_t  c_nExtractThreadCount = 4    ;  // extract thread count
19         static size_t  c_nMaxLoadFactor = 8         ;  // maximum load factor
20         static bool    c_bPrintGCState = true;
21     }
22
23     namespace {
24         struct key_thread
25         {
26             size_t  nKey;
27             size_t  nThread;
28
29             key_thread( size_t key, size_t threadNo )
30                 : nKey( key )
31                 , nThread( threadNo )
32             {}
33
34             key_thread()
35             {}
36         };
37
38         //typedef MapTypes<key_thread, size_t>::key_val     key_value_pair;
39     }
40
41     template <>
42     struct cmp<key_thread> {
43         int operator ()(key_thread const& k1, key_thread const& k2) const
44         {
45             if ( k1.nKey < k2.nKey )
46                 return -1;
47             if ( k1.nKey > k2.nKey )
48                 return 1;
49             if ( k1.nThread < k2.nThread )
50                 return -1;
51             if ( k1.nThread > k2.nThread )
52                 return 1;
53             return 0;
54         }
55         int operator ()(key_thread const& k1, size_t k2) const
56         {
57             if ( k1.nKey < k2 )
58                 return -1;
59             if ( k1.nKey > k2 )
60                 return 1;
61             return 0;
62         }
63         int operator ()(size_t k1, key_thread const& k2) const
64         {
65             if ( k1 < k2.nKey )
66                 return -1;
67             if ( k1 > k2.nKey )
68                 return 1;
69             return 0;
70         }
71     };
72
73 } // namespace map2
74
75 namespace std {
76     template <>
77     struct less<map2::key_thread>
78     {
79         bool operator()(map2::key_thread const& k1, map2::key_thread const& k2) const
80         {
81             if ( k1.nKey <= k2.nKey )
82                 return k1.nKey < k2.nKey || k1.nThread < k2.nThread;
83             return false;
84         }
85     };
86
87     template <>
88     struct hash<map2::key_thread>
89     {
90         typedef size_t              result_type;
91         typedef map2::key_thread    argument_type;
92
93         size_t operator()( map2::key_thread const& k ) const
94         {
95             return std::hash<size_t>()(k.nKey);
96         }
97         size_t operator()( size_t k ) const
98         {
99             return std::hash<size_t>()(k);
100         }
101     };
102 } // namespace std
103
104 namespace boost {
105     inline size_t hash_value( map2::key_thread const& k )\r
106     {\r
107         return std::hash<size_t>()( k.nKey );\r
108     }
109     template <>
110     struct hash<map2::key_thread>
111     {
112         typedef size_t              result_type;
113         typedef map2::key_thread    argument_type;
114
115         size_t operator()(map2::key_thread const& k) const
116         {
117             return boost::hash<size_t>()( k.nKey );
118         }
119         size_t operator()(size_t k) const
120         {
121             return boost::hash<size_t>()( k );
122         }
123     };
124 } // namespace boost
125
126 namespace map2 {
127
128     template <typename Map>
129     static inline void check_before_clear( Map& s )
130     {}
131
132     template <typename GC, typename Key, typename T, typename Traits>
133     static inline void check_before_clear( cds::container::EllenBinTreeMap<GC, Key, T, Traits>& s )
134     {
135         CPPUNIT_CHECK_CURRENT( s.check_consistency() );
136     }
137
138     class Map_DelOdd: public CppUnitMini::TestCase
139     {
140         std::vector<size_t>     m_arrData;
141
142     protected:
143         typedef key_thread  key_type;
144         typedef size_t      value_type;
145         typedef std::pair<key_type const, value_type> pair_type;
146
147         atomics::atomic<size_t>      m_nInsThreadCount;
148
149         // Inserts keys from [0..N)
150         template <class Map>
151         class InsertThread: public CppUnitMini::TestThread
152         {
153             Map&     m_Map;
154
155             virtual InsertThread *    clone()
156             {
157                 return new InsertThread( *this );
158             }
159
160             struct ensure_func
161             {
162                 template <typename Q>
163                 void operator()( bool bNew, Q const& )
164                 {}
165             };
166         public:
167             size_t  m_nInsertSuccess;
168             size_t  m_nInsertFailed;
169
170         public:
171             InsertThread( CppUnitMini::ThreadPool& pool, Map& rMap )
172                 : CppUnitMini::TestThread( pool )
173                 , m_Map( rMap )
174             {}
175             InsertThread( InsertThread& src )
176                 : CppUnitMini::TestThread( src )
177                 , m_Map( src.m_Map )
178             {}
179
180             Map_DelOdd&  getTest()
181             {
182                 return reinterpret_cast<Map_DelOdd&>( m_Pool.m_Test );
183             }
184
185             virtual void init() { cds::threading::Manager::attachThread()   ; }
186             virtual void fini() { cds::threading::Manager::detachThread()   ; }
187
188             virtual void test()
189             {
190                 Map& rMap = m_Map;
191
192                 m_nInsertSuccess =
193                     m_nInsertFailed = 0;
194
195                 std::vector<size_t>& arrData = getTest().m_arrData;
196                 for ( size_t i = 0; i < arrData.size(); ++i ) {
197                     if ( rMap.insert( key_type( arrData[i], m_nThreadNo )))
198                         ++m_nInsertSuccess;
199                     else
200                         ++m_nInsertFailed;
201                 }
202
203                 ensure_func f;
204                 for ( size_t i = arrData.size() - 1; i > 0; --i ) {
205                     if ( arrData[i] & 1 ) {
206                         rMap.ensure( key_type( arrData[i], m_nThreadNo ), f );
207                     }
208                 }
209
210                 getTest().m_nInsThreadCount.fetch_sub( 1, atomics::memory_order_acquire );
211             }
212         };
213
214         struct key_equal {
215             bool operator()( key_type const& k1, key_type const& k2 ) const
216             {
217                 return k1.nKey == k2.nKey;
218             }
219             bool operator()( size_t k1, key_type const& k2 ) const
220             {
221                 return k1 == k2.nKey;
222             }
223             bool operator()( key_type const& k1, size_t k2 ) const
224             {
225                 return k1.nKey == k2;
226             }
227         };
228
229         struct key_less {
230             bool operator()( key_type const& k1, key_type const& k2 ) const
231             {
232                 return k1.nKey < k2.nKey;
233             }
234             bool operator()( size_t k1, key_type const& k2 ) const
235             {
236                 return k1 < k2.nKey;
237             }
238             bool operator()( key_type const& k1, size_t k2 ) const
239             {
240                 return k1.nKey < k2;
241             }
242
243             typedef key_equal equal_to;
244         };
245
246         // Deletes odd keys from [0..N)
247         template <class Map>
248         class DeleteThread: public CppUnitMini::TestThread
249         {
250             Map&     m_Map;
251
252             virtual DeleteThread *    clone()
253             {
254                 return new DeleteThread( *this );
255             }
256         public:
257             size_t  m_nDeleteSuccess;
258             size_t  m_nDeleteFailed;
259
260         public:
261             DeleteThread( CppUnitMini::ThreadPool& pool, Map& rMap )
262                 : CppUnitMini::TestThread( pool )
263                 , m_Map( rMap )
264             {}
265             DeleteThread( DeleteThread& src )
266                 : CppUnitMini::TestThread( src )
267                 , m_Map( src.m_Map )
268             {}
269
270             Map_DelOdd&  getTest()
271             {
272                 return reinterpret_cast<Map_DelOdd&>( m_Pool.m_Test );
273             }
274
275             virtual void init() { cds::threading::Manager::attachThread()   ; }
276             virtual void fini() { cds::threading::Manager::detachThread()   ; }
277
278             virtual void test()
279             {
280                 Map& rMap = m_Map;
281
282                 m_nDeleteSuccess =
283                     m_nDeleteFailed = 0;
284
285                 std::vector<size_t>& arrData = getTest().m_arrData;
286                 if ( m_nThreadNo & 1 ) {
287                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
288                         for ( size_t i = 0; i < arrData.size(); ++i ) {
289                             if ( arrData[i] & 1 ) {
290                                 if ( rMap.erase_with( arrData[i], key_less() ))
291                                     ++m_nDeleteSuccess;
292                                 else
293                                     ++m_nDeleteFailed;
294                             }
295                         }
296                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
297                             break;
298                     }
299                 }
300                 else {
301                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
302                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
303                             if ( arrData[i] & 1 ) {
304                                 if ( rMap.erase_with( arrData[i], key_less() ))
305                                     ++m_nDeleteSuccess;
306                                 else
307                                     ++m_nDeleteFailed;
308                             }
309                         }
310                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
311                             break;
312                     }
313                 }
314             }
315         };
316
317         // Deletes odd keys from [0..N)
318         template <class GC, class Map >
319         class ExtractThread: public CppUnitMini::TestThread
320         {
321             Map&     m_Map;
322
323             virtual ExtractThread *    clone()
324             {
325                 return new ExtractThread( *this );
326             }
327         public:
328             size_t  m_nDeleteSuccess;
329             size_t  m_nDeleteFailed;
330
331         public:
332             ExtractThread( CppUnitMini::ThreadPool& pool, Map& rMap )
333                 : CppUnitMini::TestThread( pool )
334                 , m_Map( rMap )
335             {}
336             ExtractThread( ExtractThread& src )
337                 : CppUnitMini::TestThread( src )
338                 , m_Map( src.m_Map )
339             {}
340
341             Map_DelOdd&  getTest()
342             {
343                 return reinterpret_cast<Map_DelOdd&>( m_Pool.m_Test );
344             }
345
346             virtual void init() { cds::threading::Manager::attachThread()   ; }
347             virtual void fini() { cds::threading::Manager::detachThread()   ; }
348
349             virtual void test()
350             {
351                 Map& rMap = m_Map;
352
353                 m_nDeleteSuccess =
354                     m_nDeleteFailed = 0;
355
356                 typename Map::guarded_ptr gp;
357
358                 std::vector<size_t>& arrData = getTest().m_arrData;
359                 if ( m_nThreadNo & 1 ) {
360                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
361                         for ( size_t i = 0; i < arrData.size(); ++i ) {
362                             if ( arrData[i] & 1 ) {
363                                 if ( rMap.extract_with( gp, arrData[i], key_less() ))
364                                     ++m_nDeleteSuccess;
365                                 else
366                                     ++m_nDeleteFailed;
367                             }
368                         }
369                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
370                             break;
371                     }
372                 }
373                 else {
374                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
375                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
376                             if ( arrData[i] & 1 ) {
377                                 if ( rMap.extract_with( gp, arrData[i], key_less() ))
378                                     ++m_nDeleteSuccess;
379                                 else
380                                     ++m_nDeleteFailed;
381                             }
382                         }
383                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
384                             break;
385                     }
386                 }
387             }
388         };
389
390         template <class RCU, class Map >
391         class ExtractThread< cds::urcu::gc<RCU>, Map > : public CppUnitMini::TestThread
392         {
393             Map&     m_Map;
394
395             virtual ExtractThread *    clone()
396             {
397                 return new ExtractThread( *this );
398             }
399         public:
400             size_t  m_nDeleteSuccess;
401             size_t  m_nDeleteFailed;
402
403         public:
404             ExtractThread( CppUnitMini::ThreadPool& pool, Map& rMap )
405                 : CppUnitMini::TestThread( pool )
406                 , m_Map( rMap )
407             {}
408             ExtractThread( ExtractThread& src )
409                 : CppUnitMini::TestThread( src )
410                 , m_Map( src.m_Map )
411             {}
412
413             Map_DelOdd&  getTest()
414             {
415                 return reinterpret_cast<Map_DelOdd&>( m_Pool.m_Test );
416             }
417
418             virtual void init() { cds::threading::Manager::attachThread()   ; }
419             virtual void fini() { cds::threading::Manager::detachThread()   ; }
420
421             virtual void test()
422             {
423                 Map& rMap = m_Map;
424
425                 m_nDeleteSuccess =
426                     m_nDeleteFailed = 0;
427
428                 typename Map::exempt_ptr xp;
429
430                 std::vector<size_t>& arrData = getTest().m_arrData;
431                 if ( m_nThreadNo & 1 ) {
432                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
433                         for ( size_t i = 0; i < arrData.size(); ++i ) {
434                             if ( arrData[i] & 1 ) {
435                                 if ( Map::c_bExtractLockExternal ) {
436                                     {
437                                         typename Map::rcu_lock l;
438                                         if ( rMap.extract_with( xp, arrData[i], key_less() )) {
439                                             ++m_nDeleteSuccess;
440                                         }
441                                         else
442                                             ++m_nDeleteFailed;
443                                     }
444                                     xp.release();
445                                 }
446                                 else {
447                                     if ( rMap.extract_with( xp, arrData[i], key_less() )) {
448                                         ++m_nDeleteSuccess;
449                                         xp.release();
450                                     }
451                                     else
452                                         ++m_nDeleteFailed;
453                                 }
454                             }
455                         }
456                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
457                             break;
458                     }
459                 }
460                 else {
461                     for ( size_t k = 0; k < c_nInsThreadCount; ++k ) {
462                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
463                             if ( arrData[i] & 1 ) {
464                                 if ( Map::c_bExtractLockExternal ) {
465                                     {
466                                         typename Map::rcu_lock l;
467                                         if ( rMap.extract_with( xp, arrData[i], key_less() ))
468                                             ++m_nDeleteSuccess;
469                                         else
470                                             ++m_nDeleteFailed;
471                                     }
472                                     xp.release();
473                                 }
474                                 else {
475                                     if ( rMap.extract_with( xp, arrData[i], key_less() )) {
476                                         ++m_nDeleteSuccess;
477                                         xp.release();
478                                     }
479                                     else
480                                         ++m_nDeleteFailed;
481                                 }
482                             }
483                         }
484                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
485                             break;
486                     }
487                 }
488             }
489         };
490
491     protected:
492         template <class Map>
493         void do_test( size_t nLoadFactor )
494         {
495             Map  testMap( c_nMapSize, nLoadFactor );
496             do_test_with( testMap );
497         }
498
499         template <class Map>
500         void do_test_extract( size_t nLoadFactor )
501         {
502             Map  testMap( c_nMapSize, nLoadFactor );
503             do_test_extract_with( testMap );
504         }
505
506         template <class Map>
507         void do_test_with( Map& testMap )
508         {
509             typedef InsertThread<Map> insert_thread;
510             typedef DeleteThread<Map> delete_thread;
511
512             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
513
514             CppUnitMini::ThreadPool pool( *this );
515             pool.add( new insert_thread( pool, testMap ), c_nInsThreadCount );
516             pool.add( new delete_thread( pool, testMap ), c_nDelThreadCount ? c_nDelThreadCount : cds::OS::topology::processor_count());
517             pool.run();
518             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
519
520             size_t nInsertSuccess = 0;
521             size_t nInsertFailed = 0;
522             size_t nDeleteSuccess = 0;
523             size_t nDeleteFailed = 0;
524             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
525                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
526                 if ( pThread ) {
527                     nInsertSuccess += pThread->m_nInsertSuccess;
528                     nInsertFailed += pThread->m_nInsertFailed;
529                 }
530                 else {
531                     delete_thread * p = static_cast<delete_thread *>( *it );
532                     nDeleteSuccess += p->m_nDeleteSuccess;
533                     nDeleteFailed += p->m_nDeleteFailed;
534                 }
535             }
536
537             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
538                 << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
539                 << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
540                 );
541             CPPUNIT_CHECK( nInsertSuccess == c_nMapSize * c_nInsThreadCount );
542             CPPUNIT_CHECK( nInsertFailed == 0 );
543
544             analyze( testMap );
545         }
546
547         template <class Map>
548         void do_test_extract_with( Map& testMap )
549         {
550             typedef InsertThread<Map> insert_thread;
551             typedef DeleteThread<Map> delete_thread;
552             typedef ExtractThread< typename Map::gc, Map > extract_thread;
553
554             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
555
556             CppUnitMini::ThreadPool pool( *this );
557             pool.add( new insert_thread( pool, testMap ), c_nInsThreadCount );
558             if ( c_nDelThreadCount )
559                 pool.add( new delete_thread( pool, testMap ), c_nDelThreadCount );
560             if ( c_nExtractThreadCount )
561                 pool.add( new extract_thread( pool, testMap ), c_nExtractThreadCount );
562             pool.run();
563             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
564
565             size_t nInsertSuccess = 0;
566             size_t nInsertFailed = 0;
567             size_t nDeleteSuccess = 0;
568             size_t nDeleteFailed = 0;
569             size_t nExtractSuccess = 0;
570             size_t nExtractFailed = 0;
571             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
572                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
573                 if ( pThread ) {
574                     nInsertSuccess += pThread->m_nInsertSuccess;
575                     nInsertFailed += pThread->m_nInsertFailed;
576                 }
577                 else {
578                     delete_thread * p = dynamic_cast<delete_thread *>( *it );
579                     if ( p ) {
580                         nDeleteSuccess += p->m_nDeleteSuccess;
581                         nDeleteFailed += p->m_nDeleteFailed;
582                     }
583                     else {
584                         extract_thread * pExtract = dynamic_cast<extract_thread *>( *it );
585                         assert( pExtract );
586                         nExtractSuccess += pExtract->m_nDeleteSuccess;
587                         nExtractFailed += pExtract->m_nDeleteFailed;
588                     }
589                 }
590             }
591
592             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
593                 << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
594                 << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
595                 << "      Extract=" << nExtractSuccess << '/' << nExtractFailed << "\n\t"
596                 );
597             CPPUNIT_CHECK( nInsertSuccess == c_nMapSize * c_nInsThreadCount );
598             CPPUNIT_CHECK( nInsertFailed == 0 );
599
600             analyze( testMap );
601         }
602
603         template <class Map>
604         void analyze( Map& testMap )
605         {
606             cds::OS::Timer    timer;
607
608             // All even keys must be in the map
609             {
610                 size_t nErrorCount = 0;
611                 CPPUNIT_MSG( "  Check even keys..." );
612                 for ( size_t n = 0; n < c_nMapSize; n +=2 ) {
613                     for ( size_t i = 0; i < c_nInsThreadCount; ++i ) {
614                         if ( !testMap.find( key_type(n, i) ) ) {
615                             if ( ++nErrorCount < 10 ) {
616                                 CPPUNIT_MSG( "key " << n << "-" << i << " is not found!");
617                             }
618                         }
619                     }
620                 }
621                 CPPUNIT_CHECK_EX( nErrorCount == 0, "Totals: " << nErrorCount << " keys is not found");
622             }
623
624             check_before_clear( testMap );
625
626             CPPUNIT_MSG( "  Clear map (single-threaded)..." );
627             timer.reset();
628             testMap.clear();
629             CPPUNIT_MSG( "   Duration=" << timer.duration() );
630             CPPUNIT_CHECK_EX( testMap.empty(), ((long long) testMap.size()) );
631
632             additional_check( testMap );
633             print_stat( testMap );
634
635             additional_cleanup( testMap );
636         }
637
638
639         template <class Map>
640         void test()
641         {
642             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
643                 << " delete thread count=" << c_nDelThreadCount
644                 << " set size=" << c_nMapSize
645                 );
646
647             for ( size_t nLoadFactor = 1; nLoadFactor <= c_nMaxLoadFactor; nLoadFactor *= 2 ) {
648                 CPPUNIT_MSG( "Load factor=" << nLoadFactor );
649                 do_test<Map>( nLoadFactor );
650                 if ( c_bPrintGCState )
651                     print_gc_state();
652             }
653         }
654
655         template <class Map>
656         void test_extract()
657         {
658             CPPUNIT_MSG( "Thread count: insert=" << c_nInsThreadCount
659                 << ", delete=" << c_nDelThreadCount
660                 << ", extract=" << c_nExtractThreadCount
661                 << "; set size=" << c_nMapSize
662                 );
663
664             for ( size_t nLoadFactor = 1; nLoadFactor <= c_nMaxLoadFactor; nLoadFactor *= 2 ) {
665                 CPPUNIT_MSG( "Load factor=" << nLoadFactor );
666                 do_test_extract<Map>( nLoadFactor );
667                 if ( c_bPrintGCState )
668                     print_gc_state();
669             }
670         }
671
672         template <class Map>
673         void test_nolf()
674         {
675             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
676                 << " delete thread count=" << c_nDelThreadCount
677                 << " set size=" << c_nMapSize
678                 );
679
680             Map s;
681             do_test_with( s );
682             if ( c_bPrintGCState )
683                 print_gc_state();
684         }
685
686         template <class Map>
687         void test_nolf_extract()
688         {
689             CPPUNIT_MSG( "Thread count: insert=" << c_nInsThreadCount
690                 << ", delete=" << c_nDelThreadCount
691                 << ", extract=" << c_nExtractThreadCount
692                 << "; set size=" << c_nMapSize
693                 );
694
695             Map s;
696             do_test_extract_with( s );
697             if ( c_bPrintGCState )
698                 print_gc_state();
699         }
700
701         void setUpParams( const CppUnitMini::TestCfg& cfg ) {
702             c_nMapSize = cfg.getULong("MapSize", static_cast<unsigned long>(c_nMapSize) );
703             c_nInsThreadCount = cfg.getULong("InsThreadCount", static_cast<unsigned long>(c_nInsThreadCount) );
704             c_nDelThreadCount = cfg.getULong("DelThreadCount", static_cast<unsigned long>(c_nDelThreadCount) );
705             c_nExtractThreadCount = cfg.getULong("ExtractThreadCount", static_cast<unsigned long>(c_nExtractThreadCount) );
706             c_nMaxLoadFactor = cfg.getULong("MaxLoadFactor", static_cast<unsigned long>(c_nMaxLoadFactor) );
707             c_bPrintGCState = cfg.getBool("PrintGCStateFlag", true );
708
709             if ( c_nInsThreadCount == 0 )
710                 c_nInsThreadCount = cds::OS::topology::processor_count();
711             if ( c_nDelThreadCount == 0 && c_nExtractThreadCount == 0 ) {
712                 c_nExtractThreadCount = cds::OS::topology::processor_count() / 2;
713                 c_nDelThreadCount = cds::OS::topology::processor_count() - c_nExtractThreadCount;
714             }
715
716             m_arrData.resize( c_nMapSize );
717             for ( size_t i = 0; i < c_nMapSize; ++i )
718                 m_arrData[i] = i;
719             std::random_shuffle( m_arrData.begin(), m_arrData.end() );
720         }
721
722 #   include "map2/map_defs.h"
723         CDSUNIT_DECLARE_MichaelMap
724         CDSUNIT_DECLARE_SplitList
725         //CDSUNIT_DECLARE_StripedMap
726         //CDSUNIT_DECLARE_RefinableMap
727         CDSUNIT_DECLARE_CuckooMap
728         CDSUNIT_DECLARE_SkipListMap
729         CDSUNIT_DECLARE_EllenBinTreeMap
730         //CDSUNIT_DECLARE_StdMap
731
732         CPPUNIT_TEST_SUITE( Map_DelOdd )
733             CDSUNIT_TEST_MichaelMap
734             CDSUNIT_TEST_SplitList
735             CDSUNIT_TEST_SkipListMap
736             CDSUNIT_TEST_EllenBinTreeMap
737             //CDSUNIT_TEST_StripedMap
738             //CDSUNIT_TEST_RefinableMap
739             CDSUNIT_TEST_CuckooMap
740             //CDSUNIT_TEST_StdMap
741         CPPUNIT_TEST_SUITE_END()
742     };
743
744     CPPUNIT_TEST_SUITE_REGISTRATION( Map_DelOdd );
745 } // namespace map2