Uses different pass count for different parallel queue test cases
[libcds.git] / test / stress / map / delodd / map_delodd.h
index a0979476db910c2c9313e30232226902db5ca0a0..ea7a7fe5c7af1824965ae42c1d09aa077f8fbaf2 100644 (file)
@@ -1,7 +1,7 @@
 /*
     This file is a part of libcds - Concurrent Data Structures library
 
-    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
 
     Source code repo: http://github.com/khizmax/libcds/
     Download: http://sourceforge.net/projects/libcds/files/
@@ -29,6 +29,8 @@
 */
 
 #include "map_type.h"
+#include "../../misc/common.h"
+#include <cds/os/topology.h>
 
 namespace map {
 
@@ -120,6 +122,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)
@@ -138,13 +141,13 @@ namespace map {
         template <typename Pred>
         static void prepare_array( std::vector<size_t>& arr, Pred pred )
         {
-            arr.reserve( m_arrElements.size() );
+            arr.reserve( m_arrElements.size());
             for ( auto el : m_arrElements ) {
-                if ( pred( el ) )
+                if ( pred( el ))
                     arr.push_back( el );
             }
-            arr.resize( arr.size() );
-            shuffle( arr.begin(), arr.end() );
+            arr.resize( arr.size());
+            shuffle( arr.begin(), arr.end());
         }
 
     protected:
@@ -158,6 +161,7 @@ namespace map {
             inserter_thread,
             deleter_thread,
             extractor_thread,
+            find_thread,
         };
 
         // Inserts keys from [0..N)
@@ -187,7 +191,7 @@ namespace map {
             {
                 prepare_array( m_arr, []( size_t ) -> bool { return true; } );
                 for ( size_t i = 0; i < m_arr.size(); ++i ) {
-                    if ( m_Map.insert( key_type( m_arr[i], id() ) ) )
+                    if ( m_Map.insert( key_type( m_arr[i], id())))
                         ++m_nInsertInitSuccess;
                     else
                         ++m_nInsertInitFailed;
@@ -234,7 +238,7 @@ namespace map {
                         // insert pass
                         for ( auto el : m_arr ) {
                             if ( el & 1 ) {
-                                if ( rMap.insert( key_type( el, id() )))
+                                if ( rMap.insert( key_type( el, id())))
                                     ++m_nInsertSuccess;
                                 else
                                     ++m_nInsertFailed;
@@ -247,7 +251,7 @@ namespace map {
                             if ( el & 1 ) {
                                 bool success;
                                 bool inserted;
-                                std::tie( success, inserted ) = rMap.update( key_type( el, id() ), f );
+                                std::tie( success, inserted ) = rMap.update( key_type( el, id()), f );
                                 if ( success && inserted )
                                     ++m_nInsertSuccess;
                                 else
@@ -353,7 +357,7 @@ namespace map {
                     else {
                         for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                             for ( auto el: m_arr ) {
-                                if ( rMap.erase( key_type( el, k ) ) )
+                                if ( rMap.erase( key_type( el, k )))
                                     ++m_nDeleteSuccess;
                                 else
                                     ++m_nDeleteFailed;
@@ -428,7 +432,7 @@ namespace map {
                     else {
                         for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                             for ( auto el: m_arr ) {
-                                gp = rMap.extract( key_type( el, k ) );
+                                gp = rMap.extract( key_type( el, k ));
                                 if ( gp )
                                     ++m_nDeleteSuccess;
                                 else
@@ -494,14 +498,14 @@ namespace map {
                             for ( auto el: m_arr ) {
                                 if ( Map::c_bExtractLockExternal ) {
                                     typename Map::rcu_lock l;
-                                    xp = rMap.extract( key_type( el, k ) );
+                                    xp = rMap.extract( key_type( el, k ));
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
                                         ++m_nDeleteFailed;
                                 }
                                 else {
-                                    xp = rMap.extract( key_type( el, k ) );
+                                    xp = rMap.extract( key_type( el, k ));
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -516,14 +520,14 @@ namespace map {
                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                                 if ( Map::c_bExtractLockExternal ) {
                                     typename Map::rcu_lock l;
-                                    xp = rMap.extract( key_type( el, k ) );
+                                    xp = rMap.extract( key_type( el, k ));
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
                                         ++m_nDeleteFailed;
                                 }
                                 else {
-                                    xp = rMap.extract( key_type( el, k ) );
+                                    xp = rMap.extract( key_type( el, k ));
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -539,21 +543,85 @@ namespace map {
             }
         };
 
+        // 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 );
 
@@ -568,20 +636,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<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;
                 }
             }
 
@@ -589,6 +676,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,11 +684,15 @@ 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 );
+            DEBUG(analyze( testMap ));
         }
 
         template <class Map>
@@ -609,6 +701,7 @@ namespace map {
             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 );
 
@@ -618,10 +711,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 +733,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 +765,15 @@ namespace map {
                     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 );
                 }
@@ -672,6 +783,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,9 +795,13 @@ 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 );
+            DEBUG(analyze( testMap ));
         }
 
         template <class Map>