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