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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * 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.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <algorithm>
12 #include <tuple>
13 #include <vector>
14
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "webrtc/modules/audio_processing/swapped_nonblocking_queue.h"
17 #include "webrtc/modules/interface/module_common_types.h"
18 #include "webrtc/system_wrappers/interface/event_wrapper.h"
19 #include "webrtc/system_wrappers/interface/sleep.h"
20 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
21
22 namespace webrtc {
23
24 namespace {
25
26 // Sample data type enum.
27 enum class DataType { Float, Int16 };
28
29 // The type for a message.
30 class Message {
31 public:
32 Message() {
33 id_ = -1;
34 info_ = -1;
35 }
36
37 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.
38 id_ = m.id_;
39 info_ = m.info_;
40 }
41
42 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.
43 id_ = id;
44 info_ = info;
45 }
46
47 bool Compare(const Message& m) {
48 return ((id_ == m.id_) && (info_ == m.info_));
49 }
50
51 void swap(Message& m) {
52 int tmp = id_;
53 id_ = m.id_;
54 m.id_ = tmp;
55
56 tmp = info_;
57 info_ = m.info_;
58 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.
59 }
60
61 private:
62 int id_;
63 int info_;
64 };
65
66 // Implements the tests for the sample queue.
67 class SwappedNonBlockingQueueMessageTest
68 : public ::testing::TestWithParam<::testing::tuple<size_t, size_t>> {
69 public:
70 SwappedNonBlockingQueueMessageTest()
71 : test_complete_(EventWrapper::Create()),
72 reader_thread_(
73 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
74 writer_thread_(
75 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
76
77 // Run the test with a timeout.
78 EventTypeWrapper RunTest() {
79 StartThreads();
80 return test_complete_->Wait(kTestTimeOutLimit);
81 }
82
83 virtual void SetUp() {
84 // Read test parameter
85 size_t queue_size = static_cast<size_t>(testing::get<0>(GetParam()));
86 size_t messages_size = static_cast<size_t>(testing::get<1>(GetParam()));
87
88 // Create queues.
89 queue_.reset(new SwappedNonBlockingQueue<Message>(queue_size));
90
91 // Create and populate message vector.
92 messages_ = std::vector<Message>();
93 CreateTestData(messages_size);
94 }
95
96 virtual void TearDown() {
97 reader_thread_->Stop();
98 writer_thread_->Stop();
99 }
100
101 private:
102 const int kTestTimeOutLimit = 10 * 1000;
103
104 // Populates the data vectors with random values.
105 void CreateTestData(int messages_size) {
106 messages_.resize(messages_size);
107 for (size_t k = 0; k < messages_.size(); k++)
108 messages_[k] =
109 Message(rand_r(&writer_seed) % 10000, rand_r(&writer_seed) % 10000);
110 }
111
112 // 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.
113 static bool CbReaderThread(void* context) {
114 return reinterpret_cast<SwappedNonBlockingQueueMessageTest*>(context)
115 ->CbReaderImpl();
116 }
117
118 // 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.
119 static bool CbWriterThread(void* context) {
120 return reinterpret_cast<SwappedNonBlockingQueueMessageTest*>(context)
121 ->CbWriterImpl();
122 }
123
124 // Tests in a threadsafe manner whether all the samples have been
125 // written and read.
126 bool TestDone() { return (GetNumMessagesRead() == messages_.size()); }
127
128 // Returns in a threadsafe manner the number of frames read from the queue.
129 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.
130 rtc::CritScope cs(&crit_);
131 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
132 }
133
134 // Increases in a threadsafe manner the number of messages
135 // read from the queue.
136 void IncreaseMessageReadCounter() {
137 rtc::CritScope cs(&crit_);
138 num_messages_read_++;
139 }
140
141 // Implements the callback functionality for the reader thread.
142 bool CbReaderImpl() {
143 SleepRandomTime(3, &reader_seed);
144
145 // Read the message and verify bitexactness.
146 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.
147 Message m;
148 if (queue_->Remove(&m)) {
149 EXPECT_TRUE(m.Compare(messages_[num_messages_read]));
150 IncreaseMessageReadCounter();
151 }
152
153 // End the test if the test is done or an assert has occurred.
154 if (TestDone() || HasFatalFailure()) {
155 test_complete_->Set();
156 }
157
158 return true;
159 }
160
161 // Implements the callback functionality for the writer thread.
162 bool CbWriterImpl() {
163 SleepRandomTime(3, &writer_seed);
164
165 if (num_messages_written_ < messages_.size()) {
166 // Attempt to put the message in the queue.
167 Message m(messages_[num_messages_written_]);
168 if (queue_->Insert(&m))
169 num_messages_written_++;
170 }
171
172 // End the test early if a fatal failure (ASSERT_*) has occurred.
173 if (HasFatalFailure())
174 test_complete_->Set();
175
176 return true;
177 }
178
179 // Sleeps a random time.
180 static void SleepRandomTime(int max_sleep, unsigned int* seed) {
181 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
182 }
183
184 // Start the threads used in the test.
185 void StartThreads() {
186 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.
187 reader_thread_->SetPriority(kRealtimePriority);
188 EXPECT_TRUE(writer_thread_->Start());
189 writer_thread_->SetPriority(kRealtimePriority);
190 }
191
192 // Test parameters.
193 rtc::scoped_ptr<SwappedNonBlockingQueue<Message>> queue_;
194 rtc::CriticalSection crit_;
195 const rtc::scoped_ptr<EventWrapper> test_complete_;
196 rtc::scoped_ptr<ThreadWrapper> reader_thread_;
197 rtc::scoped_ptr<ThreadWrapper> writer_thread_;
198 unsigned int reader_seed = 42;
199 unsigned int writer_seed = 37;
200 std::vector<Message> messages_;
201 std::vector<int16_t> buffer_writer_int16_;
202 size_t num_messages_written_ = 0;
203 size_t num_messages_read_ GUARDED_BY(crit_) = 0;
204 };
205
206 // Implements the tests sample queue.
207 class SwappedNonBlockingQueueSampleTest
208 : public ::testing::TestWithParam<
209 ::testing::tuple<size_t, size_t, size_t, DataType>> {
210 public:
211 SwappedNonBlockingQueueSampleTest()
212 : test_complete_(EventWrapper::Create()),
213 reader_thread_(
214 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
215 writer_thread_(
216 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
217
218 // Run the test with a timeout.
219 EventTypeWrapper RunTest() {
220 StartThreads();
221 return test_complete_->Wait(kTestTimeOutLimit);
222 }
223
224 virtual void SetUp() {
225 // Read parameters.
226 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.
227 max_frame_length_ = static_cast<size_t>(testing::get<1>(GetParam()));
228 data_length_ = static_cast<size_t>(testing::get<2>(GetParam()));
229 data_type_ = static_cast<DataType>(testing::get<3>(GetParam()));
230
231 // llocate read and write buffers.
hlundin-webrtc 2015/10/13 06:37:57 -> Allocate
peah-webrtc 2015/10/13 11:56:12 Done.
232 buffer_reader_flt_ = std::vector<float>(max_frame_length_, 0.0f);
233 buffer_writer_flt_ = std::vector<float>(max_frame_length_, 0.0f);
234 buffer_reader_int16_ = std::vector<int16_t>(max_frame_length_, 0);
235 buffer_writer_int16_ = std::vector<int16_t>(max_frame_length_, 0);
236
237 // Create queues.
238 sample_queue_flt_.reset(new SwappedNonBlockingQueue<std::vector<float>>(
239 queue_size_, buffer_reader_flt_));
240 sample_queue_int16_.reset(new SwappedNonBlockingQueue<std::vector<int16_t>>(
241 queue_size_, buffer_reader_int16_));
242
243 // Create and populate data vectors.
244 CreateTestData(data_length_);
245 }
246
247 virtual void TearDown() {
248 reader_thread_->Stop();
249 writer_thread_->Stop();
250 }
251
252 private:
253 const int kTestTimeOutLimit = 10 * 1000;
254
255 // Populates the data vectors with random values.
256 void CreateTestData(size_t data_length) {
257 samples_int16_.resize(data_length);
258 samples_float_.resize(data_length);
259 for (size_t k = 0; k < data_length; k++) {
260 samples_float_[k] =
261 (static_cast<float>((rand_r(&writer_seed) % (32768 + 32768 + 1)) -
262 32768) /
263 32768.0f);
264 samples_int16_[k] = ((rand_r(&writer_seed) % (32767 + 32768)) - 32768);
265 }
266 }
267
268 // 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.
269 static bool CbReaderThread(void* context) {
270 return reinterpret_cast<SwappedNonBlockingQueueSampleTest*>(context)
271 ->CbReaderImpl();
272 }
273
274 // 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.
275 static bool CbWriterThread(void* context) {
276 return reinterpret_cast<SwappedNonBlockingQueueSampleTest*>(context)
277 ->CbWriterImpl();
278 }
279
280 // Tests in a threadsafe manner whether all the samples have been
281 // written and read.
282 bool TestDone() { return (GetNumSamplesRead() == data_length_); }
283
284 // Returns in a threadsafe manner the number of frames read from the queue.
285 size_t GetNumFramesRead() {
286 rtc::CritScope cs(&crit_);
287 return num_frames_read_;
288 }
289
290 // Returns in a threadsafe manner the number of samples read from the queue.
291 size_t GetNumSamplesRead() {
292 rtc::CritScope cs(&crit_);
293 return num_samples_read_;
294 }
295
296 // Increases in a threadsafe manner the number of frames and samples
297 // read from the queue.
298 void IncreaseReadCounters(size_t num_samples_read) {
299 rtc::CritScope cs(&crit_);
300 num_frames_read_++;
301 num_samples_read_ += num_samples_read;
302 }
303
304 // Implements the callback functionality for the reader thread.
305 bool CbReaderImpl() {
306 SleepRandomTime(3, &reader_seed);
307
308 // Read the samples and verify bitexactness.
309 size_t num_samples_read = GetNumSamplesRead();
hlundin-webrtc 2015/10/13 06:37:57 const
peah-webrtc 2015/10/13 11:56:12 Done.
310 if ((data_type_ == DataType::Float) &&
311 (sample_queue_flt_->Remove(&buffer_reader_flt_))) {
312 for (size_t k = 0; k < buffer_reader_flt_.size(); k++)
313 EXPECT_EQ(buffer_reader_flt_[k], samples_float_[num_samples_read + k]);
314
315 IncreaseReadCounters(buffer_reader_flt_.size());
316 } else if ((data_type_ == DataType::Int16) &&
317 (sample_queue_int16_->Remove(&buffer_reader_int16_))) {
318 for (size_t k = 0; k < buffer_reader_int16_.size(); k++)
319 EXPECT_EQ(buffer_reader_int16_[k],
320 samples_int16_[num_samples_read + k]);
321
322 IncreaseReadCounters(buffer_reader_int16_.size());
323 }
324
325 // End the test if the test is done or an assert has occurred.
326 if (TestDone() || HasFatalFailure()) {
327 test_complete_->Set();
328 }
329
330 return true;
331 }
332
333 // Implements the callback functionality for the writer thread.
334 bool CbWriterImpl() {
335 SleepRandomTime(3, &writer_seed);
336
337 // Choose number of samples to write.
338 const size_t num_samples_to_write =
339 std::min(rand_r(&writer_seed) % max_frame_length_,
340 data_length_ - num_samples_written_);
341
342 // Write the data.
343 bool data_written = false;
344 if (num_samples_to_write > 0) {
345 if (data_type_ == DataType::Float) {
346 if (buffer_writer_flt_.size() != num_samples_to_write)
347 buffer_writer_flt_.resize(num_samples_to_write);
348 memcpy(&buffer_writer_flt_[0], &samples_float_[num_samples_written_],
349 num_samples_to_write * sizeof(samples_float_[0]));
350
351 data_written = sample_queue_flt_->Insert(&buffer_writer_flt_);
352 } else {
353 if (buffer_writer_int16_.size() != num_samples_to_write)
354 buffer_writer_int16_.resize(num_samples_to_write);
355
356 memcpy(&buffer_writer_int16_[0], &samples_int16_[num_samples_written_],
357 num_samples_to_write * sizeof(samples_int16_[0]));
358
359 data_written = sample_queue_int16_->Insert(&buffer_writer_int16_);
360 }
361 }
362
363 // Update the number of samples left to write
364 if (data_written) {
365 num_samples_written_ += num_samples_to_write;
366 num_frames_written_++;
367 }
368
369 // End the test early if a fatal failure (ASSERT_*) has occurred.
370 if (HasFatalFailure())
371 test_complete_->Set();
372
373 return true;
374 }
375
376 // Sleeps a random time.
377 static void SleepRandomTime(int max_sleep, unsigned int* seed) {
378 SleepMs(rand_r(seed) % (max_sleep + 1));
379 }
380
381 // Start the threads used in the test.
382 void StartThreads() {
383 EXPECT_TRUE(reader_thread_->Start());
hlundin-webrtc 2015/10/13 06:37:57 Again, ASSERT_*?
peah-webrtc 2015/10/13 11:56:12 Done.
384 reader_thread_->SetPriority(kRealtimePriority);
385 EXPECT_TRUE(writer_thread_->Start());
386 writer_thread_->SetPriority(kRealtimePriority);
387 }
388
389 // Test parameters.
390 size_t queue_size_;
391 size_t max_frame_length_;
392 size_t data_length_;
393 DataType data_type_;
394
395 rtc::scoped_ptr<SwappedNonBlockingQueue<std::vector<float>>>
396 sample_queue_flt_;
397 rtc::scoped_ptr<SwappedNonBlockingQueue<std::vector<int16_t>>>
398 sample_queue_int16_;
399 rtc::CriticalSection crit_;
400 const rtc::scoped_ptr<EventWrapper> test_complete_;
401 rtc::scoped_ptr<ThreadWrapper> reader_thread_;
402 rtc::scoped_ptr<ThreadWrapper> writer_thread_;
403 std::vector<int16_t> samples_int16_;
404 std::vector<float> samples_float_;
405 size_t num_samples_read_ GUARDED_BY(crit_) = 0;
406 size_t num_samples_written_ = 0;
407 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.
408 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.
409 std::vector<float> buffer_reader_flt_;
410 std::vector<float> buffer_writer_flt_;
411 std::vector<int16_t> buffer_reader_int16_;
412 std::vector<int16_t> buffer_writer_int16_;
413 size_t num_frames_written_ = 0;
414 size_t num_frames_read_ GUARDED_BY(crit_) = 0;
415 };
416
417 } // anonymous namespace
418
419 // 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.
420 const size_t kMessageQueueSizes[] = {2, 7, 20};
421 const size_t kMessageQueueDataLengths[] = {100};
422
423 // Test parameters for the sample queue tests.
424 const size_t kSampleQueueSizes[] = {2, 7, 100};
425 const size_t kMaxFrameLengths[] = {77, 160};
426 const size_t kSampleQueueDataLengths[] = {1000, 10000};
427 const DataType kDataTypes[] = {DataType::Float, DataType::Int16};
428
429 TEST_P(SwappedNonBlockingQueueSampleTest, BitExactness) {
430 // Run test and verify that it did not time out.
431 EXPECT_EQ(kEventSignaled, RunTest());
432 }
433
434 TEST_P(SwappedNonBlockingQueueMessageTest, BitExactness) {
435 // Run test and verify that it did not time out.
436 EXPECT_EQ(kEventSignaled, RunTest());
437 }
438
439 INSTANTIATE_TEST_CASE_P(
440 SwappedNonBlockingQueueMessageTestAllCombinations,
441 SwappedNonBlockingQueueMessageTest,
442 testing::Combine(::testing::ValuesIn(kMessageQueueSizes),
443 ::testing::ValuesIn(kMessageQueueDataLengths)));
444
445 INSTANTIATE_TEST_CASE_P(
446 SwappedNonBlockingQueueSampleTestAllCombinations,
447 SwappedNonBlockingQueueSampleTest,
448 testing::Combine(::testing::ValuesIn(kSampleQueueSizes),
449 ::testing::ValuesIn(kMaxFrameLengths),
450 ::testing::ValuesIn(kSampleQueueDataLengths),
451 ::testing::ValuesIn(kDataTypes)));
452
453 } // 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698