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 "cppunit/thread.h"
32 #include "stack/stack_type.h"
34 // Multi-threaded stack test for push operation
37 #define TEST_CASE( Q ) void Q() { test_unbounded< Types<SimpleValue>::Q >(); }
38 #define TEST_ELIMINATION( Q ) void Q() { test_elimination< Types<SimpleValue>::Q >(); }
39 #define TEST_BOUNDED( Q ) void Q() { test_bounded< Types<SimpleValue>::Q >(); }
42 static size_t s_nThreadCount = 8;
43 static size_t s_nStackSize = 10000000;
44 static size_t s_nEliminationSize = 4;
50 SimpleValue(): nNo(0), nThread(0) {}
51 SimpleValue( size_t n ): nNo(n), nThread(0) {}
52 size_t getNo() const { return nNo; }
56 class Stack_Push: public CppUnitMini::TestCase
58 template <class Stack>
59 class Thread: public CppUnitMini::TestThread
61 virtual TestThread * clone()
63 return new Thread( *this );
73 Thread( CppUnitMini::ThreadPool& pool, Stack& s )
74 : CppUnitMini::TestThread( pool )
78 : CppUnitMini::TestThread( src )
79 , m_Stack( src.m_Stack )
84 return reinterpret_cast<Stack_Push&>( m_Pool.m_Test );
89 cds::threading::Manager::attachThread();
93 cds::threading::Manager::detachThread();
98 m_fTime = m_Timer.duration();
102 v.nThread = m_nThreadNo;
103 for ( v.nNo = m_nStartItem; v.nNo < m_nEndItem; ++v.nNo ) {
104 if ( !m_Stack.push( v ))
108 m_fTime = m_Timer.duration() - m_fTime;
113 void setUpParams( const CppUnitMini::TestCfg& cfg ) {
114 s_nThreadCount = cfg.getULong("ThreadCount", 8 );
115 s_nStackSize = cfg.getULong("StackSize", 10000000 );
116 s_nEliminationSize = cfg.getULong("EliminationSize", 4 );
119 template <class Stack>
120 void analyze( CppUnitMini::ThreadPool& pool, Stack& testStack )
122 size_t nThreadItems = s_nStackSize / s_nThreadCount;
123 std::vector<size_t> aThread;
124 aThread.resize(s_nThreadCount);
127 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
128 Thread<Stack> * pThread = reinterpret_cast<Thread<Stack> *>(*it);
129 fTime += pThread->m_fTime;
130 if ( pThread->m_nPushError != 0 )
131 CPPUNIT_MSG(" ERROR: thread push error count=" << pThread->m_nPushError );
132 aThread[ pThread->m_nThreadNo] = pThread->m_nEndItem - 1;
134 CPPUNIT_MSG( " Duration=" << (fTime / s_nThreadCount) );
135 CPPUNIT_ASSERT( !testStack.empty() )
137 size_t * arr = new size_t[ s_nStackSize ];
138 memset(arr, 0, sizeof(arr[0]) * s_nStackSize );
140 cds::OS::Timer timer;
141 CPPUNIT_MSG( " Pop (single-threaded)..." );
144 while ( testStack.pop( val )) {
146 ++arr[ val.getNo() ];
147 CPPUNIT_ASSERT( val.nThread < s_nThreadCount);
148 CPPUNIT_ASSERT( aThread[val.nThread] == val.nNo );
149 aThread[val.nThread]--;
151 CPPUNIT_MSG( " Duration=" << timer.duration() );
153 size_t nTotalItems = nThreadItems * s_nThreadCount;
155 for ( size_t i = 0; i < nTotalItems; ++i ) {
157 CPPUNIT_MSG( " ERROR: Item " << i << " has not been pushed" );
158 CPPUNIT_ASSERT( ++nError > 10 );
165 // Unbounded stack test
166 template <class Stack>
167 void test_unbounded()
173 // Unbounded elimination stack test
174 template <class Stack>
175 void test_elimination()
177 Stack testStack( s_nEliminationSize );
179 check_elimination_stat( testStack.statistics() );
181 void check_elimination_stat( cds::container::treiber_stack::empty_stat const& )
183 void check_elimination_stat( cds::container::treiber_stack::stat<> const& s )
185 CPPUNIT_CHECK( s.m_PushCount.get() == s.m_PopCount.get() );
188 // Bounded stack test
189 template <class Stack>
192 Stack testStack( s_nStackSize );
196 template <class Stack>
197 void test( Stack& testStack )
199 CppUnitMini::ThreadPool pool( *this );
200 pool.add( new Thread<Stack>( pool, testStack ), s_nThreadCount );
203 size_t nThreadItemCount = s_nStackSize / s_nThreadCount;
204 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
205 Thread<Stack> * pThread = reinterpret_cast<Thread<Stack> *>(*it);
206 pThread->m_nStartItem = nStart;
207 nStart += nThreadItemCount;
208 pThread->m_nEndItem = nStart;
211 CPPUNIT_MSG( " Push test, thread count=" << s_nThreadCount
212 << " items=" << (nThreadItemCount * s_nThreadCount)
216 analyze( pool, testStack );
217 CPPUNIT_MSG( testStack.statistics() );
221 # include "stack/stack_defs.h"
222 CDSUNIT_DECLARE_TreiberStack
223 CDSUNIT_DECLARE_EliminationStack
224 CDSUNIT_DECLARE_FCStack
225 CDSUNIT_DECLARE_FCDeque
226 CDSUNIT_DECLARE_StdStack
228 CPPUNIT_TEST_SUITE(Stack_Push)
229 CDSUNIT_TEST_TreiberStack
230 CDSUNIT_TEST_EliminationStack
233 CDSUNIT_TEST_StdStack
234 CPPUNIT_TEST_SUITE_END();
238 CPPUNIT_TEST_SUITE_REGISTRATION(stack::Stack_Push);