2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "map2/map_type.h"
32 #include "cppunit/thread.h"
38 #define TEST_CASE(TAG, X) void X();
40 class Map_InsDel_Item_int: public CppUnitMini::TestCase
43 size_t c_nMapSize = 1000000; // map size
44 size_t c_nThreadCount = 4; // thread count
45 size_t c_nAttemptCount = 100000; // count of SUCCESS insert/delete for each thread
46 size_t c_nMaxLoadFactor = 8; // maximum load factor
47 bool c_bPrintGCState = true;
49 size_t c_nCuckooInitialSize = 1024; // initial size for CuckooMap
50 size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
51 size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
53 size_t c_nFeldmanMap_HeadBits = 10;
54 size_t c_nFeldmanMap_ArrayBits = 4;
57 size_t c_nLoadFactor = 2; // current load factor
60 typedef size_t key_type;
61 typedef size_t value_type;
64 class Inserter: public CppUnitMini::TestThread
68 virtual Inserter * clone()
70 return new Inserter( *this );
75 void operator()( bool bNew, std::pair<key_type const, value_type>& item )
78 item.second = item.first;
80 // for boost::container::flat_map
81 void operator()( bool bNew, std::pair<key_type, value_type>& item )
84 item.second = item.first;
87 // for BronsonAVLTreeMap
88 void operator()( bool bNew, key_type key, value_type& val )
95 void operator()( std::pair<key_type const, value_type>& item, std::pair<key_type const, value_type> * pOld )
98 item.second = item.first;
103 size_t m_nInsertSuccess;
104 size_t m_nInsertFailed;
107 Inserter( CppUnitMini::ThreadPool& pool, Map& rMap )
108 : CppUnitMini::TestThread( pool )
111 Inserter( Inserter& src )
112 : CppUnitMini::TestThread( src )
116 Map_InsDel_Item_int& getTest()
118 return reinterpret_cast<Map_InsDel_Item_int&>( m_Pool.m_Test );
121 virtual void init() { cds::threading::Manager::attachThread() ; }
122 virtual void fini() { cds::threading::Manager::detachThread() ; }
131 size_t nGoalItem = getTest().c_nGoalItem;
132 size_t const nAttemptCount = getTest().c_nAttemptCount;
134 for ( size_t nAttempt = 0; nAttempt < nAttemptCount; ) {
135 if ( nAttempt % 2 == 0 ) {
136 if ( rMap.insert( nGoalItem, nGoalItem )) {
144 std::pair<bool, bool> updateResult = rMap.update( nGoalItem, update_func(), true );
145 if ( updateResult.second ) {
157 class Deleter: public CppUnitMini::TestThread
161 virtual Deleter * clone()
163 return new Deleter( *this );
166 size_t m_nDeleteSuccess;
167 size_t m_nDeleteFailed;
170 Deleter( CppUnitMini::ThreadPool& pool, Map& rMap )
171 : CppUnitMini::TestThread( pool )
174 Deleter( Deleter& src )
175 : CppUnitMini::TestThread( src )
179 Map_InsDel_Item_int& getTest()
181 return reinterpret_cast<Map_InsDel_Item_int&>( m_Pool.m_Test );
184 virtual void init() { cds::threading::Manager::attachThread() ; }
185 virtual void fini() { cds::threading::Manager::detachThread() ; }
194 size_t nGoalItem = getTest().c_nGoalItem;
195 size_t const nAttemptCount = getTest().c_nAttemptCount;
196 for ( size_t nAttempt = 0; nAttempt < nAttemptCount; ) {
197 if ( rMap.erase( nGoalItem )) {
210 void do_test( Map& testMap )
212 typedef Inserter<Map> InserterThread;
213 typedef Deleter<Map> DeleterThread;
214 cds::OS::Timer timer;
217 CPPUNIT_MSG( " Fill map (" << c_nMapSize << " items)...");
220 std::vector<key_type> v;
221 v.reserve( c_nMapSize );
222 for ( size_t i = 0; i < c_nMapSize; ++i )
224 shuffle( v.begin(), v.end() );
225 for ( size_t i = 0; i < v.size(); ++i ) {
226 CPPUNIT_ASSERT( testMap.insert( v[i], v[i] ));
229 CPPUNIT_MSG( " Duration=" << timer.duration() );
231 CPPUNIT_MSG( " Insert/delete the key " << c_nGoalItem << " (" << c_nAttemptCount << " successful times)...");
232 CppUnitMini::ThreadPool pool( *this );
233 pool.add( new InserterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
234 pool.add( new DeleterThread( pool, testMap ), (c_nThreadCount + 1) / 2 );
236 CPPUNIT_MSG( " Duration=" << pool.avgDuration() );
238 size_t nInsertSuccess = 0;
239 size_t nInsertFailed = 0;
240 size_t nDeleteSuccess = 0;
241 size_t nDeleteFailed = 0;
242 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
243 InserterThread * pThread = dynamic_cast<InserterThread *>( *it );
245 CPPUNIT_CHECK( pThread->m_nInsertSuccess == c_nAttemptCount );
246 nInsertSuccess += pThread->m_nInsertSuccess;
247 nInsertFailed += pThread->m_nInsertFailed;
250 DeleterThread * p = static_cast<DeleterThread *>( *it );
251 CPPUNIT_CHECK( p->m_nDeleteSuccess == c_nAttemptCount );
252 nDeleteSuccess += p->m_nDeleteSuccess;
253 nDeleteFailed += p->m_nDeleteFailed;
256 CPPUNIT_CHECK( nInsertSuccess == nDeleteSuccess );
257 size_t nGoalItem = c_nGoalItem;
258 CPPUNIT_CHECK( testMap.contains( nGoalItem ));
261 CPPUNIT_MSG( " Totals: Ins fail=" << nInsertFailed << " Del fail=" << nDeleteFailed );
263 // Check if the map contains all items
264 CPPUNIT_MSG( " Check if the map contains all items" );
266 for ( size_t i = 0; i < c_nMapSize; ++i ) {
267 CPPUNIT_CHECK_EX( testMap.contains( i ), "key " << i );
269 CPPUNIT_MSG( " Duration=" << timer.duration() );
271 check_before_cleanup( testMap );
274 additional_check( testMap );
275 print_stat( testMap );
276 additional_cleanup( testMap );
282 if ( Map::c_bLoadFactorDepended ) {
283 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
284 CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
285 Map testMap( *this );
287 if ( c_bPrintGCState )
292 Map testMap( *this );
293 do_test<Map>( testMap );
294 if ( c_bPrintGCState )
299 void setUpParams( const CppUnitMini::TestCfg& cfg );
301 # include "map2/map_defs.h"
302 CDSUNIT_DECLARE_MichaelMap
303 CDSUNIT_DECLARE_SplitList
304 CDSUNIT_DECLARE_SkipListMap
305 CDSUNIT_DECLARE_EllenBinTreeMap
306 CDSUNIT_DECLARE_BronsonAVLTreeMap
307 CDSUNIT_DECLARE_FeldmanHashMap_fixed
308 CDSUNIT_DECLARE_FeldmanHashMap_city
309 CDSUNIT_DECLARE_StripedMap
310 CDSUNIT_DECLARE_RefinableMap
311 CDSUNIT_DECLARE_CuckooMap
312 // CDSUNIT_DECLARE_StdMap // very slow!!
314 CPPUNIT_TEST_SUITE(Map_InsDel_Item_int)
315 CDSUNIT_TEST_MichaelMap
316 CDSUNIT_TEST_SplitList
317 CDSUNIT_TEST_SkipListMap
318 CDSUNIT_TEST_EllenBinTreeMap
319 CDSUNIT_TEST_BronsonAVLTreeMap
320 CDSUNIT_TEST_FeldmanHashMap_fixed
321 CDSUNIT_TEST_FeldmanHashMap_city
322 //CDSUNIT_TEST_CuckooMap
323 //CDSUNIT_TEST_StripedMap
324 //CDSUNIT_TEST_RefinableMap
325 // CDSUNIT_TEST_StdMap // very slow!!
326 CPPUNIT_TEST_SUITE_END();