Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1012)

Unified Diff: webrtc/modules/audio_processing/swapped_nonblocking_queue_unittest.cc

Issue 1398473004: Changed queue implementation to the proposed vector-based solution. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@lock_unittest_CL
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/audio_processing/swapped_nonblocking_queue_unittest.cc
diff --git a/webrtc/modules/audio_processing/swapped_nonblocking_queue_unittest.cc b/webrtc/modules/audio_processing/swapped_nonblocking_queue_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..416cd79951ab4eb771981a099fec6cc123a3417c
--- /dev/null
+++ b/webrtc/modules/audio_processing/swapped_nonblocking_queue_unittest.cc
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
kwiberg-webrtc 2015/10/10 10:16:57 You do seem to like multiples of 53...
peah-webrtc 2015/10/12 13:01:08 It is a prime number :-) But is it occurring in t
hlundin-webrtc 2015/10/13 06:37:58 I think 53 is just a coincident. 19 is obviously t
peah-webrtc 2015/10/13 11:56:12 :-) It is a shame 42 is no prime number.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <tuple>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/audio_processing/swapped_nonblocking_queue.h"
+#include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/system_wrappers/interface/event_wrapper.h"
+#include "webrtc/system_wrappers/interface/sleep.h"
+#include "webrtc/system_wrappers/interface/thread_wrapper.h"
+
+namespace webrtc {
+
+namespace {
+
+// Sample data type enum.
+enum class DataType { Float, Int16 };
+
+// The type for a message.
+class Message {
+ public:
+ Message() {
+ id_ = -1;
+ info_ = -1;
+ }
+
+ explicit Message(const Message& m) {
kwiberg-webrtc 2015/10/10 10:16:57 Copy constructor shouldn't be explicit.
peah-webrtc 2015/10/12 13:01:08 Done.
+ id_ = m.id_;
+ info_ = m.info_;
+ }
+
+ explicit Message(int id, int info) {
hlundin-webrtc 2015/10/13 06:37:57 No need to make a 2-argument constructor explicit,
peah-webrtc 2015/10/13 11:56:12 True! Removed that.
+ id_ = id;
+ info_ = info;
+ }
+
+ bool Compare(const Message& m) {
+ return ((id_ == m.id_) && (info_ == m.info_));
+ }
+
+ void swap(Message& m) {
+ int tmp = id_;
+ id_ = m.id_;
+ m.id_ = tmp;
+
+ tmp = info_;
+ info_ = m.info_;
+ m.info_ = tmp;
kwiberg-webrtc 2015/10/10 10:16:57 std::swap(id_, m.id_); std::swap(info_, m.info_);
peah-webrtc 2015/10/12 13:01:08 Done.
+ }
+
+ private:
+ int id_;
+ int info_;
+};
+
+// Implements the tests for the sample queue.
+class SwappedNonBlockingQueueMessageTest
+ : public ::testing::TestWithParam<::testing::tuple<size_t, size_t>> {
+ public:
+ SwappedNonBlockingQueueMessageTest()
+ : test_complete_(EventWrapper::Create()),
+ reader_thread_(
+ ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
+ writer_thread_(
+ ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
+
+ // Run the test with a timeout.
+ EventTypeWrapper RunTest() {
+ StartThreads();
+ return test_complete_->Wait(kTestTimeOutLimit);
+ }
+
+ virtual void SetUp() {
+ // Read test parameter
+ size_t queue_size = static_cast<size_t>(testing::get<0>(GetParam()));
+ size_t messages_size = static_cast<size_t>(testing::get<1>(GetParam()));
+
+ // Create queues.
+ queue_.reset(new SwappedNonBlockingQueue<Message>(queue_size));
+
+ // Create and populate message vector.
+ messages_ = std::vector<Message>();
+ CreateTestData(messages_size);
+ }
+
+ virtual void TearDown() {
+ reader_thread_->Stop();
+ writer_thread_->Stop();
+ }
+
+ private:
+ const int kTestTimeOutLimit = 10 * 1000;
+
+ // Populates the data vectors with random values.
+ void CreateTestData(int messages_size) {
+ messages_.resize(messages_size);
+ for (size_t k = 0; k < messages_.size(); k++)
+ messages_[k] =
+ Message(rand_r(&writer_seed) % 10000, rand_r(&writer_seed) % 10000);
+ }
+
+ // Thread callback for the reader thread
hlundin-webrtc 2015/10/13 06:37:57 End with .
peah-webrtc 2015/10/13 11:56:12 Done.
+ static bool CbReaderThread(void* context) {
+ return reinterpret_cast<SwappedNonBlockingQueueMessageTest*>(context)
+ ->CbReaderImpl();
+ }
+
+ // Thread callback for the writer thread
hlundin-webrtc 2015/10/13 06:37:57 End with .
peah-webrtc 2015/10/13 11:56:12 Done.
+ static bool CbWriterThread(void* context) {
+ return reinterpret_cast<SwappedNonBlockingQueueMessageTest*>(context)
+ ->CbWriterImpl();
+ }
+
+ // Tests in a threadsafe manner whether all the samples have been
+ // written and read.
+ bool TestDone() { return (GetNumMessagesRead() == messages_.size()); }
+
+ // Returns in a threadsafe manner the number of frames read from the queue.
+ size_t GetNumMessagesRead() {
hlundin-webrtc 2015/10/13 06:37:57 const-declare the method (and make crit_ mutable).
peah-webrtc 2015/10/13 11:56:12 Done.
+ rtc::CritScope cs(&crit_);
+ return num_messages_read_;
hlundin-webrtc 2015/10/13 06:37:57 I'm not sure, but this seems like the kind of thin
peah-webrtc 2015/10/13 11:56:11 That is fully true. But I think for the purpose of
+ }
+
+ // Increases in a threadsafe manner the number of messages
+ // read from the queue.
+ void IncreaseMessageReadCounter() {
+ rtc::CritScope cs(&crit_);
+ num_messages_read_++;
+ }
+
+ // Implements the callback functionality for the reader thread.
+ bool CbReaderImpl() {
+ SleepRandomTime(3, &reader_seed);
+
+ // Read the message and verify bitexactness.
+ size_t num_messages_read = GetNumMessagesRead();
hlundin-webrtc 2015/10/13 06:37:58 const But, you don't need this variable, at least
peah-webrtc 2015/10/13 11:56:12 Done.
+ Message m;
+ if (queue_->Remove(&m)) {
+ EXPECT_TRUE(m.Compare(messages_[num_messages_read]));
+ IncreaseMessageReadCounter();
+ }
+
+ // End the test if the test is done or an assert has occurred.
+ if (TestDone() || HasFatalFailure()) {
+ test_complete_->Set();
+ }
+
+ return true;
+ }
+
+ // Implements the callback functionality for the writer thread.
+ bool CbWriterImpl() {
+ SleepRandomTime(3, &writer_seed);
+
+ if (num_messages_written_ < messages_.size()) {
+ // Attempt to put the message in the queue.
+ Message m(messages_[num_messages_written_]);
+ if (queue_->Insert(&m))
+ num_messages_written_++;
+ }
+
+ // End the test early if a fatal failure (ASSERT_*) has occurred.
+ if (HasFatalFailure())
+ test_complete_->Set();
+
+ return true;
+ }
+
+ // Sleeps a random time.
+ static void SleepRandomTime(int max_sleep, unsigned int* seed) {
+ SleepMs(rand_r(seed) % (max_sleep + 1));
hlundin-webrtc 2015/10/13 06:37:57 Will rand_r work across platforms?
peah-webrtc 2015/10/13 11:56:12 Great find! I implemented a threadsafe random gene
+ }
+
+ // Start the threads used in the test.
+ void StartThreads() {
+ EXPECT_TRUE(reader_thread_->Start());
hlundin-webrtc 2015/10/13 06:37:57 ASSERT_TRUE. Makes little sense to continue if thr
peah-webrtc 2015/10/13 11:56:12 Done.
+ reader_thread_->SetPriority(kRealtimePriority);
+ EXPECT_TRUE(writer_thread_->Start());
+ writer_thread_->SetPriority(kRealtimePriority);
+ }
+
+ // Test parameters.
+ rtc::scoped_ptr<SwappedNonBlockingQueue<Message>> queue_;
+ rtc::CriticalSection crit_;
+ const rtc::scoped_ptr<EventWrapper> test_complete_;
+ rtc::scoped_ptr<ThreadWrapper> reader_thread_;
+ rtc::scoped_ptr<ThreadWrapper> writer_thread_;
+ unsigned int reader_seed = 42;
+ unsigned int writer_seed = 37;
+ std::vector<Message> messages_;
+ std::vector<int16_t> buffer_writer_int16_;
+ size_t num_messages_written_ = 0;
+ size_t num_messages_read_ GUARDED_BY(crit_) = 0;
+};
+
+// Implements the tests sample queue.
+class SwappedNonBlockingQueueSampleTest
+ : public ::testing::TestWithParam<
+ ::testing::tuple<size_t, size_t, size_t, DataType>> {
+ public:
+ SwappedNonBlockingQueueSampleTest()
+ : test_complete_(EventWrapper::Create()),
+ reader_thread_(
+ ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
+ writer_thread_(
+ ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
+
+ // Run the test with a timeout.
+ EventTypeWrapper RunTest() {
+ StartThreads();
+ return test_complete_->Wait(kTestTimeOutLimit);
+ }
+
+ virtual void SetUp() {
+ // Read parameters.
+ queue_size_ = static_cast<size_t>(testing::get<0>(GetParam()));
hlundin-webrtc 2015/10/13 06:37:57 If you parse these parameters in the constructor i
peah-webrtc 2015/10/13 11:56:12 Done.
+ max_frame_length_ = static_cast<size_t>(testing::get<1>(GetParam()));
+ data_length_ = static_cast<size_t>(testing::get<2>(GetParam()));
+ data_type_ = static_cast<DataType>(testing::get<3>(GetParam()));
+
+ // llocate read and write buffers.
hlundin-webrtc 2015/10/13 06:37:57 -> Allocate
peah-webrtc 2015/10/13 11:56:12 Done.
+ buffer_reader_flt_ = std::vector<float>(max_frame_length_, 0.0f);
+ buffer_writer_flt_ = std::vector<float>(max_frame_length_, 0.0f);
+ buffer_reader_int16_ = std::vector<int16_t>(max_frame_length_, 0);
+ buffer_writer_int16_ = std::vector<int16_t>(max_frame_length_, 0);
+
+ // Create queues.
+ sample_queue_flt_.reset(new SwappedNonBlockingQueue<std::vector<float>>(
+ queue_size_, buffer_reader_flt_));
+ sample_queue_int16_.reset(new SwappedNonBlockingQueue<std::vector<int16_t>>(
+ queue_size_, buffer_reader_int16_));
+
+ // Create and populate data vectors.
+ CreateTestData(data_length_);
+ }
+
+ virtual void TearDown() {
+ reader_thread_->Stop();
+ writer_thread_->Stop();
+ }
+
+ private:
+ const int kTestTimeOutLimit = 10 * 1000;
+
+ // Populates the data vectors with random values.
+ void CreateTestData(size_t data_length) {
+ samples_int16_.resize(data_length);
+ samples_float_.resize(data_length);
+ for (size_t k = 0; k < data_length; k++) {
+ samples_float_[k] =
+ (static_cast<float>((rand_r(&writer_seed) % (32768 + 32768 + 1)) -
+ 32768) /
+ 32768.0f);
+ samples_int16_[k] = ((rand_r(&writer_seed) % (32767 + 32768)) - 32768);
+ }
+ }
+
+ // Thread callback for the reader thread
hlundin-webrtc 2015/10/13 06:37:57 End with .
peah-webrtc 2015/10/13 11:56:12 Done.
+ static bool CbReaderThread(void* context) {
+ return reinterpret_cast<SwappedNonBlockingQueueSampleTest*>(context)
+ ->CbReaderImpl();
+ }
+
+ // Thread callback for the writer thread
hlundin-webrtc 2015/10/13 06:37:57 End with .
peah-webrtc 2015/10/13 11:56:12 Done.
+ static bool CbWriterThread(void* context) {
+ return reinterpret_cast<SwappedNonBlockingQueueSampleTest*>(context)
+ ->CbWriterImpl();
+ }
+
+ // Tests in a threadsafe manner whether all the samples have been
+ // written and read.
+ bool TestDone() { return (GetNumSamplesRead() == data_length_); }
+
+ // Returns in a threadsafe manner the number of frames read from the queue.
+ size_t GetNumFramesRead() {
+ rtc::CritScope cs(&crit_);
+ return num_frames_read_;
+ }
+
+ // Returns in a threadsafe manner the number of samples read from the queue.
+ size_t GetNumSamplesRead() {
+ rtc::CritScope cs(&crit_);
+ return num_samples_read_;
+ }
+
+ // Increases in a threadsafe manner the number of frames and samples
+ // read from the queue.
+ void IncreaseReadCounters(size_t num_samples_read) {
+ rtc::CritScope cs(&crit_);
+ num_frames_read_++;
+ num_samples_read_ += num_samples_read;
+ }
+
+ // Implements the callback functionality for the reader thread.
+ bool CbReaderImpl() {
+ SleepRandomTime(3, &reader_seed);
+
+ // Read the samples and verify bitexactness.
+ size_t num_samples_read = GetNumSamplesRead();
hlundin-webrtc 2015/10/13 06:37:57 const
peah-webrtc 2015/10/13 11:56:12 Done.
+ if ((data_type_ == DataType::Float) &&
+ (sample_queue_flt_->Remove(&buffer_reader_flt_))) {
+ for (size_t k = 0; k < buffer_reader_flt_.size(); k++)
+ EXPECT_EQ(buffer_reader_flt_[k], samples_float_[num_samples_read + k]);
+
+ IncreaseReadCounters(buffer_reader_flt_.size());
+ } else if ((data_type_ == DataType::Int16) &&
+ (sample_queue_int16_->Remove(&buffer_reader_int16_))) {
+ for (size_t k = 0; k < buffer_reader_int16_.size(); k++)
+ EXPECT_EQ(buffer_reader_int16_[k],
+ samples_int16_[num_samples_read + k]);
+
+ IncreaseReadCounters(buffer_reader_int16_.size());
+ }
+
+ // End the test if the test is done or an assert has occurred.
+ if (TestDone() || HasFatalFailure()) {
+ test_complete_->Set();
+ }
+
+ return true;
+ }
+
+ // Implements the callback functionality for the writer thread.
+ bool CbWriterImpl() {
+ SleepRandomTime(3, &writer_seed);
+
+ // Choose number of samples to write.
+ const size_t num_samples_to_write =
+ std::min(rand_r(&writer_seed) % max_frame_length_,
+ data_length_ - num_samples_written_);
+
+ // Write the data.
+ bool data_written = false;
+ if (num_samples_to_write > 0) {
+ if (data_type_ == DataType::Float) {
+ if (buffer_writer_flt_.size() != num_samples_to_write)
+ buffer_writer_flt_.resize(num_samples_to_write);
+ memcpy(&buffer_writer_flt_[0], &samples_float_[num_samples_written_],
+ num_samples_to_write * sizeof(samples_float_[0]));
+
+ data_written = sample_queue_flt_->Insert(&buffer_writer_flt_);
+ } else {
+ if (buffer_writer_int16_.size() != num_samples_to_write)
+ buffer_writer_int16_.resize(num_samples_to_write);
+
+ memcpy(&buffer_writer_int16_[0], &samples_int16_[num_samples_written_],
+ num_samples_to_write * sizeof(samples_int16_[0]));
+
+ data_written = sample_queue_int16_->Insert(&buffer_writer_int16_);
+ }
+ }
+
+ // Update the number of samples left to write
+ if (data_written) {
+ num_samples_written_ += num_samples_to_write;
+ num_frames_written_++;
+ }
+
+ // End the test early if a fatal failure (ASSERT_*) has occurred.
+ if (HasFatalFailure())
+ test_complete_->Set();
+
+ return true;
+ }
+
+ // Sleeps a random time.
+ static void SleepRandomTime(int max_sleep, unsigned int* seed) {
+ SleepMs(rand_r(seed) % (max_sleep + 1));
+ }
+
+ // Start the threads used in the test.
+ void StartThreads() {
+ EXPECT_TRUE(reader_thread_->Start());
hlundin-webrtc 2015/10/13 06:37:57 Again, ASSERT_*?
peah-webrtc 2015/10/13 11:56:12 Done.
+ reader_thread_->SetPriority(kRealtimePriority);
+ EXPECT_TRUE(writer_thread_->Start());
+ writer_thread_->SetPriority(kRealtimePriority);
+ }
+
+ // Test parameters.
+ size_t queue_size_;
+ size_t max_frame_length_;
+ size_t data_length_;
+ DataType data_type_;
+
+ rtc::scoped_ptr<SwappedNonBlockingQueue<std::vector<float>>>
+ sample_queue_flt_;
+ rtc::scoped_ptr<SwappedNonBlockingQueue<std::vector<int16_t>>>
+ sample_queue_int16_;
+ rtc::CriticalSection crit_;
+ const rtc::scoped_ptr<EventWrapper> test_complete_;
+ rtc::scoped_ptr<ThreadWrapper> reader_thread_;
+ rtc::scoped_ptr<ThreadWrapper> writer_thread_;
+ std::vector<int16_t> samples_int16_;
+ std::vector<float> samples_float_;
+ size_t num_samples_read_ GUARDED_BY(crit_) = 0;
+ size_t num_samples_written_ = 0;
+ unsigned int reader_seed = 42;
hlundin-webrtc 2015/10/13 06:37:57 Trailing underscore, please.
peah-webrtc 2015/10/13 11:56:12 Done.
+ unsigned int writer_seed = 37;
hlundin-webrtc 2015/10/13 06:37:58 Trailing underscore, please.
peah-webrtc 2015/10/13 11:56:12 Done.
+ std::vector<float> buffer_reader_flt_;
+ std::vector<float> buffer_writer_flt_;
+ std::vector<int16_t> buffer_reader_int16_;
+ std::vector<int16_t> buffer_writer_int16_;
+ size_t num_frames_written_ = 0;
+ size_t num_frames_read_ GUARDED_BY(crit_) = 0;
+};
+
+} // anonymous namespace
+
+// Test parameters for the message queue tests.
hlundin-webrtc 2015/10/13 06:37:57 Let the consts live in the anonymous namespace too
peah-webrtc 2015/10/13 11:56:12 Done.
+const size_t kMessageQueueSizes[] = {2, 7, 20};
+const size_t kMessageQueueDataLengths[] = {100};
+
+// Test parameters for the sample queue tests.
+const size_t kSampleQueueSizes[] = {2, 7, 100};
+const size_t kMaxFrameLengths[] = {77, 160};
+const size_t kSampleQueueDataLengths[] = {1000, 10000};
+const DataType kDataTypes[] = {DataType::Float, DataType::Int16};
+
+TEST_P(SwappedNonBlockingQueueSampleTest, BitExactness) {
+ // Run test and verify that it did not time out.
+ EXPECT_EQ(kEventSignaled, RunTest());
+}
+
+TEST_P(SwappedNonBlockingQueueMessageTest, BitExactness) {
+ // Run test and verify that it did not time out.
+ EXPECT_EQ(kEventSignaled, RunTest());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ SwappedNonBlockingQueueMessageTestAllCombinations,
+ SwappedNonBlockingQueueMessageTest,
+ testing::Combine(::testing::ValuesIn(kMessageQueueSizes),
+ ::testing::ValuesIn(kMessageQueueDataLengths)));
+
+INSTANTIATE_TEST_CASE_P(
+ SwappedNonBlockingQueueSampleTestAllCombinations,
+ SwappedNonBlockingQueueSampleTest,
+ testing::Combine(::testing::ValuesIn(kSampleQueueSizes),
+ ::testing::ValuesIn(kMaxFrameLengths),
+ ::testing::ValuesIn(kSampleQueueDataLengths),
+ ::testing::ValuesIn(kDataTypes)));
+
+} // namespace webrtc
kwiberg-webrtc 2015/10/10 10:16:57 It might just be me, but I think testing of the qu
peah-webrtc 2015/10/13 11:56:12 I agree, and I add some tests for the corner cases

Powered by Google App Engine
This is Rietveld 408576698