From 46d71b0be93217b5daaa9f1aee8301b1ce7f0f4d Mon Sep 17 00:00:00 2001 From: khizmax Date: Mon, 28 Nov 2016 13:36:58 +0300 Subject: [PATCH] Added observer thread for calling contains() to stress-delodd tests --- test/stress/data/test-debug.conf | 1 + test/stress/data/test-express-x86.conf | 1 + test/stress/data/test-express.conf | 9 +- test/stress/data/test.conf | 1 + test/stress/map/delodd/map_delodd.cpp | 2 + test/stress/map/delodd/map_delodd.h | 144 ++++++++++++++++++++++--- test/stress/set/delodd/set_delodd.cpp | 2 + test/stress/set/delodd/set_delodd.h | 144 ++++++++++++++++++++++--- 8 files changed, 271 insertions(+), 33 deletions(-) diff --git a/test/stress/data/test-debug.conf b/test/stress/data/test-debug.conf index e46778ea..9c57b513 100644 --- a/test/stress/data/test-debug.conf +++ b/test/stress/data/test-debug.conf @@ -261,6 +261,7 @@ MapSize=10000 InsThreadCount=3 DelThreadCount=2 ExtractThreadCount=2 +FindThreadCount=2 MaxLoadFactor=4 PassCount=30 diff --git a/test/stress/data/test-express-x86.conf b/test/stress/data/test-express-x86.conf index 192b54af..8362345b 100644 --- a/test/stress/data/test-express-x86.conf +++ b/test/stress/data/test-express-x86.conf @@ -255,6 +255,7 @@ MapSize=10000 InsThreadCount=2 DelThreadCount=2 ExtractThreadCount=2 +FindThreadCount=2 MaxLoadFactor=4 PassCount=40 diff --git a/test/stress/data/test-express.conf b/test/stress/data/test-express.conf index fc17f519..559b893f 100644 --- a/test/stress/data/test-express.conf +++ b/test/stress/data/test-express.conf @@ -252,11 +252,12 @@ FeldmanMapArrayBits=4 [map_delodd] MapSize=10000 -InsThreadCount=4 -DelThreadCount=3 -ExtractThreadCount=3 +InsThreadCount=3 +DelThreadCount=2 +ExtractThreadCount=2 +FindThreadCount=2 MaxLoadFactor=4 -PassCount=50 +PassCount=70 #Cuckoo map properties CuckooInitialSize=1024 diff --git a/test/stress/data/test.conf b/test/stress/data/test.conf index 8fd4bcff..bc3ec554 100644 --- a/test/stress/data/test.conf +++ b/test/stress/data/test.conf @@ -253,6 +253,7 @@ MapSize=10000 InsThreadCount=4 DelThreadCount=3 ExtractThreadCount=3 +FindThreadCount=2 MaxLoadFactor=4 PassCount=100 diff --git a/test/stress/map/delodd/map_delodd.cpp b/test/stress/map/delodd/map_delodd.cpp index 50cc89f4..7cc7fdfd 100644 --- a/test/stress/map/delodd/map_delodd.cpp +++ b/test/stress/map/delodd/map_delodd.cpp @@ -36,6 +36,7 @@ namespace map { size_t Map_DelOdd::s_nInsThreadCount = 4; size_t Map_DelOdd::s_nDelThreadCount = 4; size_t Map_DelOdd::s_nExtractThreadCount = 4; + size_t Map_DelOdd::s_nFindThreadCount = 2; size_t Map_DelOdd::s_nMaxLoadFactor = 8; size_t Map_DelOdd::s_nInsertPassCount = 100; @@ -63,6 +64,7 @@ namespace map { s_nDelThreadCount = cfg.get_size_t( "DelThreadCount", s_nDelThreadCount ); s_nExtractThreadCount = cfg.get_size_t( "ExtractThreadCount", s_nExtractThreadCount ); + s_nFindThreadCount = cfg.get_size_t( "FindThreadCount", s_nFindThreadCount ); s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor ); if ( s_nMaxLoadFactor == 0 ) diff --git a/test/stress/map/delodd/map_delodd.h b/test/stress/map/delodd/map_delodd.h index a0979476..98d33fd6 100644 --- a/test/stress/map/delodd/map_delodd.h +++ b/test/stress/map/delodd/map_delodd.h @@ -120,6 +120,7 @@ namespace map { static size_t s_nMapSize; // max map size static size_t s_nMaxLoadFactor; // maximum load factor static size_t s_nInsertPassCount; + static size_t s_nFindThreadCount; // find thread count static size_t s_nCuckooInitialSize; // initial size for CuckooMap static size_t s_nCuckooProbesetSize; // CuckooMap probeset size (only for list-based probeset) @@ -158,6 +159,7 @@ namespace map { inserter_thread, deleter_thread, extractor_thread, + find_thread, }; // Inserts keys from [0..N) @@ -539,21 +541,85 @@ namespace map { } }; + // Finds keys + template + class Observer: public cds_test::thread + { + typedef cds_test::thread base_class; + Map& m_Map; + + public: + size_t m_nFindEvenSuccess = 0; + size_t m_nFindEvenFailed = 0; + size_t m_nFindOddSuccess = 0; + size_t m_nFindOddFailed = 0; + + public: + Observer( cds_test::thread_pool& pool, Map& map ) + : base_class( pool, find_thread ) + , m_Map( map ) + {} + + Observer( Observer& src ) + : base_class( src ) + , m_Map( src.m_Map ) + {} + + virtual thread * clone() + { + return new Observer( *this ); + } + + virtual void test() + { + Map& map = m_Map; + Map_DelOdd& fixture = pool().template fixture(); + std::vector const& arr = m_arrElements; + size_t const nInsThreadCount = s_nInsThreadCount; + + do { + for ( size_t key : arr ) { + if ( key & 1 ) { + for ( size_t k = 0; k < nInsThreadCount; ++k ) { + if ( map.contains( key_thread( key, k ))) + ++m_nFindOddSuccess; + else + ++m_nFindOddFailed; + } + } + else { + // even keys MUST be in the map + for ( size_t k = 0; k < nInsThreadCount; ++k ) { + if ( map.contains( key_thread( key, k ))) + ++m_nFindEvenSuccess; + else + ++m_nFindEvenFailed; + } + } + } + } while ( fixture.m_nInsThreadCount.load( atomics::memory_order_acquire ) != 0 ); + } + }; + protected: template void do_test( Map& testMap ) { typedef Inserter insert_thread; typedef Deleter delete_thread; + typedef Observer observer_thread; m_nInsThreadCount.store( s_nInsThreadCount, atomics::memory_order_release ); cds_test::thread_pool& pool = get_pool(); pool.add( new insert_thread( pool, testMap ), s_nInsThreadCount ); pool.add( new delete_thread( pool, testMap ), s_nDelThreadCount ? s_nDelThreadCount : cds::OS::topology::processor_count()); + if ( s_nFindThreadCount ) + pool.add( new observer_thread( pool, testMap ), s_nFindThreadCount ); propout() << std::make_pair( "insert_thread_count", s_nInsThreadCount ) << std::make_pair( "delete_thread_count", s_nDelThreadCount ) + << std::make_pair( "find_thread_count", s_nFindThreadCount ) << std::make_pair( "map_size", s_nMapSize ) << std::make_pair( "pass_count", s_nInsertPassCount ); @@ -568,20 +634,39 @@ namespace map { size_t nDeleteSuccess = 0; size_t nDeleteFailed = 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 ); - if ( thr.type() == inserter_thread ) { - insert_thread& inserter = static_cast(thr); - nInsertSuccess += inserter.m_nInsertSuccess; - nInsertFailed += inserter.m_nInsertFailed; - nInsertInitSuccess += inserter.m_nInsertInitSuccess; - nInsertInitFailed += inserter.m_nInsertInitFailed; - } - else { - assert( thr.type() == deleter_thread ); - delete_thread& deleter = static_cast(thr); - nDeleteSuccess += deleter.m_nDeleteSuccess; - nDeleteFailed += deleter.m_nDeleteFailed; + switch ( thr.type() ) { + case inserter_thread: + { + insert_thread& inserter = static_cast( 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( thr ); + nDeleteSuccess += deleter.m_nDeleteSuccess; + nDeleteFailed += deleter.m_nDeleteFailed; + } + break; + case find_thread: + { + observer_thread& observer = static_cast( thr ); + nFindEvenSuccess = observer.m_nFindEvenSuccess; + nFindEvenFailed = observer.m_nFindEvenFailed; + nFindOddSuccess = observer.m_nFindOddSuccess; + nFindOddFailed = observer.m_nFindOddFailed; + } + break; } } @@ -589,6 +674,7 @@ namespace map { EXPECT_EQ( nInsertInitFailed, 0u ); EXPECT_EQ( nInsertInitSuccess, s_nMapSize * s_nInsThreadCount ); + EXPECT_EQ( nFindEvenFailed, 0u ); EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess ); EXPECT_LE( nInsertSuccess, nDeleteSuccess ); @@ -596,9 +682,13 @@ namespace map { << 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( "insert_failed", nInsertFailed ) << std::make_pair( "delete_success", nDeleteSuccess ) - << std::make_pair( "delete_failed", nDeleteFailed ); + << std::make_pair( "delete_failed", nDeleteFailed ) + << 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 ); analyze( testMap ); } @@ -609,6 +699,7 @@ namespace map { typedef Inserter insert_thread; typedef Deleter delete_thread; typedef Extractor< typename Map::gc, Map > extract_thread; + typedef Observer observer_thread; m_nInsThreadCount.store( s_nInsThreadCount, atomics::memory_order_release ); @@ -618,10 +709,13 @@ namespace map { pool.add( new delete_thread( pool, testMap ), s_nDelThreadCount ); if ( s_nExtractThreadCount ) pool.add( new extract_thread( pool, testMap ), s_nExtractThreadCount ); + if ( s_nFindThreadCount ) + pool.add( new observer_thread( pool, testMap ), 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( "map_size", s_nMapSize ) << std::make_pair( "pass_count", s_nInsertPassCount ); @@ -637,6 +731,12 @@ namespace map { 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()) { @@ -663,6 +763,15 @@ namespace map { nExtractFailed += extractor.m_nDeleteFailed; } break; + case find_thread: + { + observer_thread& observer = static_cast( thr ); + nFindEvenSuccess = observer.m_nFindEvenSuccess; + nFindEvenFailed = observer.m_nFindEvenFailed; + nFindOddSuccess = observer.m_nFindOddSuccess; + nFindOddFailed = observer.m_nFindOddFailed; + } + break; default: assert( false ); } @@ -672,6 +781,7 @@ namespace map { EXPECT_EQ( nInsertInitFailed, 0u ); EXPECT_EQ( nInsertInitSuccess, s_nMapSize * s_nInsThreadCount ); + EXPECT_EQ( nFindEvenFailed, 0u ); EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess + nExtractSuccess ); EXPECT_LE( nInsertSuccess, nDeleteSuccess + nExtractSuccess ); @@ -683,7 +793,11 @@ namespace map { << 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( "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 ); analyze( testMap ); } diff --git a/test/stress/set/delodd/set_delodd.cpp b/test/stress/set/delodd/set_delodd.cpp index a6de8a8c..0ad1d671 100644 --- a/test/stress/set/delodd/set_delodd.cpp +++ b/test/stress/set/delodd/set_delodd.cpp @@ -36,6 +36,7 @@ namespace set { size_t Set_DelOdd::s_nInsThreadCount = 4; size_t Set_DelOdd::s_nDelThreadCount = 4; size_t Set_DelOdd::s_nExtractThreadCount = 4; + size_t Set_DelOdd::s_nFindThreadCount = 2; size_t Set_DelOdd::s_nMaxLoadFactor = 8; size_t Set_DelOdd::s_nInsertPassCount = 100; @@ -64,6 +65,7 @@ namespace set { s_nDelThreadCount = cfg.get_size_t( "DelThreadCount", s_nDelThreadCount ); s_nExtractThreadCount = cfg.get_size_t( "ExtractThreadCount", s_nExtractThreadCount ); + s_nFindThreadCount = cfg.get_size_t( "FindThreadCount", s_nFindThreadCount ); s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor ); if ( s_nMaxLoadFactor == 0 ) diff --git a/test/stress/set/delodd/set_delodd.h b/test/stress/set/delodd/set_delodd.h index a27fcad2..5400e3e5 100644 --- a/test/stress/set/delodd/set_delodd.h +++ b/test/stress/set/delodd/set_delodd.h @@ -122,6 +122,7 @@ namespace set { static size_t s_nExtractThreadCount; // extract thread count static size_t s_nMaxLoadFactor; // maximum load factor static size_t s_nInsertPassCount; + static size_t s_nFindThreadCount; // find thread count static size_t s_nCuckooInitialSize; // initial size for CuckooSet static size_t s_nCuckooProbesetSize; // CuckooSet probeset size (only for list-based probeset) @@ -159,6 +160,7 @@ namespace set { inserter_thread, deleter_thread, extractor_thread, + find_thread }; @@ -587,21 +589,85 @@ namespace set { } }; + // Finds keys + template + class Observer: public cds_test::thread + { + typedef cds_test::thread base_class; + Set& m_Set; + + public: + size_t m_nFindEvenSuccess = 0; + size_t m_nFindEvenFailed = 0; + size_t m_nFindOddSuccess = 0; + size_t m_nFindOddFailed = 0; + + public: + Observer( cds_test::thread_pool& pool, Set& set ) + : base_class( pool, find_thread ) + , m_Set( set ) + {} + + Observer( Observer& src ) + : base_class( src ) + , m_Set( src.m_Set ) + {} + + virtual thread * clone() + { + return new Observer( *this ); + } + + virtual void test() + { + Set& set = m_Set; + Set_DelOdd& fixture = pool().template fixture(); + std::vector const& arr = m_arrData; + size_t const nInsThreadCount = s_nInsThreadCount; + + do { + for ( size_t key : arr ) { + if ( key & 1 ) { + for ( size_t k = 0; k < nInsThreadCount; ++k ) { + if ( set.contains( key_thread( key, k ) ) ) + ++m_nFindOddSuccess; + else + ++m_nFindOddFailed; + } + } + else { + // even keys MUST be in the map + for ( size_t k = 0; k < nInsThreadCount; ++k ) { + if ( set.contains( key_thread( key, k ) ) ) + ++m_nFindEvenSuccess; + else + ++m_nFindEvenFailed; + } + } + } + } while ( fixture.m_nInsThreadCount.load( atomics::memory_order_acquire ) != 0 ); + } + }; + protected: template void do_test_with( Set& testSet ) { typedef Inserter insert_thread; typedef Deleter delete_thread; + typedef Observer 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 ); pool.add( new delete_thread( pool, testSet ), s_nDelThreadCount ? s_nDelThreadCount : cds::OS::topology::processor_count()); + 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( "find_thread_count", s_nFindThreadCount ) << std::make_pair( "set_size", s_nSetSize ) << std::make_pair( "pass_count", s_nInsertPassCount ); @@ -616,20 +682,41 @@ namespace set { size_t nDeleteSuccess = 0; size_t nDeleteFailed = 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 ); - if ( thr.type() == inserter_thread ) { - insert_thread& inserter = static_cast(thr); - nInsertSuccess += inserter.m_nInsertSuccess; - nInsertFailed += inserter.m_nInsertFailed; - nInsertInitSuccess += inserter.m_nInsertInitSuccess; - nInsertInitFailed += inserter.m_nInsertInitFailed; - } - else { - assert( thr.type() == deleter_thread ); - delete_thread& deleter = static_cast(thr); - nDeleteSuccess += deleter.m_nDeleteSuccess; - nDeleteFailed += deleter.m_nDeleteFailed; + switch ( thr.type()) { + case inserter_thread: + { + insert_thread& inserter = static_cast(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(thr); + nDeleteSuccess += deleter.m_nDeleteSuccess; + nDeleteFailed += deleter.m_nDeleteFailed; + } + break; + case find_thread: + { + observer_thread& observer = static_cast( thr ); + nFindEvenSuccess = observer.m_nFindEvenSuccess; + nFindEvenFailed = observer.m_nFindEvenFailed; + nFindOddSuccess = observer.m_nFindOddSuccess; + nFindOddFailed = observer.m_nFindOddFailed; + } + break; + default: + assert( false ); } } @@ -637,6 +724,7 @@ namespace set { EXPECT_EQ( nInsertInitFailed, 0u ); EXPECT_EQ( nInsertInitSuccess, s_nSetSize * s_nInsThreadCount ); + EXPECT_EQ( nFindEvenFailed, 0u ); EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess ); EXPECT_LE( nInsertSuccess, nDeleteSuccess ); @@ -646,7 +734,11 @@ namespace set { << 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( "delete_failed", nDeleteFailed ) + << 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 ); } template @@ -655,6 +747,7 @@ namespace set { typedef Inserter insert_thread; typedef Deleter delete_thread; typedef Extractor< typename Set::gc, Set > extract_thread; + typedef Observer observer_thread; m_nInsThreadCount.store( s_nInsThreadCount, atomics::memory_order_release ); @@ -664,10 +757,13 @@ namespace set { 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 ); @@ -683,6 +779,12 @@ namespace set { 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()) { @@ -709,6 +811,15 @@ namespace set { nExtractFailed += extractor.m_nExtractFailed; } break; + case find_thread: + { + observer_thread& observer = static_cast( thr ); + nFindEvenSuccess = observer.m_nFindEvenSuccess; + nFindEvenFailed = observer.m_nFindEvenFailed; + nFindOddSuccess = observer.m_nFindOddSuccess; + nFindOddFailed = observer.m_nFindOddFailed; + } + break; default: assert( false ); } @@ -718,6 +829,7 @@ namespace set { 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 ); @@ -729,7 +841,11 @@ namespace set { << 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( "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 ); } template -- 2.34.1