- void do_test_extract_with( Set& testSet )
- {
- typedef Inserter<Set> insert_thread;
- typedef Deleter<Set> delete_thread;
- typedef Extractor< typename Set::gc, Set > extract_thread;
- typedef Observer<Set> observer_thread;
-
- m_nInsThreadCount.store( s_nInsThreadCount, atomics::memory_order_release );
-
- cds_test::thread_pool& pool = get_pool();
- pool.add( new insert_thread( pool, testSet ), s_nInsThreadCount );
- if ( s_nDelThreadCount )
- pool.add( new delete_thread( pool, testSet ), s_nDelThreadCount );
- if ( s_nExtractThreadCount )
- pool.add( new extract_thread( pool, testSet ), s_nExtractThreadCount );
- if ( s_nFindThreadCount )
- pool.add( new observer_thread( pool, testSet ), s_nFindThreadCount );
-
- propout() << std::make_pair( "insert_thread_count", s_nInsThreadCount )
- << std::make_pair( "delete_thread_count", s_nDelThreadCount )
- << std::make_pair( "extract_thread_count", s_nExtractThreadCount )
- << std::make_pair( "find_thread_count", s_nFindThreadCount )
- << std::make_pair( "set_size", s_nSetSize )
- << std::make_pair( "pass_count", s_nInsertPassCount );
-
- std::chrono::milliseconds duration = pool.run();
-
- propout() << std::make_pair( "duration", duration );
-
- size_t nInsertInitFailed = 0;
- size_t nInsertInitSuccess = 0;
- size_t nInsertSuccess = 0;
- size_t nInsertFailed = 0;
- size_t nDeleteSuccess = 0;
- size_t nDeleteFailed = 0;
- size_t nExtractSuccess = 0;
- size_t nExtractFailed = 0;
-
- size_t nFindEvenSuccess = 0;
- size_t nFindEvenFailed = 0;
- size_t nFindOddSuccess = 0;
- size_t nFindOddFailed = 0;
-
- for ( size_t i = 0; i < pool.size(); ++i ) {
- cds_test::thread& thr = pool.get( i );
- switch ( thr.type()) {
- case inserter_thread:
- {
- insert_thread& inserter = static_cast<insert_thread&>( thr );
- nInsertSuccess += inserter.m_nInsertSuccess;
- nInsertFailed += inserter.m_nInsertFailed;
- nInsertInitSuccess += inserter.m_nInsertInitSuccess;
- nInsertInitFailed += inserter.m_nInsertInitFailed;
- }
- break;
- case deleter_thread:
- {
- delete_thread& deleter = static_cast<delete_thread&>(thr);
- nDeleteSuccess += deleter.m_nDeleteSuccess;
- nDeleteFailed += deleter.m_nDeleteFailed;
- }
- break;
- case extractor_thread:
- {
- extract_thread& extractor = static_cast<extract_thread&>(thr);
- nExtractSuccess += extractor.m_nExtractSuccess;
- nExtractFailed += extractor.m_nExtractFailed;
- }
- break;
- case find_thread:
- {
- observer_thread& observer = static_cast<observer_thread&>( thr );
- nFindEvenSuccess = observer.m_nFindEvenSuccess;
- nFindEvenFailed = observer.m_nFindEvenFailed;
- nFindOddSuccess = observer.m_nFindOddSuccess;
- nFindOddFailed = observer.m_nFindOddFailed;
- }
- break;
- default:
- assert( false );
- }
- }
-
- size_t const nInitialOddKeys = ( s_nSetSize * s_nInsThreadCount ) / 2;
-
- EXPECT_EQ( nInsertInitFailed, 0u );
- EXPECT_EQ( nInsertInitSuccess, s_nSetSize * s_nInsThreadCount );
- EXPECT_EQ( nFindEvenFailed, 0u );
- EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess + nExtractSuccess );
- EXPECT_LE( nInsertSuccess, nDeleteSuccess + nExtractSuccess );
-
- propout()
- << std::make_pair( "insert_init_success", nInsertInitSuccess )
- << std::make_pair( "insert_init_failed", nInsertInitFailed )
- << std::make_pair( "insert_success", nInsertSuccess )
- << std::make_pair( "insert_failed", nInsertFailed )
- << std::make_pair( "delete_success", nDeleteSuccess )
- << std::make_pair( "delete_failed", nDeleteFailed )
- << std::make_pair( "extract_success", nExtractSuccess )
- << std::make_pair( "extract_failed", nExtractFailed )
- << std::make_pair( "find_even_success", nFindEvenSuccess )
- << std::make_pair( "find_even_failed", nFindEvenFailed )
- << std::make_pair( "find_odd_success", nFindOddSuccess )
- << std::make_pair( "find_odd_failed", nFindOddFailed );
+ void do_test_extract_with(Set &testSet, size_t pass_count) {
+ typedef Inserter<Set> insert_thread;
+ typedef Deleter<Set> delete_thread;
+ typedef Extractor<typename Set::gc, Set> extract_thread;
+ typedef Observer<Set> observer_thread;
+
+ size_t nInsertSuccess = 0;
+ size_t nInsertFailed = 0;
+ size_t nDeleteSuccess = 0;
+ size_t nDeleteFailed = 0;
+ size_t nExtractSuccess = 0;
+ size_t nExtractFailed = 0;
+ size_t nFindEvenSuccess = 0;
+ size_t nFindEvenFailed = 0;
+ size_t nFindOddSuccess = 0;
+ size_t nFindOddFailed = 0;
+
+ auto reset_stat = [&]() {
+ nInsertSuccess = 0;
+ nInsertFailed = 0;
+ nDeleteSuccess = 0;
+ nDeleteFailed = 0;
+ nExtractSuccess = 0;
+ nExtractFailed = 0;
+ nFindEvenSuccess = 0;
+ nFindEvenFailed = 0;
+ nFindOddSuccess = 0;
+ nFindOddFailed = 0;
+ };
+
+ auto insert_func = [&]() {
+ for (auto el : m_arrData) {
+ if (testSet.insert(key_type(el, 0)))
+ ++nInsertSuccess;
+ else
+ ++nInsertFailed;
+ }
+ };
+
+ auto delete_func = [&]() {
+ for (auto el : m_arrData) {
+ if (el & 1) {
+ if (testSet.erase(key_type(el, 0)))
+ ++nDeleteSuccess;
+ else
+ ++nDeleteFailed;
+ }
+ }
+ };
+
+ auto extract_func = [&]() {
+ for (auto el : m_arrData) {
+ if (el & 1) {
+ auto gp = testSet.extract(key_type(el, 0));
+ if (gp)
+ ++nExtractSuccess;
+ else
+ ++nExtractFailed;
+ gp.release();
+ }
+ }
+ };
+
+ auto find_func = [&]() {
+ for (size_t el : m_arrData) {
+ if (el & 1) {
+ if (testSet.contains(key_thread(el, 0)))
+ ++nFindOddSuccess;
+ else
+ ++nFindOddFailed;
+ } else {
+ // even keys MUST be in the map
+ if (testSet.contains(key_thread(el, 0)))
+ ++nFindEvenSuccess;
+ else
+ ++nFindEvenFailed;
+ }
+ }
+ };
+
+ auto test_func = [&](size_t count, std::function<void()> func) {
+ for (size_t i = 0; i < count; ++i) {
+ func();
+ }
+ };
+
+ size_t const nInitialOddKeys = s_nSetSize / 2;
+ size_t const nInitialEvenKeys = s_nSetSize / 2;
+ for (size_t nPass = 0; nPass < pass_count; ++nPass) {
+ // Start with an empty set.
+ testSet.clear();
+ reset_stat();
+
+ test_func(s_nInsertPassCount, insert_func);
+ EXPECT_EQ(nInsertSuccess, s_nSetSize);
+ reset_stat();
+
+ test_func(s_nFindPassCount, find_func);
+ EXPECT_EQ(nFindEvenFailed, 0u);
+ EXPECT_EQ(nFindOddFailed, 0u);
+ reset_stat();
+
+ test_func(s_nDeletePassCount, delete_func);
+ EXPECT_EQ(nDeleteSuccess, nInitialOddKeys);
+ reset_stat();
+
+ test_func(s_nInsertPassCount, insert_func);
+ EXPECT_EQ(nInsertSuccess, nInitialOddKeys);
+ reset_stat();
+
+ test_func(s_nDeletePassCount, extract_func);
+ EXPECT_EQ(nExtractSuccess, nInitialOddKeys);
+ reset_stat();
+
+ test_func(s_nFindPassCount, find_func);
+ EXPECT_EQ(nFindEvenFailed, 0u);
+ EXPECT_EQ(nFindOddSuccess, 0u);
+ }
+
+ // std::chrono::duration<double> time_elapsed;
+ // std::chrono::duration<double> time_diff;
+ // std::chrono::time_point<std::chrono::steady_clock>
+ // time_start;
+ // std::chrono::time_point<std::chrono::steady_clock>
+ // time_end;
+ // time_start = std::chrono::steady_clock::now();
+ // time_end = std::chrono::steady_clock::now();
+ // time_diff = time_end - time_start;
+ // time_elapsed = time_diff;
+ // std::cout << "Time elapsed: " << time_elapsed.count() <<
+ // "\n";