xref: /oneTBB/test/tbb/test_concurrent_queue.cpp (revision 51c0b2f7)
1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev #include <common/test.h>
18*51c0b2f7Stbbdev #include <common/utils.h>
19*51c0b2f7Stbbdev #include <common/vector_types.h>
20*51c0b2f7Stbbdev #include <common/custom_allocators.h>
21*51c0b2f7Stbbdev 
22*51c0b2f7Stbbdev #include <tbb/concurrent_queue.h>
23*51c0b2f7Stbbdev 
24*51c0b2f7Stbbdev //! \file test_concurrent_queue.cpp
25*51c0b2f7Stbbdev //! \brief Test for [containers.concurrent_queue containers.concurrent_bounded_queue] specification
26*51c0b2f7Stbbdev 
27*51c0b2f7Stbbdev static constexpr std::size_t MaxThread = 4;
28*51c0b2f7Stbbdev 
29*51c0b2f7Stbbdev template<typename CQ, typename T>
30*51c0b2f7Stbbdev struct TestQueueElements {
31*51c0b2f7Stbbdev     CQ& queue;
32*51c0b2f7Stbbdev     const std::size_t nthread;
33*51c0b2f7Stbbdev     TestQueueElements( CQ& q, std::size_t n ) : queue(q), nthread(n) {}
34*51c0b2f7Stbbdev     void operator()( std::size_t k ) const {
35*51c0b2f7Stbbdev         for (std::size_t i=0; i < 1000; ++i) {
36*51c0b2f7Stbbdev             if( (i&0x1)==0 ) {
37*51c0b2f7Stbbdev                 CHECK(T(k) < T(nthread));
38*51c0b2f7Stbbdev                 queue.push(T(k));
39*51c0b2f7Stbbdev             } else {
40*51c0b2f7Stbbdev                 // Pop item from queue
41*51c0b2f7Stbbdev                 T item = 0;
42*51c0b2f7Stbbdev                 queue.try_pop(item);
43*51c0b2f7Stbbdev                 CHECK(item <= T(nthread));
44*51c0b2f7Stbbdev             }
45*51c0b2f7Stbbdev         }
46*51c0b2f7Stbbdev     }
47*51c0b2f7Stbbdev };
48*51c0b2f7Stbbdev 
49*51c0b2f7Stbbdev //! Test concurrent queue with primitive data type
50*51c0b2f7Stbbdev template<typename CQ, typename T>
51*51c0b2f7Stbbdev void TestPrimitiveTypes(std::size_t nthread, T exemplar) {
52*51c0b2f7Stbbdev     CQ queue;
53*51c0b2f7Stbbdev     for (std::size_t i = 0; i < 100; ++i) {
54*51c0b2f7Stbbdev         queue.push(exemplar);
55*51c0b2f7Stbbdev     }
56*51c0b2f7Stbbdev     utils::NativeParallelFor(nthread, TestQueueElements<CQ, T>(queue, nthread));
57*51c0b2f7Stbbdev }
58*51c0b2f7Stbbdev 
59*51c0b2f7Stbbdev void TestQueueWorksWithPrimitiveTypes() {
60*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_queue<char>, char>(MaxThread, (char)1);
61*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_queue<int>, int>(MaxThread, (int)-12);
62*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_queue<float>, float>(MaxThread, (float)-1.2f);
63*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_queue<double>, double>(MaxThread, (double)-4.3);
64*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_bounded_queue<char>, char>(MaxThread, (char)1);
65*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_bounded_queue<int>, int>(MaxThread, (int)-12);
66*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_bounded_queue<float>, float>(MaxThread, (float)-1.2f);
67*51c0b2f7Stbbdev     TestPrimitiveTypes<tbb::concurrent_bounded_queue<double>, double>(MaxThread, (double)-4.3);
68*51c0b2f7Stbbdev }
69*51c0b2f7Stbbdev 
70*51c0b2f7Stbbdev #if HAVE_m128 || HAVE_m256
71*51c0b2f7Stbbdev //! Test concurrent queue with vector types
72*51c0b2f7Stbbdev /** Type Queue should be a queue of ClassWithSSE/ClassWithAVX. */
73*51c0b2f7Stbbdev template<typename ClassWithVectorType, typename Queue>
74*51c0b2f7Stbbdev void TestVectorTypes() {
75*51c0b2f7Stbbdev     Queue q1;
76*51c0b2f7Stbbdev     for (int i = 0; i < 100; ++i) {
77*51c0b2f7Stbbdev         // VC8 does not properly align a temporary value; to work around, use explicit variable
78*51c0b2f7Stbbdev         ClassWithVectorType bar(i);
79*51c0b2f7Stbbdev         q1.push(bar);
80*51c0b2f7Stbbdev     }
81*51c0b2f7Stbbdev 
82*51c0b2f7Stbbdev     // Copy the queue
83*51c0b2f7Stbbdev     Queue q2 = q1;
84*51c0b2f7Stbbdev     // Check that elements of the copy are correct
85*51c0b2f7Stbbdev     typename Queue::const_iterator ci = q2.unsafe_begin();
86*51c0b2f7Stbbdev     for (int i=0; i < 100; ++i ) {
87*51c0b2f7Stbbdev         CHECK((ci != q2.unsafe_end()));
88*51c0b2f7Stbbdev         ClassWithVectorType foo = *ci;
89*51c0b2f7Stbbdev         ClassWithVectorType bar(i);
90*51c0b2f7Stbbdev         CHECK((*ci == bar));
91*51c0b2f7Stbbdev         ++ci;
92*51c0b2f7Stbbdev     }
93*51c0b2f7Stbbdev 
94*51c0b2f7Stbbdev     for (int i = 0; i < 101; ++i) {
95*51c0b2f7Stbbdev         ClassWithVectorType tmp;
96*51c0b2f7Stbbdev         bool b = q1.try_pop(tmp);
97*51c0b2f7Stbbdev         CHECK((b == (i < 100)));
98*51c0b2f7Stbbdev         ClassWithVectorType bar(i);
99*51c0b2f7Stbbdev         CHECK((!b || tmp==bar));
100*51c0b2f7Stbbdev     }
101*51c0b2f7Stbbdev }
102*51c0b2f7Stbbdev #endif /* HAVE_m128 || HAVE_m256 */
103*51c0b2f7Stbbdev 
104*51c0b2f7Stbbdev void TestQueueWorksWithSSE() {
105*51c0b2f7Stbbdev 
106*51c0b2f7Stbbdev #if HAVE_m128
107*51c0b2f7Stbbdev     TestVectorTypes<ClassWithSSE, tbb::concurrent_queue<ClassWithSSE> >();
108*51c0b2f7Stbbdev     TestVectorTypes<ClassWithSSE, tbb::concurrent_bounded_queue<ClassWithSSE> >();
109*51c0b2f7Stbbdev #endif /* HAVE_m128 */
110*51c0b2f7Stbbdev #if HAVE_m256
111*51c0b2f7Stbbdev     if( have_AVX() ) {
112*51c0b2f7Stbbdev         TestVectorTypes<ClassWithAVX, tbb::concurrent_queue<ClassWithAVX> >();
113*51c0b2f7Stbbdev         TestVectorTypes<ClassWithAVX, tbb::concurrent_bounded_queue<ClassWithAVX> >();
114*51c0b2f7Stbbdev     }
115*51c0b2f7Stbbdev #endif /* HAVE_m256 */
116*51c0b2f7Stbbdev }
117*51c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
118*51c0b2f7Stbbdev     int rnd_elem = -1;
119*51c0b2f7Stbbdev     int global_counter = -1;
120*51c0b2f7Stbbdev 
121*51c0b2f7Stbbdev struct throw_element {
122*51c0b2f7Stbbdev     throw_element() = default;
123*51c0b2f7Stbbdev     throw_element(const throw_element&) {
124*51c0b2f7Stbbdev         if (global_counter++ == rnd_elem) {
125*51c0b2f7Stbbdev             throw std::exception{};
126*51c0b2f7Stbbdev         }
127*51c0b2f7Stbbdev     }
128*51c0b2f7Stbbdev 
129*51c0b2f7Stbbdev     throw_element& operator= (const throw_element&) = default;
130*51c0b2f7Stbbdev };
131*51c0b2f7Stbbdev 
132*51c0b2f7Stbbdev template <typename Queue>
133*51c0b2f7Stbbdev void CopyWithThrowElement() {
134*51c0b2f7Stbbdev     utils::FastRandom<> rnd(42);
135*51c0b2f7Stbbdev 
136*51c0b2f7Stbbdev     Queue source;
137*51c0b2f7Stbbdev 
138*51c0b2f7Stbbdev     constexpr size_t queue_size = 100000;
139*51c0b2f7Stbbdev     for (std::size_t i = 0; i < queue_size; ++i) {
140*51c0b2f7Stbbdev         source.emplace();
141*51c0b2f7Stbbdev     }
142*51c0b2f7Stbbdev 
143*51c0b2f7Stbbdev     for (std::size_t i = 0; i < 100; ++i) {
144*51c0b2f7Stbbdev         global_counter = 0;
145*51c0b2f7Stbbdev         rnd_elem = rnd.get() % queue_size;
146*51c0b2f7Stbbdev 
147*51c0b2f7Stbbdev         REQUIRE_THROWS_AS( [&] {
148*51c0b2f7Stbbdev             Queue copy(source);
149*51c0b2f7Stbbdev             utils::suppress_unused_warning(copy);
150*51c0b2f7Stbbdev         }(), std::exception);
151*51c0b2f7Stbbdev     }
152*51c0b2f7Stbbdev }
153*51c0b2f7Stbbdev #endif // TBB_USE_EXCEPTIONS
154*51c0b2f7Stbbdev 
155*51c0b2f7Stbbdev //! Test work with different fypes
156*51c0b2f7Stbbdev //! \brief \ref error_guessing
157*51c0b2f7Stbbdev TEST_CASE("testing work with different fypes") {
158*51c0b2f7Stbbdev     TestQueueWorksWithPrimitiveTypes();
159*51c0b2f7Stbbdev }
160*51c0b2f7Stbbdev 
161*51c0b2f7Stbbdev //! Test work with vector types
162*51c0b2f7Stbbdev //! \brief \ref error_guessing
163*51c0b2f7Stbbdev TEST_CASE("testing vector types") {
164*51c0b2f7Stbbdev     TestQueueWorksWithSSE();
165*51c0b2f7Stbbdev }
166*51c0b2f7Stbbdev 
167*51c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
168*51c0b2f7Stbbdev //! \brief \ref regression \ref error_guessing
169*51c0b2f7Stbbdev TEST_CASE("Test exception in allocation") {
170*51c0b2f7Stbbdev     using allocator_type = StaticSharedCountingAllocator<std::allocator<int>>;
171*51c0b2f7Stbbdev     using queue_type = tbb::concurrent_queue<int, allocator_type>;
172*51c0b2f7Stbbdev 
173*51c0b2f7Stbbdev     queue_type src_queue;
174*51c0b2f7Stbbdev     for (int i = 0; i < 100000; ++i) {
175*51c0b2f7Stbbdev         src_queue.push(i);
176*51c0b2f7Stbbdev     }
177*51c0b2f7Stbbdev 
178*51c0b2f7Stbbdev     allocator_type::set_limits(1);
179*51c0b2f7Stbbdev 
180*51c0b2f7Stbbdev     REQUIRE_THROWS_AS( [] {
181*51c0b2f7Stbbdev         queue_type queue1;
182*51c0b2f7Stbbdev         queue1.push(1);
183*51c0b2f7Stbbdev     }(), const std::bad_alloc);
184*51c0b2f7Stbbdev 
185*51c0b2f7Stbbdev     for (std::size_t i = 1; i < 1000; ++i) {
186*51c0b2f7Stbbdev         allocator_type::init_counters();
187*51c0b2f7Stbbdev         allocator_type::set_limits(1);
188*51c0b2f7Stbbdev         REQUIRE_THROWS_AS( [&] {
189*51c0b2f7Stbbdev             queue_type queue2(src_queue);
190*51c0b2f7Stbbdev             utils::suppress_unused_warning(queue2);
191*51c0b2f7Stbbdev         }(), const std::bad_alloc);
192*51c0b2f7Stbbdev     }
193*51c0b2f7Stbbdev }
194*51c0b2f7Stbbdev 
195*51c0b2f7Stbbdev //! \brief \ref regression \ref error_guessing
196*51c0b2f7Stbbdev TEST_CASE("Test exception in allocation") {
197*51c0b2f7Stbbdev     CopyWithThrowElement<tbb::concurrent_queue<throw_element>>();
198*51c0b2f7Stbbdev     CopyWithThrowElement<tbb::concurrent_bounded_queue<throw_element>>();
199*51c0b2f7Stbbdev }
200*51c0b2f7Stbbdev 
201*51c0b2f7Stbbdev #endif // TBB_USE_EXCEPTIONS
202