Disables running some stat analysis for benchmarks & Adds some sequential data structures
[libcds.git] / test / stress / stack / push.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 "stack_type.h"
32 #include "../misc/common.h"
33
34 namespace {
35
36     static size_t s_nThreadCount = 8;
37     static size_t s_nStackSize = 10000000;
38     static size_t s_nEliminationSize = 4;
39
40     class stack_push : public cds_test::stress_fixture
41     {
42     protected:
43
44         struct value_type {
45             size_t      nNo;
46             size_t      nThread;
47
48             value_type()
49                 : nNo( 0 )
50                 , nThread( 0 )
51             {}
52             value_type( size_t n )
53                 : nNo( n )
54                 , nThread( 0 )
55             {}
56         };
57
58         template <class Stack>
59         class Producer: public cds_test::thread
60         {
61             typedef cds_test::thread base_class;
62
63         public:
64             Producer( cds_test::thread_pool& pool, Stack& stack )
65                 : base_class( pool )
66                 , m_stack( stack )
67                 , m_nStartItem( 0 )
68                 , m_nEndItem( 0 )
69                 , m_nPushError( 0 )
70             {}
71
72             Producer( Producer& src )
73                 : base_class( src )
74                 , m_stack( src.m_stack )
75                 , m_nStartItem( 0 )
76                 , m_nEndItem( 0 )
77                 , m_nPushError( 0 )
78             {}
79
80             virtual thread * clone()
81             {
82                 return new Producer( *this );
83             }
84
85             virtual void test()
86             {
87                 value_type v;
88                 v.nThread = id();
89                 for ( v.nNo = m_nStartItem; v.nNo < m_nEndItem; ++v.nNo ) {
90                     if ( !m_stack.push( v ))
91                         ++m_nPushError;
92                 }
93             }
94
95         public:
96             Stack&  m_stack;
97             size_t  m_nStartItem;
98             size_t  m_nEndItem;
99             size_t  m_nPushError;
100         };
101
102     protected:
103         static void SetUpTestCase()
104         {
105             cds_test::config const& cfg = get_config("Stack_Push");
106
107             s_nThreadCount     = cfg.get_size_t( "ThreadCount",     s_nThreadCount );
108             s_nStackSize       = cfg.get_size_t( "StackSize",       s_nStackSize );
109             s_nEliminationSize = cfg.get_size_t( "EliminationSize", s_nEliminationSize );
110
111             if ( s_nThreadCount == 0 )
112                 s_nThreadCount = 1;
113         }
114
115         //static void TearDownTestCase();
116
117         template <typename Stack>
118         void test( Stack& stack )
119         {
120             cds_test::thread_pool& pool = get_pool();
121
122             pool.add( new Producer<Stack>( pool, stack ), s_nThreadCount );
123
124             size_t nStart = 0;
125             size_t nThreadItemCount = s_nStackSize / s_nThreadCount;
126             for ( size_t i = 0; i < pool.size(); ++i ) {
127                 Producer<Stack>& thread = static_cast<Producer<Stack>&>( pool.get( i ));
128                 thread.m_nStartItem = nStart;
129                 nStart += nThreadItemCount;
130                 thread.m_nEndItem = nStart;
131             }
132
133             propout() << std::make_pair( "thread_count", s_nThreadCount )
134                 << std::make_pair( "push_count", s_nStackSize );
135
136             std::chrono::milliseconds duration = pool.run();
137
138             propout() << std::make_pair( "duration", duration );
139
140             DEBUG(analyze( stack ));
141             propout() << stack.statistics();
142         }
143
144         template <typename Stack>
145         void test_elimination( Stack& stack )
146         {
147             test( stack );
148             check_elimination_stat( stack.statistics());
149         }
150
151         void check_elimination_stat( cds::container::treiber_stack::empty_stat const& )
152         {}
153
154         void check_elimination_stat( cds::container::treiber_stack::stat<> const& s )
155         {
156             EXPECT_EQ( s.m_PushCount.get(), s.m_PopCount.get());
157         }
158
159         template <class Stack>
160         void analyze( Stack& testStack )
161         {
162             cds_test::thread_pool& pool = get_pool();
163
164             size_t nThreadItems = s_nStackSize / s_nThreadCount;
165             std::vector<size_t> aThread;
166             aThread.resize( s_nThreadCount );
167
168             for ( size_t i = 0; i < pool.size(); ++i ) {
169                 Producer<Stack>& producer = static_cast<Producer<Stack>&>( pool.get( i ));
170                 EXPECT_EQ( producer.m_nPushError, 0u ) << "Producer=" << i;
171                 aThread[producer.id()] = producer.m_nEndItem - 1;
172             }
173             EXPECT_FALSE( testStack.empty());
174
175             std::unique_ptr< uint8_t[] > uarr( new uint8_t[s_nStackSize] );
176             uint8_t * arr = uarr.get();
177             memset( arr, 0, sizeof( arr[0] ) * s_nStackSize );
178
179             auto time_start = std::chrono::steady_clock::now();
180             size_t nPopped = 0;
181             value_type val;
182             while ( testStack.pop( val )) {
183                 nPopped++;
184                 ASSERT_LT( val.nNo, s_nStackSize );
185                 ++arr[val.nNo];
186                 ASSERT_LT( val.nThread, s_nThreadCount );
187                 ASSERT_EQ( aThread[val.nThread], val.nNo );
188                 aThread[val.nThread]--;
189             }
190             propout() << std::make_pair( "pop_duration", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - time_start));
191
192             size_t nTotalItems = nThreadItems * s_nThreadCount;
193             size_t nError = 0;
194             for ( size_t i = 0; i < nTotalItems; ++i ) {
195                 EXPECT_EQ( arr[i], 1 ) << "i=" << i;
196                 if ( ++nError > 10 ) {
197                     ASSERT_EQ( arr[i], 1 );
198                 }
199             }
200         }
201     };
202
203     CDSSTRESS_TreiberStack( stack_push )
204     CDSSTRESS_EliminationStack( stack_push )
205     //CDSSTRESS_FCStack( stack_push )
206     //CDSSTRESS_FCDeque( stack_push )
207
208 } // namespace