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