2 * Copyright 2012 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "folly/ProducerConsumerQueue.h"
19 #include <gtest/gtest.h>
25 #include <glog/logging.h>
27 //////////////////////////////////////////////////////////////////////
31 template<class T> struct TestTraits {
32 T limit() const { return 1 << 24; }
33 T generate() const { return rand() % 26; }
36 template<> struct TestTraits<std::string> {
37 int limit() const { return 1 << 21; }
38 std::string generate() const { return std::string(12, ' '); }
41 template<class QueueType, size_t Size>
43 typedef typename QueueType::value_type T;
45 explicit PerfTest() : queue_(Size), done_(false) {}
48 using namespace std::chrono;
49 auto const startTime = system_clock::now();
51 std::thread producer([this] { this->producer(); });
52 std::thread consumer([this] { this->consumer(); });
58 auto duration = duration_cast<milliseconds>(
59 system_clock::now() - startTime);
60 LOG(INFO) << " done: " << duration.count() << "ms";
64 for (int i = 0; i < traits_.limit(); ++i) {
65 while (!queue_.write(traits_.generate())) {
78 std::atomic<bool> done_;
79 TestTraits<T> traits_;
82 template<class TestType> void doTest(const char* name) {
83 LOG(INFO) << " testing: " << name;
84 std::unique_ptr<TestType> const t(new TestType());
88 template<class T> void perfTestType(const char* type) {
89 const size_t size = 0xfffe;
91 LOG(INFO) << "Type: " << type;
92 doTest<PerfTest<folly::ProducerConsumerQueue<T>,size> >(
93 "ProducerConsumerQueue");
96 template<class QueueType, size_t Size>
97 struct CorrectnessTest {
98 typedef typename QueueType::value_type T;
100 explicit CorrectnessTest()
104 const size_t testSize = traits_.limit();
105 testData_.reserve(testSize);
106 for (int i = 0; i < testSize; ++i) {
107 testData_.push_back(traits_.generate());
112 std::thread producer([this] { this->producer(); });
113 std::thread consumer([this] { this->consumer(); });
121 for (auto& data : testData_) {
122 while (!queue_.write(data)) {
128 for (auto& expect : testData_) {
131 if (!queue_.read(data)) {
133 // Try one more read; unless there's a bug in the queue class
134 // there should still be more data sitting in the queue even
135 // though the producer thread exited.
136 if (!queue_.read(data)) {
137 EXPECT_TRUE(0 && "Finished too early ...");
144 EXPECT_EQ(data, expect);
148 std::vector<T> testData_;
150 TestTraits<T> traits_;
151 std::atomic<bool> done_;
154 template<class T> void correctnessTestType(const std::string& type) {
155 LOG(INFO) << "Type: " << type;
156 doTest<CorrectnessTest<folly::ProducerConsumerQueue<T>,0xfffe> >(
157 "ProducerConsumerQueue");
161 static int numInstances;
162 DtorChecker() { ++numInstances; }
163 DtorChecker(const DtorChecker& o) { ++numInstances; }
164 ~DtorChecker() { --numInstances; }
167 int DtorChecker::numInstances = 0;
171 //////////////////////////////////////////////////////////////////////
173 TEST(PCQ, QueueCorrectness) {
174 correctnessTestType<std::string>("string");
175 correctnessTestType<int>("int");
176 correctnessTestType<unsigned long long>("unsigned long long");
179 TEST(PCQ, PerfTest) {
180 perfTestType<std::string>("string");
181 perfTestType<int>("int");
182 perfTestType<unsigned long long>("unsigned long long");
185 TEST(PCQ, Destructor) {
186 // Test that orphaned elements in a ProducerConsumerQueue are
189 folly::ProducerConsumerQueue<DtorChecker> queue(1024);
190 for (int i = 0; i < 10; ++i) {
191 EXPECT_TRUE(queue.write(DtorChecker()));
194 EXPECT_EQ(DtorChecker::numInstances, 10);
198 EXPECT_TRUE(queue.read(ignore));
199 EXPECT_TRUE(queue.read(ignore));
202 EXPECT_EQ(DtorChecker::numInstances, 8);
205 EXPECT_EQ(DtorChecker::numInstances, 0);
207 // Test the same thing in the case that the queue write pointer has
208 // wrapped, but the read one hasn't.
210 folly::ProducerConsumerQueue<DtorChecker> queue(4);
211 for (int i = 0; i < 3; ++i) {
212 EXPECT_TRUE(queue.write(DtorChecker()));
214 EXPECT_EQ(DtorChecker::numInstances, 3);
217 EXPECT_TRUE(queue.read(ignore));
219 EXPECT_EQ(DtorChecker::numInstances, 2);
220 EXPECT_TRUE(queue.write(DtorChecker()));
221 EXPECT_EQ(DtorChecker::numInstances, 3);
223 EXPECT_EQ(DtorChecker::numInstances, 0);