push.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright (c) 2006-2018 Maxim Khizhinsky
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include "stack_type.h"
  6. namespace {
  7. static size_t s_nThreadCount = 8;
  8. static size_t s_nStackSize = 10000000;
  9. static size_t s_nEliminationSize = 4;
  10. class stack_push : public cds_test::stress_fixture
  11. {
  12. protected:
  13. struct value_type {
  14. size_t nNo;
  15. size_t nThread;
  16. value_type()
  17. : nNo( 0 )
  18. , nThread( 0 )
  19. {}
  20. value_type( size_t n )
  21. : nNo( n )
  22. , nThread( 0 )
  23. {}
  24. };
  25. template <class Stack>
  26. class Producer: public cds_test::thread
  27. {
  28. typedef cds_test::thread base_class;
  29. public:
  30. Producer( cds_test::thread_pool& pool, Stack& stack )
  31. : base_class( pool )
  32. , m_stack( stack )
  33. , m_nStartItem( 0 )
  34. , m_nEndItem( 0 )
  35. , m_nPushError( 0 )
  36. {}
  37. Producer( Producer& src )
  38. : base_class( src )
  39. , m_stack( src.m_stack )
  40. , m_nStartItem( 0 )
  41. , m_nEndItem( 0 )
  42. , m_nPushError( 0 )
  43. {}
  44. virtual thread * clone()
  45. {
  46. return new Producer( *this );
  47. }
  48. virtual void test()
  49. {
  50. value_type v;
  51. v.nThread = id();
  52. for ( v.nNo = m_nStartItem; v.nNo < m_nEndItem; ++v.nNo ) {
  53. if ( !m_stack.push( v ))
  54. ++m_nPushError;
  55. }
  56. }
  57. public:
  58. Stack& m_stack;
  59. size_t m_nStartItem;
  60. size_t m_nEndItem;
  61. size_t m_nPushError;
  62. };
  63. protected:
  64. static void SetUpTestCase()
  65. {
  66. cds_test::config const& cfg = get_config("Stack_Push");
  67. s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount );
  68. s_nStackSize = cfg.get_size_t( "StackSize", s_nStackSize );
  69. s_nEliminationSize = cfg.get_size_t( "EliminationSize", s_nEliminationSize );
  70. if ( s_nThreadCount == 0 )
  71. s_nThreadCount = 1;
  72. }
  73. //static void TearDownTestCase();
  74. template <typename Stack>
  75. void test( Stack& stack )
  76. {
  77. cds_test::thread_pool& pool = get_pool();
  78. pool.add( new Producer<Stack>( pool, stack ), s_nThreadCount );
  79. size_t nStart = 0;
  80. size_t nThreadItemCount = s_nStackSize / s_nThreadCount;
  81. for ( size_t i = 0; i < pool.size(); ++i ) {
  82. Producer<Stack>& thread = static_cast<Producer<Stack>&>( pool.get( i ));
  83. thread.m_nStartItem = nStart;
  84. nStart += nThreadItemCount;
  85. thread.m_nEndItem = nStart;
  86. }
  87. propout() << std::make_pair( "thread_count", s_nThreadCount )
  88. << std::make_pair( "push_count", s_nStackSize );
  89. std::chrono::milliseconds duration = pool.run();
  90. propout() << std::make_pair( "duration", duration );
  91. analyze( stack );
  92. propout() << stack.statistics();
  93. }
  94. template <typename Stack>
  95. void test_elimination( Stack& stack )
  96. {
  97. test( stack );
  98. check_elimination_stat( stack.statistics());
  99. }
  100. void check_elimination_stat( cds::container::treiber_stack::empty_stat const& )
  101. {}
  102. void check_elimination_stat( cds::container::treiber_stack::stat<> const& s )
  103. {
  104. EXPECT_EQ( s.m_PushCount.get(), s.m_PopCount.get());
  105. }
  106. template <class Stack>
  107. void analyze( Stack& testStack )
  108. {
  109. cds_test::thread_pool& pool = get_pool();
  110. size_t nThreadItems = s_nStackSize / s_nThreadCount;
  111. std::vector<size_t> aThread;
  112. aThread.resize( s_nThreadCount );
  113. for ( size_t i = 0; i < pool.size(); ++i ) {
  114. Producer<Stack>& producer = static_cast<Producer<Stack>&>( pool.get( i ));
  115. EXPECT_EQ( producer.m_nPushError, 0u ) << "Producer=" << i;
  116. aThread[producer.id()] = producer.m_nEndItem - 1;
  117. }
  118. EXPECT_FALSE( testStack.empty());
  119. std::unique_ptr< uint8_t[] > uarr( new uint8_t[s_nStackSize] );
  120. uint8_t * arr = uarr.get();
  121. memset( arr, 0, sizeof( arr[0] ) * s_nStackSize );
  122. auto time_start = std::chrono::steady_clock::now();
  123. size_t nPopped = 0;
  124. value_type val;
  125. while ( testStack.pop( val )) {
  126. nPopped++;
  127. ASSERT_LT( val.nNo, s_nStackSize );
  128. ++arr[val.nNo];
  129. ASSERT_LT( val.nThread, s_nThreadCount );
  130. ASSERT_EQ( aThread[val.nThread], val.nNo );
  131. aThread[val.nThread]--;
  132. }
  133. propout() << std::make_pair( "pop_duration", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - time_start));
  134. size_t nTotalItems = nThreadItems * s_nThreadCount;
  135. size_t nError = 0;
  136. for ( size_t i = 0; i < nTotalItems; ++i ) {
  137. EXPECT_EQ( arr[i], 1 ) << "i=" << i;
  138. if ( ++nError > 10 ) {
  139. ASSERT_EQ( arr[i], 1 );
  140. }
  141. }
  142. }
  143. };
  144. CDSSTRESS_TreiberStack( stack_push )
  145. CDSSTRESS_EliminationStack( stack_push )
  146. CDSSTRESS_FCStack( stack_push )
  147. CDSSTRESS_FCDeque( stack_push )
  148. CDSSTRESS_StdStack( stack_push )
  149. } // namespace