2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
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 "queue_type.h"
35 #include <type_traits>
37 // Single producer/single consumer buffer push/pop test
40 static size_t s_nBufferSize = 1024*1024;
41 static size_t s_nPushCount = 1000000;
43 static std::atomic<size_t> s_nProducerDone( 0 );
45 class spsc_buffer: public cds_test::stress_fixture
48 typedef size_t value_type;
55 template <class Queue>
56 class Producer: public cds_test::thread
58 typedef cds_test::thread base_class;
61 Producer( cds_test::thread_pool& pool, Queue& queue )
62 : base_class( pool, producer_thread )
66 Producer( Producer& src )
68 , m_Queue( src.m_Queue )
71 virtual thread * clone()
73 return new Producer( *this );
78 size_t const nPushCount = s_nPushCount;
80 for ( size_t i = 0; i < nPushCount; ++i ) {
81 size_t len = rand( 1024 ) + 64;
82 void* buf = m_Queue.back( len );
84 memset( buf, len % 256, len );
92 s_nProducerDone.fetch_add( 1 );
97 size_t m_nPushFailed = 0;
101 template <class Queue>
102 class Consumer: public cds_test::thread
104 typedef cds_test::thread base_class;
108 size_t m_nPopEmpty = 0;
109 size_t m_nPopped = 0;
110 size_t m_nBadValue = 0;
111 size_t m_nPopFrontFailed = 0;
114 Consumer( cds_test::thread_pool& pool, Queue& queue )
115 : base_class( pool, consumer_thread )
118 Consumer( Consumer& src )
120 , m_Queue( src.m_Queue )
123 virtual thread * clone()
125 return new Consumer( *this );
131 auto buf = m_Queue.front();
133 m_nPopped += buf.second;
135 uint8_t val = static_cast<uint8_t>( buf.second % 256 );
136 uint8_t const* p = reinterpret_cast<uint8_t*>( buf.first );
137 for ( uint8_t const* pEnd = p + buf.second; p < pEnd; ++p ) {
144 if ( !m_Queue.pop_front() )
149 if ( s_nProducerDone.load() != 0 ) {
150 if ( m_Queue.empty() )
159 size_t m_nThreadPushCount;
162 template <class Queue>
163 void test_queue( Queue& q )
165 cds_test::thread_pool& pool = get_pool();
166 auto producer = new Producer<Queue>( pool, q );
167 auto consumer = new Consumer<Queue>( pool, q );
169 pool.add( producer, 1 );
170 pool.add( consumer, 1 );
172 s_nProducerDone.store( 0 );
174 propout() << std::make_pair( "buffer_size", s_nBufferSize )
175 << std::make_pair( "push_count", s_nPushCount );
177 std::chrono::milliseconds duration = pool.run();
179 propout() << std::make_pair( "duration", duration );
182 EXPECT_EQ( consumer->m_nBadValue, 0u );
183 EXPECT_EQ( consumer->m_nPopFrontFailed, 0u );
184 EXPECT_EQ( consumer->m_nPopped, producer->m_nPushed );
187 << std::make_pair( "producer_push_length", producer->m_nPushed )
188 << std::make_pair( "producer_push_failed", producer->m_nPushFailed )
189 << std::make_pair( "consumer_pop_length", consumer->m_nPopped )
190 << std::make_pair( "consumer_pop_empty", consumer->m_nPopEmpty )
191 << std::make_pair( "consumer_bad_value", consumer->m_nBadValue )
192 << std::make_pair( "consumer_pop_front_failed", consumer->m_nPopFrontFailed );
195 template <class Queue>
196 void test( Queue& q )
199 propout() << q.statistics();
203 static void SetUpTestCase()
205 cds_test::config const& cfg = get_config( "spsc_buffer" );
207 s_nBufferSize = cfg.get_size_t( "BufferSize", s_nBufferSize );
208 s_nPushCount = cfg.get_size_t( "PushCount", s_nPushCount );
210 if ( s_nBufferSize < 1024 * 64 )
211 s_nBufferSize = 1024 * 64;
212 if ( s_nPushCount == 0u )
217 #undef CDSSTRESS_Queue_F
218 #define CDSSTRESS_Queue_F( test_fixture, type_name ) \
219 TEST_F( test_fixture, type_name ) \
221 typedef queue::Types< value_type >::type_name queue_type; \
222 queue_type queue( s_nBufferSize ); \
226 CDSSTRESS_WeakRingBuffer_void( spsc_buffer )
228 #undef CDSSTRESS_Queue_F