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