Runs fewer test cases (only 2 threads)
[libcds.git] / test / stress / queue / pop.cpp
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
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 "queue_type.h"
32 #include "../misc/common.h"
33
34 // Multi-threaded queue test for pop operation
35 namespace {
36
37     static size_t s_nThreadCount = 8;
38     static size_t s_nQueueSize = 20000000 ;   // no more than 20 million records
39
40         struct SimpleValue {
41             size_t    nNo;
42
43             SimpleValue(): nNo(0) {}
44             SimpleValue( size_t n ): nNo(n) {}
45             size_t getNo() const { return  nNo; }
46         };
47
48     class queue_pop: public cds_test::stress_fixture
49     {
50     protected:
51         struct value_type
52         {
53             size_t      nNo;
54
55             value_type()
56                 : nNo( 0 )
57             {}
58
59             value_type( size_t n )
60                 : nNo( n )
61             {}
62         };
63
64         template <class Queue>
65         class Consumer: public cds_test::thread
66         {
67             typedef cds_test::thread base_class;
68
69         public:
70             Consumer( cds_test::thread_pool& pool, Queue& queue )
71                 : base_class( pool )
72                 , m_Queue( queue )
73                 , m_arr( new uint8_t[ s_nQueueSize ])
74                 , m_nPopCount( 0 )
75             {}
76
77             Consumer( Consumer& src )
78                 : base_class( src )
79                 , m_Queue( src.m_Queue )
80                 , m_arr( new uint8_t[ s_nQueueSize ])
81                 , m_nPopCount( 0 )
82             {}
83
84             virtual thread * clone()
85             {
86                 return new Consumer( *this );
87             }
88
89             virtual void test()
90             {
91                 memset( m_arr.get(), 0, sizeof( m_arr[0] ) * s_nQueueSize );
92                 typedef typename Queue::value_type value_type;
93                 value_type value;
94                 size_t nPopCount = 0;
95                 while ( m_Queue.pop( value )) {
96                     ++m_arr[ value.nNo ];
97                     ++nPopCount;
98                 }
99                 m_nPopCount = nPopCount;
100             }
101
102         public:
103             Queue&              m_Queue;
104             std::unique_ptr< uint8_t[] > m_arr;
105             size_t              m_nPopCount;
106         };
107
108     public:
109         static void SetUpTestCase()
110         {
111             cds_test::config const& cfg = get_config( "queue_pop" );
112
113             s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount );
114             s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize );
115
116             if ( s_nThreadCount == 0 )
117                 s_nThreadCount = 1;
118             if ( s_nQueueSize == 0 )
119                 s_nQueueSize = 1000;
120         }
121
122         //static void TearDownTestCase();
123
124     protected:
125         template <class Queue>
126         void analyze( Queue& q )
127         {
128             cds_test::thread_pool& pool = get_pool();
129             std::unique_ptr< uint8_t[] > arr( new uint8_t[s_nQueueSize] );
130             memset(arr.get(), 0, sizeof(arr[0]) * s_nQueueSize );
131
132             size_t nTotalPops = 0;
133             for ( size_t i = 0; i < pool.size(); ++i ) {
134                 Consumer<Queue>& thread = static_cast<Consumer<Queue>&>(pool.get( i ));
135                 for ( size_t j = 0; j < s_nQueueSize; ++j )
136                     arr[j] += thread.m_arr[j];
137                 nTotalPops += thread.m_nPopCount;
138             }
139             EXPECT_EQ( nTotalPops, s_nQueueSize );
140             EXPECT_TRUE( q.empty());
141
142             for ( size_t i = 0; i < s_nQueueSize; ++i ) {
143                 EXPECT_EQ( arr[i], 1 ) << "i=" << i;
144             }
145         }
146
147         template <class Queue>
148         void test( Queue& q )
149         {
150             cds_test::thread_pool& pool = get_pool();
151
152             pool.add( new Consumer<Queue>( pool, q ), s_nThreadCount );
153
154             for ( size_t i = 0; i < s_nQueueSize; ++i )
155                 q.push( i );
156
157             propout() << std::make_pair( "thread_count", s_nThreadCount )
158                 << std::make_pair( "push_count", s_nQueueSize );
159
160             std::chrono::milliseconds duration = pool.run();
161
162             propout() << std::make_pair( "duration", duration );
163
164             DEBUG(analyze( q ));
165
166             propout() << q.statistics();
167         }
168     };
169
170     CDSSTRESS_MSQueue( queue_pop )
171     CDSSTRESS_MoirQueue( queue_pop )
172     CDSSTRESS_BasketQueue( queue_pop )
173     CDSSTRESS_OptimsticQueue( queue_pop )
174     CDSSTRESS_RWQueue( queue_pop )
175
176 #undef CDSSTRESS_Queue_F
177 #define CDSSTRESS_Queue_F( test_fixture, type_name ) \
178     TEST_F( test_fixture, type_name ) \
179     { \
180         typedef queue::Types< value_type >::type_name queue_type; \
181         queue_type queue( s_nQueueSize ); \
182         test( queue ); \
183     }
184
185     CDSSTRESS_VyukovQueue( queue_pop )
186
187 #undef CDSSTRESS_Queue_F
188
189
190     // ********************************************************************
191     // SegmentedQueue test
192
193     class segmented_queue_pop
194         : public queue_pop
195         , public ::testing::WithParamInterface< size_t >
196     {
197         typedef queue_pop base_class;
198
199     protected:
200         template <typename Queue>
201         void test()
202         {
203             size_t quasi_factor = GetParam();
204
205             Queue q( quasi_factor );
206             propout() << std::make_pair( "quasi_factor", quasi_factor );
207             base_class::test( q );
208         }
209
210     public:
211         static std::vector< size_t > get_test_parameters()
212         {
213             cds_test::config const& cfg = cds_test::stress_fixture::get_config( "queue_pop" );
214             bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false );
215             size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 );
216
217             std::vector<size_t> args;
218             if ( bIterative && quasi_factor > 4 ) {
219                 for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 )
220                     args.push_back( qf );
221             }
222             else {
223                 if ( quasi_factor > 2 )
224                     args.push_back( quasi_factor );
225                 else
226                     args.push_back( 2 );
227             }
228
229             return args;
230         }
231     };
232
233 #define CDSSTRESS_Queue_F( test_fixture, type_name ) \
234     TEST_P( test_fixture, type_name ) \
235     { \
236         typedef typename queue::Types<value_type>::type_name queue_type; \
237         test< queue_type >(); \
238     }
239
240     CDSSTRESS_SegmentedQueue( segmented_queue_pop )
241
242 #ifdef CDSTEST_GTEST_INSTANTIATE_TEST_CASE_P_HAS_4TH_ARG
243     static std::string get_test_parameter_name( testing::TestParamInfo<size_t> const& p )
244     {
245         return std::to_string( p.param );
246     }
247     INSTANTIATE_TEST_CASE_P( SQ,
248         segmented_queue_pop,
249         ::testing::ValuesIn( segmented_queue_pop::get_test_parameters()), get_test_parameter_name );
250 #else
251     INSTANTIATE_TEST_CASE_P( SQ,
252         segmented_queue_pop,
253         ::testing::ValuesIn( segmented_queue_pop::get_test_parameters()));
254 #endif
255
256
257 } // namespace