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