From: khizmax Date: Wed, 24 Feb 2016 14:16:30 +0000 (+0300) Subject: Moved stress test for intrusive stack to gtest framework X-Git-Tag: v2.2.0~383 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7f0c81027ac79be9b024a484357841734746a4da;p=libcds.git Moved stress test for intrusive stack to gtest framework --- diff --git a/projects/Win/vc14/stress-stack.vcxproj b/projects/Win/vc14/stress-stack.vcxproj index f63eb1a0..abd5845d 100644 --- a/projects/Win/vc14/stress-stack.vcxproj +++ b/projects/Win/vc14/stress-stack.vcxproj @@ -28,10 +28,13 @@ + + + diff --git a/projects/Win/vc14/stress-stack.vcxproj.filters b/projects/Win/vc14/stress-stack.vcxproj.filters index 361b821f..5d4e437e 100644 --- a/projects/Win/vc14/stress-stack.vcxproj.filters +++ b/projects/Win/vc14/stress-stack.vcxproj.filters @@ -24,10 +24,19 @@ Source Files + + Source Files + Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/test/stress/stack/CMakeLists.txt b/test/stress/stack/CMakeLists.txt index 460bdee5..8a62e6c2 100644 --- a/test/stress/stack/CMakeLists.txt +++ b/test/stress/stack/CMakeLists.txt @@ -2,6 +2,7 @@ set(PACKAGE_NAME stress-stack) set(CDSSTRESS_STACK_SOURCES ../main.cpp + intrusive_push_pop.cpp push.cpp push_pop.cpp ) diff --git a/test/stress/stack/intrusive_push_pop.cpp b/test/stress/stack/intrusive_push_pop.cpp new file mode 100644 index 00000000..3b89e7bf --- /dev/null +++ b/test/stress/stack/intrusive_push_pop.cpp @@ -0,0 +1,180 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "intrusive_stack_push_pop.h" + +namespace cds_test { + /*static*/ size_t intrusive_stack_push_pop::s_nPushThreadCount = 4; + /*static*/ size_t intrusive_stack_push_pop::s_nPopThreadCount = 4; + /*static*/ size_t intrusive_stack_push_pop::s_nStackSize = 10000000; + /*static*/ size_t intrusive_stack_push_pop::s_nEliminationSize = 4; + /*static*/ bool intrusive_stack_push_pop::s_bFCIterative = false; + /*static*/ unsigned int intrusive_stack_push_pop::s_nFCCombinePassCount = 64; + /*static*/ unsigned int intrusive_stack_push_pop::s_nFCCompactFactor = 1024; + + /*static*/ atomics::atomic intrusive_stack_push_pop::s_nWorkingProducers( 0 ); + + /*static*/ void intrusive_stack_push_pop::SetUpTestCase() + { + cds_test::config const& cfg = get_config( "IntrusiveStack_PushPop" ); + + s_nPushThreadCount = cfg.get_size_t( "PushThreadCount", s_nPushThreadCount ); + s_nPopThreadCount = cfg.get_size_t( "PopThreadCount", s_nPopThreadCount ); + s_nStackSize = cfg.get_size_t( "StackSize", s_nStackSize ); + s_nEliminationSize = cfg.get_size_t( "EliminationSize", s_nEliminationSize ); + s_bFCIterative = cfg.get_bool( "FCIterate", s_bFCIterative ); + s_nFCCombinePassCount = cfg.get_uint( "FCCombinePassCount", s_nFCCombinePassCount ); + s_nFCCompactFactor = cfg.get_uint( "FCCompactFactor", s_nFCCompactFactor ); + + if ( s_nPushThreadCount == 0 ) + s_nPushThreadCount = 1; + if ( s_nPopThreadCount == 0 ) + s_nPopThreadCount = 1; + if ( s_nEliminationSize == 0 ) + s_nEliminationSize = 1; + } +} // namespace cds_test + +namespace { + class intrusive_stack_push_pop : public cds_test::intrusive_stack_push_pop + { + typedef cds_test::intrusive_stack_push_pop base_class; + protected: + typedef base_class::value_type<> value_type; + typedef base_class::value_type< cds::intrusive::treiber_stack::node< cds::gc::HP >> hp_value_type; + typedef base_class::value_type< cds::intrusive::treiber_stack::node< cds::gc::DHP >> dhp_value_type; + + template + void test() + { + value_array arrValue( s_nStackSize ); + { + Stack stack; + do_test( stack, arrValue ); + } + Stack::gc::force_dispose(); + } + + void check_elimination_stat( cds::intrusive::treiber_stack::empty_stat const& ) + {} + + void check_elimination_stat( cds::intrusive::treiber_stack::stat<> const& s ) + { + EXPECT_EQ( s.m_PushCount.get() + s.m_ActivePushCollision.get() + s.m_PassivePushCollision.get(), s_nStackSize ); + EXPECT_EQ( s.m_PopCount.get() + s.m_ActivePopCollision.get() + s.m_PassivePopCollision.get(), s_nStackSize ); + EXPECT_EQ( s.m_PushCount.get(), s.m_PopCount.get() ); + EXPECT_EQ( s.m_ActivePopCollision.get(), s.m_PassivePushCollision.get() ); + EXPECT_EQ( s.m_ActivePushCollision.get(), s.m_PassivePopCollision.get() ); + } + + template + void test_elimination() + { + value_array arrValue( s_nStackSize ); + { + Stack stack( s_nEliminationSize ); + do_test( stack, arrValue ); + check_elimination_stat( stack.statistics() ); + } + Stack::gc::force_dispose(); + } + + template + void test_std() + { + value_array arrValue( s_nStackSize ); + Stack stack; + do_test( stack, arrValue ); + } + }; + + // TreiberStack +#define CDSSTRESS_Stack_F( test_fixture, stack_impl ) \ + TEST_F( test_fixture, stack_impl ) \ + { \ + typedef typename istack::Types::stack_impl stack_type; \ + test< stack_type >(); \ + } + + CDSSTRESS_TreiberStack_HP( intrusive_stack_push_pop ) + +#undef CDSSTRESS_Stack_F + + // TreiberStack +#define CDSSTRESS_Stack_F( test_fixture, stack_impl ) \ + TEST_F( test_fixture, stack_impl ) \ + { \ + typedef typename istack::Types::stack_impl stack_type; \ + test< stack_type >(); \ + } + + CDSSTRESS_TreiberStack_DHP( intrusive_stack_push_pop ) + +#undef CDSSTRESS_Stack_F + + // TreiberStack + elimination enabled +#define CDSSTRESS_Stack_F( test_fixture, stack_impl ) \ + TEST_F( test_fixture, stack_impl ) \ + { \ + typedef typename istack::Types::stack_impl stack_type; \ + test_elimination< stack_type >(); \ + } + + CDSSTRESS_EliminationStack_HP( intrusive_stack_push_pop ) + +#undef CDSSTRESS_Stack_F + + + // TreiberStack + elimination enabled +#define CDSSTRESS_Stack_F( test_fixture, stack_impl ) \ + TEST_F( test_fixture, stack_impl ) \ + { \ + typedef typename istack::Types::stack_impl stack_type; \ + test_elimination< stack_type >(); \ + } + + CDSSTRESS_EliminationStack_DHP( intrusive_stack_push_pop ) + +#undef CDSSTRESS_Stack_F + + + // StdStack +#define CDSSTRESS_Stack_F( test_fixture, stack_impl ) \ + TEST_F( test_fixture, stack_impl ) \ + { \ + typedef typename istack::Types::stack_impl stack_type; \ + test_std< stack_type >(); \ + } + + CDSSTRESS_StdStack( intrusive_stack_push_pop ) + +#undef CDSSTRESS_Stack_F + +} // namespace diff --git a/test/stress/stack/intrusive_stack_push_pop.h b/test/stress/stack/intrusive_stack_push_pop.h new file mode 100644 index 00000000..c919a61c --- /dev/null +++ b/test/stress/stack/intrusive_stack_push_pop.h @@ -0,0 +1,295 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "intrusive_stack_type.h" + +namespace cds_test { + + class intrusive_stack_push_pop : public cds_test::stress_fixture + { + protected: + static size_t s_nPushThreadCount; + static size_t s_nPopThreadCount; + static size_t s_nStackSize; + static size_t s_nEliminationSize; + static bool s_bFCIterative; + static unsigned int s_nFCCombinePassCount; + static unsigned int s_nFCCompactFactor; + + static atomics::atomic s_nWorkingProducers; + + static CDS_CONSTEXPR const size_t c_nValArraySize = 1024; + static CDS_CONSTEXPR const size_t c_nBadConsumer = 0xbadc0ffe; + + enum thread_type + { + producer_thread, + consumer_thread + }; + + struct empty + {}; + + template + struct value_type : public Base + { + atomics::atomic nNo; + size_t nProducer; + size_t nConsumer; + + value_type() {} + value_type( size_t n ) : nNo( n ) {} + }; + + + template + class Producer : public cds_test::thread + { + typedef cds_test::thread base_class; + public: + Stack& m_Stack; + size_t m_nPushError; + size_t m_arrPush[c_nValArraySize]; + + // Interval in m_arrValue + typename Stack::value_type * m_pStart; + typename Stack::value_type * m_pEnd; + + public: + Producer( cds_test::thread_pool& pool, Stack& s ) + : base_class( pool, producer_thread ) + , m_Stack( s ) + , m_nPushError( 0 ) + , m_pStart( nullptr ) + , m_pEnd( nullptr ) + {} + + Producer( Producer& src ) + : base_class( src ) + , m_Stack( src.m_Stack ) + , m_nPushError( 0 ) + , m_pStart( nullptr ) + , m_pEnd( nullptr ) + {} + + virtual thread * clone() + { + return new Producer( *this ); + } + + virtual void test() + { + m_nPushError = 0; + memset( m_arrPush, 0, sizeof( m_arrPush ) ); + + size_t i = 0; + for ( typename Stack::value_type * p = m_pStart; p < m_pEnd; ++p, ++i ) { + p->nProducer = id(); + size_t no; + p->nNo.store( no = i % c_nValArraySize, atomics::memory_order_release ); + if ( m_Stack.push( *p ) ) + ++m_arrPush[no]; + else + ++m_nPushError; + } + + s_nWorkingProducers.fetch_sub( 1, atomics::memory_order_release ); + } + }; + + template + class Consumer : public cds_test::thread + { + typedef cds_test::thread base_class; + public: + Stack& m_Stack; + size_t m_nPopCount; + size_t m_nPopEmpty; + size_t m_arrPop[c_nValArraySize]; + size_t m_nDirtyPop; + public: + Consumer( cds_test::thread_pool& pool, Stack& s ) + : base_class( pool, consumer_thread ) + , m_Stack( s ) + , m_nPopCount( 0 ) + , m_nPopEmpty( 0 ) + , m_nDirtyPop( 0 ) + {} + + Consumer( Consumer& src ) + : base_class( src ) + , m_Stack( src.m_Stack ) + , m_nPopCount( 0 ) + , m_nPopEmpty( 0 ) + , m_nDirtyPop( 0 ) + {} + + virtual thread * clone() + { + return new Consumer( *this ); + } + + virtual void test() + { + m_nPopEmpty = 0; + m_nPopCount = 0; + m_nDirtyPop = 0; + memset( m_arrPop, 0, sizeof( m_arrPop ) ); + + while ( !(s_nWorkingProducers.load( atomics::memory_order_acquire ) == 0 && m_Stack.empty()) ) { + typename Stack::value_type * p = m_Stack.pop(); + if ( p ) { + p->nConsumer = id(); + ++m_nPopCount; + size_t no = p->nNo.load( atomics::memory_order_acquire ); + if ( no < sizeof( m_arrPop ) / sizeof( m_arrPop[0] ) ) + ++m_arrPop[no]; + else + ++m_nDirtyPop; + } + else + ++m_nPopEmpty; + } + } + }; + + template + class value_array + { + std::unique_ptr< T[] > m_pArr; + + public: + value_array( size_t nSize ) + : m_pArr( new T[nSize] ) + {} + + T * get() const { return m_pArr.get(); } + }; + + protected: + static void SetUpTestCase(); + //static void TearDownTestCase(); + + template + void analyze( Stack& stack ) + { + cds_test::thread_pool& pool = get_pool(); + + size_t nPushError = 0; + size_t nPopEmpty = 0; + size_t nPopCount = 0; + size_t arrVal[c_nValArraySize]; + memset( arrVal, 0, sizeof( arrVal ) ); + size_t nDirtyPop = 0; + + for ( size_t threadNo = 0; threadNo < pool.size(); ++threadNo ) { + cds_test::thread& thread = pool.get( threadNo ); + if ( thread.type() == producer_thread ) { + Producer& producer = static_cast&>(thread); + nPushError += producer.m_nPushError; + for ( size_t i = 0; i < sizeof( arrVal ) / sizeof( arrVal[0] ); ++i ) + arrVal[i] += producer.m_arrPush[i]; + } + else { + ASSERT_TRUE( thread.type() == consumer_thread ); + Consumer& consumer = static_cast&>(thread); + nPopEmpty += consumer.m_nPopEmpty; + nPopCount += consumer.m_nPopCount; + nDirtyPop += consumer.m_nDirtyPop; + for ( size_t i = 0; i < sizeof( arrVal ) / sizeof( arrVal[0] ); ++i ) + arrVal[i] -= consumer.m_arrPop[i]; + } + } + + EXPECT_EQ( nPopCount, s_nStackSize ); + EXPECT_EQ( nDirtyPop, 0 ); + EXPECT_EQ( nPushError, 0 ); + + for ( size_t i = 0; i < sizeof( arrVal ) / sizeof( arrVal[0] ); ++i ) { + EXPECT_EQ( arrVal[i], 0 ) << "i=" << i; + } + + propout() << std::make_pair( "push_count", s_nStackSize ) + << std::make_pair( "push_error", nPushError ) + << std::make_pair( "pop_count", nPopCount ) + << std::make_pair( "pop_empty", nPopEmpty ) + << std::make_pair( "dirty_pop", nDirtyPop ) + ; + + } + + template + void do_test( Stack& stack, value_array& arrValue ) + { + cds_test::thread_pool& pool = get_pool(); + + s_nWorkingProducers.store( s_nPushThreadCount, atomics::memory_order_release ); + size_t const nPushCount = s_nStackSize / s_nPushThreadCount; + + typename Stack::value_type * pValStart = arrValue.get(); + typename Stack::value_type * pValEnd = pValStart + s_nStackSize; + + pool.add( new Producer( pool, stack ), s_nPushThreadCount ); + { + for ( typename Stack::value_type * it = pValStart; it != pValEnd; ++it ) + it->nConsumer = c_nBadConsumer; + + typename Stack::value_type * pStart = pValStart; + for ( size_t thread_no = 0; thread_no < pool.size(); ++thread_no ) { + static_cast&>(pool.get( thread_no )).m_pStart = pStart; + pStart += nPushCount; + static_cast&>(pool.get( thread_no )).m_pEnd = pStart; + } + } + pool.add( new Consumer( pool, stack ), s_nPopThreadCount ); + + propout() << std::make_pair( "producer_thread_count", s_nPushThreadCount ) + << std::make_pair( "consumer_thread_count", s_nPopThreadCount ) + << std::make_pair( "push_count", nPushCount * s_nPushThreadCount ) + ; + + std::chrono::milliseconds duration = pool.run(); + + propout() << std::make_pair( "duration", duration ); + + s_nStackSize = nPushCount * s_nPushThreadCount; + + { + typename Stack::value_type * pEnd = pValStart + s_nStackSize; + for ( typename Stack::value_type * it = pValStart; it != pEnd; ++it ) + EXPECT_NE( it->nConsumer, c_nBadConsumer ); + } + + analyze( stack ); + + propout() << stack.statistics(); + } + }; +} // namespace cds_test \ No newline at end of file diff --git a/test/stress/stack/intrusive_stack_type.h b/test/stress/stack/intrusive_stack_type.h new file mode 100644 index 00000000..89f6a8eb --- /dev/null +++ b/test/stress/stack/intrusive_stack_type.h @@ -0,0 +1,497 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSSTRESS_INTRUSIVE_STACK_TYPES_H +#define CDSSTRESS_INTRUSIVE_STACK_TYPES_H + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +namespace istack { + + namespace details { + + template < typename T, typename Stack, typename Lock> + class StdStack + { + Stack m_Impl; + mutable Lock m_Lock; + cds::intrusive::treiber_stack::empty_stat m_stat; + + typedef std::unique_lock unique_lock; + + public: + typedef T value_type; + + bool push( T& v ) + { + unique_lock l( m_Lock ); + m_Impl.push( &v ); + return true; + } + + T * pop() + { + unique_lock l( m_Lock ); + if ( !m_Impl.empty() ) { + T * v = m_Impl.top(); + m_Impl.pop(); + return v; + } + return nullptr; + } + + bool empty() const + { + unique_lock l( m_Lock ); + return m_Impl.empty(); + } + + cds::intrusive::treiber_stack::empty_stat const& statistics() const + { + return m_stat; + } + }; + } + + template + struct Types { + + template + using base_hook = cds::intrusive::treiber_stack::base_hook < cds::opt::gc< GC > >; + + // TreiberStack + typedef cds::intrusive::TreiberStack< cds::gc::HP, T > Treiber_HP; + struct traits_Treiber_DHP: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_DHP >Treiber_DHP; + + template struct traits_Treiber_seqcst : public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::memory_model + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Treiber_seqcst > Treiber_HP_seqcst; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_seqcst > Treiber_DHP_seqcst; + + template struct traits_Treiber_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Treiber_stat > Treiber_HP_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_stat > Treiber_DHP_stat; + + template struct traits_Treiber_yield: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::back_off + , cds::opt::memory_model + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Treiber_yield > Treiber_HP_yield; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_yield > Treiber_DHP_yield; + + template struct traits_Treiber_pause: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::back_off + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Treiber_pause > Treiber_HP_pause; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_pause > Treiber_DHP_pause; + + template struct traits_Treiber_exp: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + ,cds::opt::back_off< + cds::backoff::exponential< + cds::backoff::pause, + cds::backoff::yield + > + > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Treiber_exp > Treiber_HP_exp; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Treiber_exp > Treiber_DHP_exp; + + + // Elimination stack + template struct traits_Elimination_on : public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_on > Elimination_HP; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_on > Elimination_DHP; + + template struct traits_Elimination_seqcst : public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::memory_model< cds::opt::v::sequential_consistent > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_seqcst > Elimination_HP_seqcst; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_seqcst > Elimination_DHP_seqcst; + + template struct traits_Elimination_2ms: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<2> > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_2ms > Elimination_HP_2ms; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_2ms > Elimination_DHP_2ms; + + template struct traits_Elimination_2ms_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<2> > + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_2ms_stat > Elimination_HP_2ms_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_2ms_stat > Elimination_DHP_2ms_stat; + + template struct traits_Elimination_5ms: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<5> > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_5ms > Elimination_HP_5ms; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_5ms > Elimination_DHP_5ms; + + template struct traits_Elimination_5ms_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<5> > + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_5ms_stat > Elimination_HP_5ms_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_5ms_stat > Elimination_DHP_5ms_stat; + + template struct traits_Elimination_10ms: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<10> > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_10ms > Elimination_HP_10ms; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_10ms > Elimination_DHP_10ms; + + template struct traits_Elimination_10ms_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::elimination_backoff< cds::backoff::delay_of<10> > + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_10ms_stat > Elimination_HP_10ms_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_10ms_stat > Elimination_DHP_10ms_stat; + + template struct traits_Elimination_dyn: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::buffer< cds::opt::v::dynamic_buffer > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_dyn > Elimination_HP_dyn; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_dyn > Elimination_DHP_dyn; + + template struct traits_Elimination_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_stat > Elimination_HP_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_stat > Elimination_DHP_stat; + + template struct traits_Elimination_dyn_stat: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::buffer< cds::opt::v::dynamic_buffer > + , cds::opt::stat > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_dyn_stat > Elimination_HP_dyn_stat; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_dyn_stat > Elimination_DHP_dyn_stat; + + template struct traits_Elimination_yield: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::back_off + , cds::opt::memory_model + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_yield > Elimination_HP_yield; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_yield > Elimination_DHP_yield; + + template struct traits_Elimination_pause: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + , cds::opt::back_off + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_pause > Elimination_HP_pause; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_pause > Elimination_DHP_pause; + + template struct traits_Elimination_exp: public + cds::intrusive::treiber_stack::make_traits < + cds::intrusive::opt::hook< base_hook > + , cds::opt::enable_elimination + ,cds::opt::back_off< + cds::backoff::exponential< + cds::backoff::pause, + cds::backoff::yield + > + > + > ::type + {}; + typedef cds::intrusive::TreiberStack< cds::gc::HP, T, traits_Elimination_exp > Elimination_HP_exp; + typedef cds::intrusive::TreiberStack< cds::gc::DHP, T, traits_Elimination_exp > Elimination_DHP_exp; + + // FCStack + typedef cds::intrusive::FCStack< T > FCStack_slist; + + struct traits_FCStack_stat: + public cds::intrusive::fcstack::make_traits< + cds::opt::stat< cds::intrusive::fcstack::stat<> > + >::type + {}; + struct traits_FCStack_elimination: + public cds::intrusive::fcstack::make_traits< + cds::opt::enable_elimination< true > + >::type + {}; + struct traits_FCStack_elimination_stat: + public cds::intrusive::fcstack::make_traits< + cds::opt::stat< cds::intrusive::fcstack::stat<> >, + cds::opt::enable_elimination< true > + >::type + {}; + + struct traits_FCStack_mutex_stat: + public cds::intrusive::fcstack::make_traits< + cds::opt::stat< cds::intrusive::fcstack::stat<> > + ,cds::opt::lock_type< std::mutex > + >::type + {}; + struct traits_FCStack_mutex_elimination: + public cds::intrusive::fcstack::make_traits< + cds::opt::enable_elimination< true > + ,cds::opt::lock_type< std::mutex > + >::type + {}; + struct traits_FCStack_mutex_elimination_stat: + public cds::intrusive::fcstack::make_traits< + cds::opt::stat< cds::intrusive::fcstack::stat<> > + ,cds::opt::enable_elimination< true > + ,cds::opt::lock_type< std::mutex > + >::type + {}; + + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_stat > FCStack_slist_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_elimination > FCStack_slist_elimination; + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_elimination_stat > FCStack_slist_elimination_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_mutex_stat > FCStack_slist_mutex_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_mutex_elimination > FCStack_slist_mutex_elimination; + typedef cds::intrusive::FCStack< T, boost::intrusive::slist< T >, traits_FCStack_mutex_elimination_stat > FCStack_slist_mutex_elimination_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T > > FCStack_list; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_stat > FCStack_list_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_elimination > FCStack_list_elimination; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_elimination_stat > FCStack_list_elimination_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_mutex_stat > FCStack_list_mutex_stat; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_mutex_elimination > FCStack_list_mutex_elimination; + typedef cds::intrusive::FCStack< T, boost::intrusive::list< T >, traits_FCStack_mutex_elimination_stat > FCStack_list_mutex_elimination_stat; + + + // std::stack + typedef details::StdStack< T, std::stack< T* >, std::mutex > StdStack_Deque_Mutex; + typedef details::StdStack< T, std::stack< T* >, cds::sync::spin > StdStack_Deque_Spin; + typedef details::StdStack< T, std::stack< T*, std::vector >, std::mutex > StdStack_Vector_Mutex; + typedef details::StdStack< T, std::stack< T*, std::vector >, cds::sync::spin > StdStack_Vector_Spin; + typedef details::StdStack< T, std::stack< T*, std::list >, std::mutex > StdStack_List_Mutex; + typedef details::StdStack< T, std::stack< T*, std::list >, cds::sync::spin > StdStack_List_Spin; + + }; +} // namespace istack + +namespace cds_test { + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::treiber_stack::empty_stat const& ) + { + return o; + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::treiber_stack::stat<> const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_PushCount ) + << CDSSTRESS_STAT_OUT( s, m_PopCount ) + << CDSSTRESS_STAT_OUT( s, m_PushRace ) + << CDSSTRESS_STAT_OUT( s, m_PopRace ) + << CDSSTRESS_STAT_OUT( s, m_ActivePushCollision ) + << CDSSTRESS_STAT_OUT( s, m_PassivePopCollision ) + << CDSSTRESS_STAT_OUT( s, m_ActivePopCollision ) + << CDSSTRESS_STAT_OUT( s, m_PassivePushCollision ) + << CDSSTRESS_STAT_OUT( s, m_EliminationFailed ); + } + + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::fcstack::empty_stat const& ) + { + return o; + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::fcstack::stat<> const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_nPush ) + << CDSSTRESS_STAT_OUT( s, m_nPop ) + << CDSSTRESS_STAT_OUT( s, m_nFailedPop ) + << CDSSTRESS_STAT_OUT( s, m_nCollided ) + << CDSSTRESS_STAT_OUT_( "combining_factor", s.combining_factor() ) + << CDSSTRESS_STAT_OUT( s, m_nOperationCount ) + << CDSSTRESS_STAT_OUT( s, m_nCombiningCount ) + << CDSSTRESS_STAT_OUT( s, m_nCompactPublicationList ) + << CDSSTRESS_STAT_OUT( s, m_nDeactivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nActivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordCreated ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordDeteted ) + << CDSSTRESS_STAT_OUT( s, m_nAcquirePubRecCount ) + << CDSSTRESS_STAT_OUT( s, m_nReleasePubRecCount ); + } + +} // namespace cds_test + +#define CDSSTRESS_TreiberStack_HP( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_HP ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_HP_seqcst ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_HP_pause ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_HP_exp ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_HP_stat ) \ + +#define CDSSTRESS_TreiberStack_DHP( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_DHP ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_DHP_pause ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_DHP_exp ) \ + CDSSTRESS_Stack_F( test_fixture, Treiber_DHP_stat ) + + +#define CDSSTRESS_EliminationStack_HP( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_2ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_2ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_5ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_5ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_10ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_10ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_seqcst ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_pause ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_exp ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_dyn ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_HP_dyn_stat ) \ + + +#define CDSSTRESS_EliminationStack_DHP( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_seqcst ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_2ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_2ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_5ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_5ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_10ms ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_10ms_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_pause ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_exp ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_stat ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_dyn ) \ + CDSSTRESS_Stack_F( test_fixture, Elimination_DHP_dyn_stat ) + +#define CDSSTRESS_FCStack( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_elimination ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_elimination_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_mutex_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_mutex_elimination ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_slist_mutex_elimination_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_elimination ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_elimination_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_mutex_stat ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_mutex_elimination ) \ + CDSSTRESS_Stack_F( test_fixture, FCStack_list_mutex_elimination_stat ) + +#define CDSSTRESS_StdStack( test_fixture ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_Deque_Mutex ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_Deque_Spin ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_Vector_Mutex ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_Vector_Spin ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_List_Mutex ) \ + CDSSTRESS_Stack_F( test_fixture, StdStack_List_Spin ) + +#endif // #ifndef CDSSTRESS_INTRUSIVE_STACK_TYPES_H