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