InsThreadCount=3\r
DelThreadCount=2\r
ExtractThreadCount=2\r
+FindThreadCount=2\r
MaxLoadFactor=4\r
PassCount=30\r
\r
InsThreadCount=2
DelThreadCount=2
ExtractThreadCount=2
+FindThreadCount=2
MaxLoadFactor=4
PassCount=40
\r
[map_delodd]\r
MapSize=10000\r
-InsThreadCount=4\r
-DelThreadCount=3\r
-ExtractThreadCount=3\r
+InsThreadCount=3\r
+DelThreadCount=2\r
+ExtractThreadCount=2\r
+FindThreadCount=2\r
MaxLoadFactor=4\r
-PassCount=50\r
+PassCount=70\r
\r
#Cuckoo map properties\r
CuckooInitialSize=1024\r
InsThreadCount=4\r
DelThreadCount=3\r
ExtractThreadCount=3\r
+FindThreadCount=2\r
MaxLoadFactor=4\r
PassCount=100\r
\r
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;
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 )
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)
inserter_thread,
deleter_thread,
extractor_thread,
+ find_thread,
};
// Inserts keys from [0..N)
}
};
+ // Finds keys
+ template <class Map>
+ 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<Map_DelOdd>();
+ std::vector<size_t> 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 <class Map>
void do_test( Map& testMap )
{
typedef Inserter<Map> insert_thread;
typedef Deleter<Map> delete_thread;
+ typedef Observer<Map> 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 );
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<insert_thread&>(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<delete_thread&>(thr);
- nDeleteSuccess += deleter.m_nDeleteSuccess;
- nDeleteFailed += deleter.m_nDeleteFailed;
+ 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 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;
}
}
EXPECT_EQ( nInsertInitFailed, 0u );
EXPECT_EQ( nInsertInitSuccess, s_nMapSize * s_nInsThreadCount );
+ EXPECT_EQ( nFindEvenFailed, 0u );
EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess );
EXPECT_LE( nInsertSuccess, nDeleteSuccess );
<< 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 );
}
typedef Inserter<Map> insert_thread;
typedef Deleter<Map> delete_thread;
typedef Extractor< typename Map::gc, Map > extract_thread;
+ typedef Observer<Map> observer_thread;
m_nInsThreadCount.store( s_nInsThreadCount, atomics::memory_order_release );
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 );
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()) {
nExtractFailed += extractor.m_nDeleteFailed;
}
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 );
}
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 );
<< 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 );
}
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;
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 )
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)
inserter_thread,
deleter_thread,
extractor_thread,
+ find_thread
};
}
};
+ // Finds keys
+ template <class Set>
+ 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<Set_DelOdd>();
+ std::vector<size_t> 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 <class Set>
void do_test_with( Set& testSet )
{
typedef Inserter<Set> insert_thread;
typedef Deleter<Set> delete_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 );
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 );
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<insert_thread&>(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<delete_thread&>(thr);
- nDeleteSuccess += deleter.m_nDeleteSuccess;
- nDeleteFailed += deleter.m_nDeleteFailed;
+ 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 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 );
}
}
EXPECT_EQ( nInsertInitFailed, 0u );
EXPECT_EQ( nInsertInitSuccess, s_nSetSize * s_nInsThreadCount );
+ EXPECT_EQ( nFindEvenFailed, 0u );
EXPECT_GE( nInsertSuccess + nInitialOddKeys, nDeleteSuccess );
EXPECT_LE( nInsertSuccess, nDeleteSuccess );
<< 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 <class Set>
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 );
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 );
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()) {
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 );
}
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 );
<< 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 <typename Set>