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"
37 #define TEST_CASE(TAG, X) void X();
39 class Map_InsDelFind: public CppUnitMini::TestCase
42 size_t c_nMapSize = 500000; // initial map size
43 size_t c_nThreadCount = 8; // thread count
44 size_t c_nMaxLoadFactor = 8; // maximum load factor
45 unsigned int c_nInsertPercentage = 5;
46 unsigned int c_nDeletePercentage = 5;
47 unsigned int c_nDuration = 30; // test duration, seconds
48 bool c_bPrintGCState = true;
50 size_t c_nCuckooInitialSize = 1024;// initial size for CuckooMap
51 size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
52 size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
54 size_t c_nFeldmanMap_HeadBits = 10;
55 size_t c_nFeldmanMap_ArrayBits = 4;
57 size_t c_nLoadFactor = 2; // current load factor
66 static const unsigned int c_nShuffleSize = 100;
67 actions m_arrShuffle[c_nShuffleSize];
70 typedef size_t key_type;
71 typedef size_t value_type;
74 class WorkThread: public CppUnitMini::TestThread
78 virtual WorkThread * clone()
80 return new WorkThread( *this );
83 size_t m_nInsertSuccess;
84 size_t m_nInsertFailed;
85 size_t m_nDeleteSuccess;
86 size_t m_nDeleteFailed;
87 size_t m_nFindSuccess;
91 WorkThread( CppUnitMini::ThreadPool& pool, Map& rMap )
92 : CppUnitMini::TestThread( pool )
95 WorkThread( WorkThread& src )
96 : CppUnitMini::TestThread( src )
100 Map_InsDelFind& getTest()
102 return reinterpret_cast<Map_InsDelFind&>( m_Pool.m_Test );
105 virtual void init() { cds::threading::Manager::attachThread() ; }
106 virtual void fini() { cds::threading::Manager::detachThread() ; }
108 typedef std::pair< key_type const, value_type > map_value_type;
110 struct update_functor {
111 template <typename Q>
112 void operator()( bool /*bNew*/, map_value_type& /*cur*/, Q const& /*val*/ )
116 void operator()( map_value_type& /*cur*/, map_value_type * /*old*/)
120 void operator()( bool /*bNew*/, map_value_type& /*cur*/ )
124 void operator()( bool /*bNew*/, key_type /*key*/, value_type& /*val*/ )
139 actions * pAct = getTest().m_arrShuffle;
141 size_t const nNormalize = size_t(-1) / (getTest().c_nMapSize * 2);
144 while ( !time_elapsed() ) {
145 nRand = cds::bitop::RandXorShift(nRand);
146 size_t n = nRand / nNormalize;
149 if ( rMap.contains( n ))
156 if ( rMap.insert( n, n ))
162 if ( rMap.update(n, update_functor(), true ).first )
169 if ( rMap.erase( n ))
176 if ( ++i >= c_nShuffleSize )
184 void do_test( Map& testMap )
186 typedef WorkThread<Map> work_thread;
187 cds::OS::Timer timer;
189 // fill map - only odd number
191 std::vector<size_t> arr;
192 arr.reserve( c_nMapSize );
193 for ( size_t i = 0; i < c_nMapSize; ++i )
194 arr.push_back( i * 2 + 1);
195 shuffle( arr.begin(), arr.end() );
196 for ( size_t i = 0; i < c_nMapSize; ++i )
197 testMap.insert( arr[i], arr[i] );
199 CPPUNIT_MSG( " Insert " << c_nMapSize << " items time (single-threaded)=" << timer.duration() );
202 CppUnitMini::ThreadPool pool( *this );
203 pool.add( new work_thread( pool, testMap ), c_nThreadCount );
204 pool.run( c_nDuration );
205 //CPPUNIT_MSG( " Duration=" << pool.avgDuration() );
207 size_t nInsertSuccess = 0;
208 size_t nInsertFailed = 0;
209 size_t nDeleteSuccess = 0;
210 size_t nDeleteFailed = 0;
211 size_t nFindSuccess = 0;
212 size_t nFindFailed = 0;
213 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
214 work_thread * pThread = static_cast<work_thread *>( *it );
215 assert( pThread != nullptr );
216 nInsertSuccess += pThread->m_nInsertSuccess;
217 nInsertFailed += pThread->m_nInsertFailed;
218 nDeleteSuccess += pThread->m_nDeleteSuccess;
219 nDeleteFailed += pThread->m_nDeleteFailed;
220 nFindSuccess += pThread->m_nFindSuccess;
221 nFindFailed += pThread->m_nFindFailed;
224 size_t nTotalOps = nInsertSuccess + nInsertFailed + nDeleteSuccess + nDeleteFailed + nFindSuccess + nFindFailed;
226 CPPUNIT_MSG( " Totals (success/failed): \n\t"
227 << " Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
228 << " Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
229 << " Find=" << nFindSuccess << '/' << nFindFailed << "\n\t"
230 << " Speed=" << (nFindSuccess + nFindFailed) / c_nDuration << " find/sec\n\t"
231 << " " << (nInsertSuccess + nDeleteSuccess) / c_nDuration << " modify/sec\n\t"
232 << " Total ops=" << nTotalOps << "\n\t"
233 << " speed=" << nTotalOps / c_nDuration << " ops/sec\n\t"
234 << " Map size=" << testMap.size()
238 check_before_cleanup( testMap );
240 CPPUNIT_MSG( " Clear map (single-threaded)..." );
243 CPPUNIT_MSG( " Duration=" << timer.duration() );
244 CPPUNIT_CHECK_EX( testMap.empty(), "size=" << ((long long) testMap.size()) );
246 additional_check( testMap );
247 print_stat( testMap );
248 additional_cleanup( testMap );
254 CPPUNIT_MSG( "Thread count=" << c_nThreadCount
255 << " initial map size=" << c_nMapSize
256 << " insert=" << c_nInsertPercentage << '%'
257 << " delete=" << c_nDeletePercentage << '%'
258 << " duration=" << c_nDuration << "s"
261 if ( Map::c_bLoadFactorDepended ) {
262 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
263 CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
264 Map testMap( *this );
266 if ( c_bPrintGCState )
271 Map testMap( *this );
273 if ( c_bPrintGCState )
278 void setUpParams( const CppUnitMini::TestCfg& cfg );
280 # include "map2/map_defs.h"
281 CDSUNIT_DECLARE_MichaelMap
282 CDSUNIT_DECLARE_SplitList
283 CDSUNIT_DECLARE_SkipListMap
284 CDSUNIT_DECLARE_EllenBinTreeMap
285 CDSUNIT_DECLARE_BronsonAVLTreeMap
286 CDSUNIT_DECLARE_FeldmanHashMap_fixed
287 CDSUNIT_DECLARE_FeldmanHashMap_city
288 CDSUNIT_DECLARE_StripedMap
289 CDSUNIT_DECLARE_RefinableMap
290 CDSUNIT_DECLARE_CuckooMap
291 CDSUNIT_DECLARE_StdMap
293 CPPUNIT_TEST_SUITE_(Map_InsDelFind, "map_insdelfind")
294 CDSUNIT_TEST_MichaelMap
295 CDSUNIT_TEST_SplitList
296 CDSUNIT_TEST_SkipListMap
297 CDSUNIT_TEST_EllenBinTreeMap
298 CDSUNIT_TEST_BronsonAVLTreeMap
299 CDSUNIT_TEST_FeldmanHashMap_fixed
300 CDSUNIT_TEST_FeldmanHashMap_city
301 CDSUNIT_TEST_CuckooMap
302 CDSUNIT_TEST_StripedMap
303 CDSUNIT_TEST_RefinableMap
305 CPPUNIT_TEST_SUITE_END();