Remove cds/details/std/memory.h, use STL <memory> instead
[libcds.git] / tests / unit / pqueue / pop.cpp
1 //$$CDS-header$$
2
3 #include "cppunit/thread.h"
4 #include "pqueue/pqueue_item.h"
5 #include "pqueue/pqueue_type.h"
6
7 #include <vector>
8 #include <algorithm>    // random_shuffle
9 #include <memory>
10
11 namespace pqueue {
12
13 #define TEST_CASE( Q ) void Q() { test< Types<pqueue::SimpleValue>::Q >(); }
14 #define TEST_BOUNDED( Q ) void Q() { test_bounded< Types<pqueue::SimpleValue>::Q >(); }
15
16     namespace {
17         static size_t s_nThreadCount = 8;
18         static size_t s_nQueueSize = 2000000;
19     }
20 } // namespace pqueue
21
22 namespace pqueue {
23
24     class PQueue_Pop: public CppUnitMini::TestCase
25     {
26
27         template <class PQueue>
28         class Pusher: public CppUnitMini::TestThread
29         {
30             virtual TestThread *    clone()
31             {
32                 return new Pusher( *this );
33             }
34         public:
35             PQueue&             m_Queue;
36             size_t              m_nPushError;
37
38             typedef std::vector<size_t> array_type;
39             array_type          m_arr;
40
41         public:
42             Pusher( CppUnitMini::ThreadPool& pool, PQueue& q )
43                 : CppUnitMini::TestThread( pool )
44                 , m_Queue( q )
45             {}
46             Pusher( Pusher& src )
47                 : CppUnitMini::TestThread( src )
48                 , m_Queue( src.m_Queue )
49             {}
50
51             PQueue_Pop&  getTest()
52             {
53                 return static_cast<PQueue_Pop&>( m_Pool.m_Test );
54             }
55
56             virtual void init()
57             {
58                 cds::threading::Manager::attachThread();
59             }
60             virtual void fini()
61             {
62                 cds::threading::Manager::detachThread();
63             }
64
65             virtual void test()
66             {
67                 m_nPushError = 0;
68
69                 for ( array_type::const_iterator it = m_arr.begin(); it != m_arr.end(); ++it ) {
70                     if ( !m_Queue.push( SimpleValue( *it ) ))
71                         ++m_nPushError;
72                 }
73             }
74
75             void prepare( size_t nStart, size_t nEnd )
76             {
77                 m_arr.reserve( nEnd - nStart );
78                 for ( size_t i = nStart; i < nEnd; ++i )
79                     m_arr.push_back( i );
80                 std::random_shuffle( m_arr.begin(), m_arr.end() );
81             }
82         };
83
84         template <class PQueue>
85         class Popper: public CppUnitMini::TestThread
86         {
87             virtual TestThread *    clone()
88             {
89                 return new Popper( *this );
90             }
91         public:
92             PQueue&             m_Queue;
93             size_t              m_nPopError;
94             size_t              m_nPopSuccess;
95             size_t              m_nPopFailed;
96
97             typedef std::vector<size_t> array_type;
98             array_type          m_arr;
99
100         public:
101             Popper( CppUnitMini::ThreadPool& pool, PQueue& q )
102                 : CppUnitMini::TestThread( pool )
103                 , m_Queue( q )
104             {}
105             Popper( Popper& src )
106                 : CppUnitMini::TestThread( src )
107                 , m_Queue( src.m_Queue )
108             {}
109
110             PQueue_Pop&  getTest()
111             {
112                 return static_cast<PQueue_Pop&>( m_Pool.m_Test );
113             }
114
115             virtual void init()
116             {
117                 cds::threading::Manager::attachThread();
118             }
119             virtual void fini()
120             {
121                 cds::threading::Manager::detachThread();
122             }
123
124             virtual void test()
125             {
126                 m_nPopError = 0;
127                 m_nPopSuccess = 0;
128                 m_nPopFailed = 0;
129
130                 size_t nPrevKey;
131                 SimpleValue val;
132                 if ( m_Queue.pop( val )) {
133                     ++m_nPopSuccess;
134                     nPrevKey = val.key;
135
136                     while ( !m_Queue.empty() ) {
137                         if ( m_Queue.pop( val )) {
138                             ++m_nPopSuccess;
139                             if ( val.key >= nPrevKey )
140                                 ++m_nPopError;
141                             nPrevKey = val.key;
142                         }
143                         else
144                             ++m_nPopFailed;
145                     }
146                 }
147             }
148         };
149
150     protected:
151         template <class PQueue>
152         void test()
153         {
154             PQueue testQueue;
155             test_with( testQueue );
156         }
157
158         template <class PQueue>
159         void test_bounded()
160         {
161             std::unique_ptr<PQueue> pq( new PQueue(s_nQueueSize) );
162             test_with( *pq.get() );
163         }
164
165         template <class PQueue>
166         void test_with( PQueue& testQueue )
167         {
168             size_t const nThreadItemCount = s_nQueueSize / s_nThreadCount;
169
170             // push
171             {
172                 CppUnitMini::ThreadPool pool( *this );
173                 pool.add( new Pusher<PQueue>( pool, testQueue ), s_nThreadCount );
174
175                 size_t nStart = 0;
176                 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
177                     Pusher<PQueue> * pThread = static_cast<Pusher<PQueue> *>(*it);
178                     pThread->prepare( nStart, nStart + nThreadItemCount );
179                     nStart += nThreadItemCount;
180                 }
181
182                 CPPUNIT_MSG( "   Push, thread count=" << s_nThreadCount << ", item count=" << nThreadItemCount * s_nThreadCount << " ..." );
183                 pool.run();
184                 CPPUNIT_MSG( "     Duration=" << pool.avgDuration() );
185             }
186
187             // pop
188             {
189                 CppUnitMini::ThreadPool pool( *this );
190                 pool.add( new Popper<PQueue>( pool, testQueue ), s_nThreadCount );
191
192                 CPPUNIT_MSG( "   Pop, thread count=" << s_nThreadCount << ", item count=" << nThreadItemCount * s_nThreadCount << " ..." );
193                 pool.run();
194                 CPPUNIT_MSG( "     Duration=" << pool.avgDuration() );
195
196                 // Analyze result
197                 size_t nTotalPopped = 0;
198                 size_t nTotalError = 0;
199                 size_t nTotalFailed = 0;
200                 for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
201                     Popper<PQueue> * pThread = static_cast<Popper<PQueue> *>(*it);
202
203                     nTotalPopped += pThread->m_nPopSuccess;
204                     nTotalError += pThread->m_nPopError;
205                     nTotalFailed += pThread->m_nPopFailed;
206                 }
207
208                 CPPUNIT_MSG( "   Total: popped=" << nTotalPopped << ", error=" << nTotalError << ", empty pop=" << nTotalFailed );
209                 CPPUNIT_CHECK( nTotalPopped == nThreadItemCount * s_nThreadCount );
210                 CPPUNIT_CHECK( nTotalError == 0 );
211             }
212
213             CPPUNIT_MSG( testQueue.statistics() );
214         }
215
216         void setUpParams( const CppUnitMini::TestCfg& cfg ) {
217             s_nThreadCount = cfg.getULong("ThreadCount", (unsigned long) s_nThreadCount );
218             s_nQueueSize = cfg.getULong("QueueSize", (unsigned long) s_nQueueSize );
219         }
220
221     protected:
222 #include "pqueue/pqueue_defs.h"
223         CDSUNIT_DECLARE_MSPriorityQueue
224         CDSUNIT_DECLARE_EllenBinTree
225         CDSUNIT_DECLARE_SkipList
226         CDSUNIT_DECLARE_FCPriorityQueue
227         CDSUNIT_DECLARE_StdPQueue
228
229         CPPUNIT_TEST_SUITE_(PQueue_Pop, "PQueue_Push")
230             CDSUNIT_TEST_MSPriorityQueue
231             CDSUNIT_TEST_EllenBinTree
232             CDSUNIT_TEST_SkipList
233             CDSUNIT_TEST_FCPriorityQueue
234             CDUNIT_TEST_StdPQueue
235         CPPUNIT_TEST_SUITE_END();
236     };
237
238 } // namespace queue
239
240 CPPUNIT_TEST_SUITE_REGISTRATION(pqueue::PQueue_Pop);