a8778307dcd21bfc01079e4f4ea13be67fd6c7b6
[libcds.git] / test / stress / set / insdel_find / set_insdelfind.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.
29 */
30
31 #include "set_type.h"
32
33 namespace set {
34
35     class Set_InsDelFind: public cds_test::stress_fixture
36     {
37     public:
38         static size_t s_nSetSize;           // initial set size
39         static size_t s_nThreadCount;       // thread count
40         static size_t s_nMaxLoadFactor;     // maximum load factor
41         static unsigned int s_nInsertPercentage;
42         static unsigned int s_nDeletePercentage;
43         static unsigned int s_nDuration;   // test duration, seconds
44
45         static size_t  s_nCuckooInitialSize;        // initial size for CuckooSet
46         static size_t  s_nCuckooProbesetSize;       // CuckooSet probeset size (only for list-based probeset)
47         static size_t  s_nCuckooProbesetThreshold;  // CUckooSet probeset threshold (0 - use default)
48
49         static size_t s_nFeldmanSet_HeadBits;
50         static size_t s_nFeldmanSet_ArrayBits;
51
52         static size_t s_nLoadFactor;
53
54         static void SetUpTestCase();
55         //static void TearDownTestCase();
56
57     public:
58         enum actions
59         {
60             do_find,
61             do_insert,
62             do_delete
63         };
64         static const unsigned int c_nShuffleSize = 100;
65         actions m_arrShuffle[c_nShuffleSize];
66
67     protected:
68         typedef size_t  key_type;
69         typedef size_t  value_type;
70
71         template <class Set>
72         class Worker: public cds_test::thread
73         {
74             typedef cds_test::thread base_class;
75             Set&     m_Set;
76
77         public:
78             size_t  m_nInsertSuccess = 0;
79             size_t  m_nInsertFailed = 0;
80             size_t  m_nDeleteSuccess = 0;
81             size_t  m_nDeleteFailed = 0;
82             size_t  m_nFindSuccess = 0;
83             size_t  m_nFindFailed = 0;
84
85         public:
86             Worker( cds_test::thread_pool& pool, Set& set )
87                 : base_class( pool )
88                 , m_Set( set )
89             {}
90
91             Worker( Worker& src )
92                 : base_class( src )
93                 , m_Set( src.m_Set )
94             {}
95
96             virtual thread * clone()
97             {
98                 return new Worker( *this );
99             }
100
101             virtual void test()
102             {
103                 Set& rSet = m_Set;
104                 Set_InsDelFind& fixture = pool().template fixture<Set_InsDelFind>();
105
106                 actions * pAct = fixture.m_arrShuffle;
107                 unsigned int i = 0;
108                 size_t const nNormalize = size_t(-1) / ( fixture.s_nSetSize * 2);
109
110                 typedef typename Set::value_type value_type;
111
112                 size_t nRand = 0;
113                 while ( !time_elapsed()) {
114                     nRand = cds::bitop::RandXorShift(nRand);
115                     size_t n = nRand / nNormalize;
116                     switch ( pAct[i] ) {
117                     case do_find:
118                         if ( rSet.contains( n ))
119                             ++m_nFindSuccess;
120                         else
121                             ++m_nFindFailed;
122                         break;
123                     case do_insert:
124                         if ( rSet.insert( n ))
125                             ++m_nInsertSuccess;
126                         else
127                             ++m_nInsertFailed;
128                         break;
129                     case do_delete:
130                         if ( rSet.erase( n ))
131                             ++m_nDeleteSuccess;
132                         else
133                             ++m_nDeleteFailed;
134                         break;
135                     }
136
137                     if ( ++i >= c_nShuffleSize )
138                         i = 0;
139                 }
140             }
141         };
142
143     protected:
144         template <class Set>
145         void do_test( Set& testSet )
146         {
147             typedef Worker<Set> work_thread;
148
149             // fill map - only odd number
150             {
151                 size_t * pInitArr = new size_t[ s_nSetSize ];
152                 size_t * pEnd = pInitArr + s_nSetSize;
153                 for ( size_t i = 0; i < s_nSetSize; ++i )
154                     pInitArr[i] = i * 2 + 1;
155                 shuffle( pInitArr, pEnd );
156                 for ( size_t * p = pInitArr; p < pEnd; ++p )
157                     testSet.insert( typename Set::value_type( *p, *p ));
158                 delete [] pInitArr;
159             }
160
161             cds_test::thread_pool& pool = get_pool();
162             pool.add( new work_thread( pool, testSet ), s_nThreadCount );
163
164             propout() << std::make_pair( "thread_count", s_nThreadCount )
165                 << std::make_pair( "set_size", s_nSetSize )
166                 << std::make_pair( "insert_percentage", s_nInsertPercentage )
167                 << std::make_pair( "delete_percentage", s_nDeletePercentage )
168                 << std::make_pair( "total_duration", s_nDuration );
169
170             std::chrono::milliseconds duration = pool.run( std::chrono::seconds( s_nDuration ));
171
172             propout() << std::make_pair( "duration", duration );
173
174             size_t nInsertSuccess = 0;
175             size_t nInsertFailed = 0;
176             size_t nDeleteSuccess = 0;
177             size_t nDeleteFailed = 0;
178             size_t nFindSuccess = 0;
179             size_t nFindFailed = 0;
180             for ( size_t i = 0; i < pool.size(); ++i ) {
181                 work_thread& thr = static_cast<work_thread&>( pool.get( i ));
182                 nInsertSuccess += thr.m_nInsertSuccess;
183                 nInsertFailed  += thr.m_nInsertFailed;
184                 nDeleteSuccess += thr.m_nDeleteSuccess;
185                 nDeleteFailed  += thr.m_nDeleteFailed;
186                 nFindSuccess   += thr.m_nFindSuccess;
187                 nFindFailed    += thr.m_nFindFailed;
188             }
189
190             propout()
191                 << std::make_pair( "insert_success", nInsertSuccess )
192                 << std::make_pair( "insert_failed", nInsertFailed )
193                 << std::make_pair( "delete_success", nDeleteSuccess )
194                 << std::make_pair( "delete_failed", nDeleteFailed )
195                 << std::make_pair( "find_success", nFindSuccess )
196                 << std::make_pair( "find_failed", nFindFailed );
197
198             {
199                 ASSERT_TRUE( std::chrono::duration_cast<std::chrono::seconds>(duration).count() > 0 );
200                 size_t nTotalOps = nInsertSuccess + nInsertFailed + nDeleteSuccess + nDeleteFailed + nFindSuccess + nFindFailed;
201                 propout() << std::make_pair( "avg_speed", nTotalOps / std::chrono::duration_cast<std::chrono::seconds>(duration).count());
202             }
203
204
205             testSet.clear();
206             EXPECT_TRUE( testSet.empty()) << "set size=" << testSet.size();
207
208             additional_check( testSet );
209             print_stat( propout(), testSet );
210             additional_cleanup( testSet );
211         }
212
213         template <class Set>
214         void run_test()
215         {
216             Set s( *this );
217             do_test( s );
218         }
219     };
220
221     class Set_InsDelFind_LF: public Set_InsDelFind
222         , public ::testing::WithParamInterface<size_t>
223     {
224     public:
225         template <class Set>
226         void run_test()
227         {
228             s_nLoadFactor = GetParam();
229             propout() << std::make_pair( "load_factor", s_nLoadFactor );
230             Set_InsDelFind::run_test<Set>();
231         }
232
233         static std::vector<size_t> get_load_factors();
234     };
235
236 } // namespace set