Rearranged queue tests
[libcds.git] / tests / unit / queue / bounded_queue_fulness.cpp
1 //$$CDS-header$$
2
3 #include "cppunit/thread.h"
4 #include "queue/queue_type.h"
5 #include "queue/queue_defs.h"
6
7
8 /*
9     Bounded queue test.
10     The test checks the behaviour of bounded queue when it is almost full.
11     Many algorithms says the queue is full when it is not, and vice versa.
12 */
13 namespace queue {
14
15 #define TEST_BOUNDED( Q, V )    void Q() { test< Types<V>::Q >(); }
16
17     namespace ns_BoundedQueue_Fullness {
18         static size_t s_nThreadCount = 8;
19         static size_t s_nQueueSize = 1024;
20         static size_t s_nPassCount = 1000000;
21     }
22     using namespace ns_BoundedQueue_Fullness;
23
24     class VyukovMPMCCycleQueue_dyn_fair_ : public Types<size_t>::VyukovMPMCCycleQueue_dyn_ic
25     {
26         typedef Types<size_t>::VyukovMPMCCycleQueue_dyn_ic base_class;
27     public:
28         typedef base_class::value_type value_type;
29
30         VyukovMPMCCycleQueue_dyn_fair_()
31             : base_class()
32         {}
33
34         VyukovMPMCCycleQueue_dyn_fair_( size_t nCapacity )
35             : base_class( nCapacity )
36         {}
37
38         bool enqueue( value_type const& data )
39         {
40             bool ret;
41             do {
42                 ret = base_class::enqueue( data );
43             } while ( !ret && size() != capacity() );
44             return ret;
45         }
46
47         bool push( value_type const& data )
48         {
49             return enqueue( data );
50         }
51
52         bool dequeue( value_type& dest )
53         {
54             bool ret;
55             do {
56                 ret = base_class::dequeue( dest );
57             } while ( !ret && size() != capacity() );
58             return ret;
59         }
60
61         bool pop( value_type& dest )
62         {
63             return dequeue( dest );
64         }
65
66         size_t size() const { return base_class::size(); }
67         size_t capacity() const { return base_class::capacity(); }
68     };
69
70     class BoundedQueue_Fullness: public CppUnitMini::TestCase
71     {
72         template <class Queue>
73         class Thread: public CppUnitMini::TestThread
74         {
75             virtual TestThread *    clone()
76             {
77                 return new Thread( *this );
78             }
79         public:
80             Queue&              m_Queue;
81             double              m_fTime;
82             size_t              m_nPushError;
83             size_t              m_nPopError;
84
85         public:
86             Thread( CppUnitMini::ThreadPool& pool, Queue& q )
87                 : CppUnitMini::TestThread( pool )
88                 , m_Queue( q )
89             {}
90             Thread( Thread& src )
91                 : CppUnitMini::TestThread( src )
92                 , m_Queue( src.m_Queue )
93             {}
94
95             BoundedQueue_Fullness&  getTest()
96             {
97                 return reinterpret_cast<BoundedQueue_Fullness&>( m_Pool.m_Test );
98             }
99
100             virtual void init()
101             {
102                 cds::threading::Manager::attachThread();
103             }
104             virtual void fini()
105             {
106                 cds::threading::Manager::detachThread();
107             }
108
109             virtual void test()
110             {
111                 m_fTime = m_Timer.duration();
112
113                 m_nPushError = 0;
114                 m_nPopError = 0;
115                 for ( size_t i = 0; i < s_nPassCount; ++i ) {
116                     if ( !m_Queue.push( i ))
117                         ++m_nPushError;
118                     size_t item;
119                     if ( !m_Queue.pop( item ))
120                         ++m_nPopError;
121                 }
122                 m_fTime = m_Timer.duration() - m_fTime;
123             }
124         };
125
126     protected:
127         template <class Queue>
128         void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue  )
129         {
130             double fTime = 0;
131             size_t nPushError = 0;
132             size_t nPopError = 0;
133             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
134                 Thread<Queue> * pThread = reinterpret_cast<Thread<Queue> *>(*it);
135                 fTime += pThread->m_fTime;
136                 nPushError += pThread->m_nPushError;
137                 nPopError  += pThread->m_nPopError;
138             }
139             CPPUNIT_MSG( "     Duration=" << (fTime / s_nThreadCount) );
140             CPPUNIT_MSG( "     Errors: push=" << nPushError << ", pop=" << nPopError );
141             CPPUNIT_CHECK( !testQueue.empty());
142             CPPUNIT_CHECK( nPushError == 0 );
143             CPPUNIT_CHECK( nPopError == 0 );
144         }
145
146         template <class Queue>
147         void test()
148         {
149             Queue testQueue( s_nQueueSize );
150
151             CppUnitMini::ThreadPool pool( *this );
152             pool.add( new Thread<Queue>( pool, testQueue ), s_nThreadCount );
153
154             size_t nSize = testQueue.capacity() - s_nThreadCount;
155             for ( size_t i = 0; i < nSize; ++i )
156                 testQueue.push( i );
157
158             CPPUNIT_MSG( "   Thread count=" << s_nThreadCount << ", push/pop pairs=" << s_nPassCount 
159                          << ", queue capacity=" << testQueue.capacity() << " ...");
160             pool.run();
161
162             analyze( pool, testQueue );
163
164             CPPUNIT_MSG( testQueue.statistics() );
165         }
166         void setUpParams( const CppUnitMini::TestCfg& cfg ) {
167             s_nThreadCount = cfg.getULong("ThreadCount", 8 );
168             s_nQueueSize = cfg.getULong("QueueSize", 1024 );
169             s_nPassCount = cfg.getULong( "PassCount", 1000000 );
170         }
171
172     protected:
173         CDSUNIT_DECLARE_TsigasCycleQueue( size_t )
174         CDSUNIT_DECLARE_VyukovMPMCCycleQueue( size_t )
175         void VyukovMPMCCycleQueue_dyn_fair()
176         {
177             test< VyukovMPMCCycleQueue_dyn_fair_ >();
178         }
179
180         CPPUNIT_TEST_SUITE( BoundedQueue_Fullness )
181             CDSUNIT_TEST_TsigasCycleQueue
182             CDSUNIT_TEST_VyukovMPMCCycleQueue
183             CPPUNIT_TEST( VyukovMPMCCycleQueue_dyn_fair_ ) \
184         CPPUNIT_TEST_SUITE_END();
185     };
186
187 } // namespace queue
188
189 CPPUNIT_TEST_SUITE_REGISTRATION(queue::BoundedQueue_Fullness );