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

Side by Side Diff: webrtc/common_audio/swap_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: Added changes in response to reviewer comments. Added further unit tests and reduce the size of theā€¦ 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) 2015 The WebRTC project authors. All Rights Reserved.
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 <map>
13 #include <tuple>
14 #include <vector>
15
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "webrtc/common_audio/swap_queue.h"
18 #include "webrtc/modules/interface/module_common_types.h"
19 #include "webrtc/system_wrappers/interface/event_wrapper.h"
20 #include "webrtc/system_wrappers/interface/sleep.h"
21 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
22
23 namespace webrtc {
24
25 namespace {
26
27 // Provides thread_safe random numbers.
28 class ThreadSafeRandomNumberGenerator {
kwiberg-webrtc 2015/10/13 13:54:24 It's not thread safe, it just avoids being terribl
peah-webrtc 2015/10/14 12:16:48 Fully true, I rewrote it using a functor instead.
29 public:
30 ThreadSafeRandomNumberGenerator() : ThreadSafeRandomNumberGenerator(10000) {}
31 explicit ThreadSafeRandomNumberGenerator(int size) {
32 srand(42);
33 random_numbers_.resize(size);
34 for (int k = 0; k < size; k++) {
35 random_numbers_[k] = rand();
the sun 2015/10/14 13:05:21 Note that it doesn't matter that we make rand() th
peah-webrtc 2015/10/15 07:34:59 You are fully correct! If ok with you, I'll keep t
the sun 2015/10/15 08:44:00 Not ok. It still has global mutable state, implici
peah-webrtc 2015/10/26 08:56:57 I definitely agree on the issues with non-determin
36 }
37 }
38
39 // Initializes a user of the random number generator and
40 // returns a user id to use when aquiring a random number.
41 int AddUser(int seed) {
42 int next_user_index = GetNextIserId();
43
44 user_indices_[next_user_index] = seed % random_numbers_.size();
45 return next_user_index;
46 }
47
48 // Returns a random number between 0 and RAND_MAX.
49 int Rand(int user_id) {
50 int index = user_indices_[user_id];
51 index = (index < (static_cast<int>(random_numbers_.size()) - 1) ? index + 1
52 : 0);
53 user_indices_[user_id] = index;
54 return random_numbers_[index];
55 }
kwiberg-webrtc 2015/10/13 13:54:24 Why do you need to support several isers? Couldn't
peah-webrtc 2015/10/14 12:16:48 Fully true, I rewrote it using a functor instead.
56
57 private:
58 int GetNextIserId() {
59 int max_user_id = -1;
60 for (auto it = user_indices_.begin(); it != user_indices_.end(); ++it) {
61 max_user_id = std::max(max_user_id, it->first);
62 }
63
64 return max_user_id + 1;
65 }
66
67 std::vector<int> random_numbers_;
68 std::map<int, int> user_indices_;
69 };
kwiberg-webrtc 2015/10/13 13:54:24 Wouldn't it be simpler to just protect rand() call
peah-webrtc 2015/10/14 12:16:48 Fully true! This is definitely over-engineered! I
the sun 2015/10/15 08:44:00 See above comment. You will still have non-determi
peah-webrtc 2015/10/26 08:56:57 Acknowledged.
70
71 // The type for a message.
72 class SwapQueueTestMessage {
73 public:
74 SwapQueueTestMessage() {
75 id_ = -1;
76 info_ = -1;
77 }
78
79 SwapQueueTestMessage(const SwapQueueTestMessage& m)
80 : id_(m.id_), info_(m.info_) {}
81
82 SwapQueueTestMessage(int id, int info) {
83 id_ = id;
84 info_ = info;
85 }
86
87 bool Compare(const SwapQueueTestMessage& m) {
88 return ((id_ == m.id_) && (info_ == m.info_));
89 }
90
91 void swap(SwapQueueTestMessage& m) {
92 std::swap(id_, m.id_);
93 std::swap(info_, m.info_);
94 }
95
96 private:
97 int id_;
98 int info_;
99 };
100
101 // Implements the tests for the sample queue.
102 class SwapQueueMessageTest
103 : public ::testing::TestWithParam<::testing::tuple<size_t, size_t>> {
104 public:
105 SwapQueueMessageTest()
106 : test_complete_(EventWrapper::Create()),
107 reader_thread_(
108 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
109 writer_thread_(
110 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
111
112 // Run the test with a timeout.
113 EventTypeWrapper RunTest() {
114 StartThreads();
115 return test_complete_->Wait(kTestTimeOutLimit);
116 }
117
118 virtual void SetUp() {
119 // Read test parameter
120 size_t queue_size = static_cast<size_t>(testing::get<0>(GetParam()));
121 size_t messages_size = static_cast<size_t>(testing::get<1>(GetParam()));
122
123 // Create queues.
124 queue_.reset(new SwapQueue<SwapQueueTestMessage>(queue_size));
125
126 // Create and populate message vector.
127 messages_ = std::vector<SwapQueueTestMessage>();
128 CreateTestData(messages_size);
129
130 // Setup the random number generator.
131 reader_rand_id_ = random_generator_.AddUser(42);
132 writer_rand_id_ = random_generator_.AddUser(37);
133 }
134
135 virtual void TearDown() {
136 reader_thread_->Stop();
137 writer_thread_->Stop();
138 }
139
140 private:
141 const int kTestTimeOutLimit = 10 * 1000;
142
143 // Populates the data vectors with random values.
144 void CreateTestData(int messages_size) {
145 messages_.resize(messages_size);
146 for (size_t k = 0; k < messages_.size(); k++)
147 messages_[k] =
148 SwapQueueTestMessage(random_generator_.Rand(writer_rand_id_) % 10000,
149 random_generator_.Rand(writer_rand_id_) % 10000);
150 }
151
152 // Thread callback for the reader thread.
153 static bool CbReaderThread(void* context) {
154 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbReaderImpl();
155 }
156
157 // Thread callback for the writer thread.
158 static bool CbWriterThread(void* context) {
159 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbWriterImpl();
160 }
161
162 // Tests in a threadsafe manner whether all the samples have been
163 // written and read.
164 bool TestDone() { return (GetNumMessagesRead() == messages_.size()); }
165
166 // Returns in a threadsafe manner the number of frames read from the queue.
167 size_t GetNumMessagesRead() const {
168 rtc::CritScope cs(&crit_);
169 return num_messages_read_;
170 }
171
172 // Increases in a threadsafe manner the number of messages
173 // read from the queue.
174 void IncreaseMessageReadCounter() {
175 rtc::CritScope cs(&crit_);
176 num_messages_read_++;
177 }
178
179 // Implements the callback functionality for the reader thread.
180 bool CbReaderImpl() {
181 SleepRandomTime(3, reader_rand_id_);
182
183 // Read the message and verify bitexactness.
184 SwapQueueTestMessage m;
185 if (queue_->Remove(&m)) {
186 EXPECT_TRUE(m.Compare(messages_[GetNumMessagesRead()]));
187 IncreaseMessageReadCounter();
188 }
189
190 // End the test if the test is done or an assert has occurred.
191 if (TestDone() || HasFatalFailure()) {
192 test_complete_->Set();
193 }
194
195 return true;
196 }
197
198 // Implements the callback functionality for the writer thread.
199 bool CbWriterImpl() {
200 SleepRandomTime(3, writer_rand_id_);
201
202 if (num_messages_written_ < messages_.size()) {
203 // Attempt to put the message in the queue.
204 SwapQueueTestMessage m(messages_[num_messages_written_]);
205 if (queue_->Insert(&m))
206 num_messages_written_++;
207 }
208
209 // End the test early if a fatal failure (ASSERT_*) has occurred.
210 if (HasFatalFailure())
211 test_complete_->Set();
212
213 return true;
214 }
215
216 // Sleeps a random time.
217 void SleepRandomTime(int max_sleep, int user_id) {
218 SleepMs(random_generator_.Rand(user_id) % (max_sleep + 1));
219 }
220
221 // Start the threads used in the test.
222 void StartThreads() {
223 ASSERT_TRUE(reader_thread_->Start());
224 reader_thread_->SetPriority(kRealtimePriority);
225 ASSERT_TRUE(writer_thread_->Start());
226 writer_thread_->SetPriority(kRealtimePriority);
227 }
228
229 // Test parameters.
230 rtc::scoped_ptr<SwapQueue<SwapQueueTestMessage>> queue_;
231 mutable rtc::CriticalSection crit_;
232 ThreadSafeRandomNumberGenerator random_generator_;
233 const rtc::scoped_ptr<EventWrapper> test_complete_;
234 rtc::scoped_ptr<ThreadWrapper> reader_thread_;
235 rtc::scoped_ptr<ThreadWrapper> writer_thread_;
236 int reader_rand_id_;
237 int writer_rand_id_;
238 std::vector<SwapQueueTestMessage> messages_;
239 size_t num_messages_written_ = 0;
240 size_t num_messages_read_ GUARDED_BY(crit_) = 0;
241 };
242
243 // Implements the tests sample queue.
244 class SwapQueueSampleTest : public ::testing::TestWithParam<
245 ::testing::tuple<size_t, size_t, size_t>> {
246 public:
247 SwapQueueSampleTest()
248 : queue_size_(static_cast<size_t>(testing::get<0>(GetParam()))),
249 max_frame_length_(static_cast<size_t>(testing::get<1>(GetParam()))),
250 data_length_(static_cast<size_t>(testing::get<2>(GetParam()))),
251 test_complete_(EventWrapper::Create()),
252 reader_thread_(
253 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")),
254 writer_thread_(
255 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {}
256
257 // Run the test with a timeout.
258 EventTypeWrapper RunTest() {
259 StartThreads();
260 return test_complete_->Wait(kTestTimeOutLimit);
261 }
262
263 virtual void SetUp() {
264 // Allocate read and write buffers.
265 buffer_reader_ = std::vector<int16_t>(max_frame_length_, 0);
266 buffer_writer_ = std::vector<int16_t>(max_frame_length_, 0);
267
268 // Create queue.
269 std::vector<std::vector<int16_t>> template_queue(queue_size_);
270 for (size_t k = 0; k < queue_size_; k++) {
271 template_queue.resize(buffer_reader_.size());
272 }
273 sample_queue_.reset(new SwapQueue<std::vector<int16_t>>(&template_queue));
274
275 // Create and populate data vectors.
276 CreateTestData(data_length_);
277
278 // Setup the random number generator.
279 reader_rand_id_ = random_generator_.AddUser(42);
280 writer_rand_id_ = random_generator_.AddUser(37);
281 }
282
283 virtual void TearDown() {
284 reader_thread_->Stop();
285 writer_thread_->Stop();
286 }
287
288 private:
289 const int kTestTimeOutLimit = 10 * 1000;
290
291 // Populates the data vectors with random values.
292 void CreateTestData(size_t data_length) {
293 samples_.resize(data_length);
294 for (size_t k = 0; k < data_length; k++) {
295 samples_[k] =
296 ((random_generator_.Rand(writer_rand_id_) % (32767 + 32768)) - 32768);
297 }
298 }
299
300 // Thread callback for the reader thread.
301 static bool CbReaderThread(void* context) {
302 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbReaderImpl();
303 }
304
305 // Thread callback for the writer thread.
306 static bool CbWriterThread(void* context) {
307 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbWriterImpl();
308 }
309
310 // Tests in a threadsafe manner whether all the samples have been
311 // written and read.
312 bool TestDone() { return (GetNumSamplesRead() == data_length_); }
313
314 // Returns in a threadsafe manner the number of frames read from the queue.
315 size_t GetNumFramesRead() {
316 rtc::CritScope cs(&crit_);
317 return num_frames_read_;
318 }
319
320 // Returns in a threadsafe manner the number of samples read from the queue.
321 size_t GetNumSamplesRead() {
322 rtc::CritScope cs(&crit_);
323 return num_samples_read_;
324 }
325
326 // Increases in a threadsafe manner the number of frames and samples
327 // read from the queue.
328 void IncreaseReadCounters(size_t num_samples_read) {
329 rtc::CritScope cs(&crit_);
330 num_frames_read_++;
331 num_samples_read_ += num_samples_read;
332 }
333
334 // Implements the callback functionality for the reader thread.
335 bool CbReaderImpl() {
336 SleepRandomTime(3, reader_rand_id_);
337
338 // Read the samples and verify bitexactness.
339 const size_t num_samples_read = GetNumSamplesRead();
340 if (sample_queue_->Remove(&buffer_reader_)) {
341 for (size_t k = 0; k < buffer_reader_.size(); k++)
342 EXPECT_EQ(buffer_reader_[k], samples_[num_samples_read + k]);
343
344 IncreaseReadCounters(buffer_reader_.size());
345 }
346
347 // End the test if the test is done or an assert has occurred.
348 if (TestDone() || HasFatalFailure()) {
349 test_complete_->Set();
350 }
351
352 return true;
353 }
354
355 // Implements the callback functionality for the writer thread.
356 bool CbWriterImpl() {
357 SleepRandomTime(3, writer_rand_id_);
358
359 // Choose number of samples to write.
360 const size_t num_samples_to_write =
361 std::min(random_generator_.Rand(writer_rand_id_) % max_frame_length_,
362 data_length_ - num_samples_written_);
363
364 // Write the data.
365 bool data_written = false;
366 if (num_samples_to_write > 0) {
367 if (buffer_writer_.size() != num_samples_to_write)
368 buffer_writer_.resize(num_samples_to_write);
369
370 memcpy(&buffer_writer_[0], &samples_[num_samples_written_],
371 num_samples_to_write * sizeof(samples_[0]));
372
373 data_written = sample_queue_->Insert(&buffer_writer_);
374 }
375
376 // Update the number of samples left to write
377 if (data_written) {
378 num_samples_written_ += num_samples_to_write;
379 num_frames_written_++;
380 }
381
382 // End the test early if a fatal failure (ASSERT_*) has occurred.
383 if (HasFatalFailure())
384 test_complete_->Set();
385
386 return true;
387 }
388
389 // Sleeps a random time.
390 void SleepRandomTime(int max_sleep, int user_id) {
391 SleepMs(random_generator_.Rand(user_id) % (max_sleep + 1));
392 }
393
394 // Start the threads used in the test.
395 void StartThreads() {
396 ASSERT_TRUE(reader_thread_->Start());
397 reader_thread_->SetPriority(kRealtimePriority);
398 ASSERT_TRUE(writer_thread_->Start());
399 writer_thread_->SetPriority(kRealtimePriority);
400 }
401
402 // Test parameters.
403 const size_t queue_size_;
404 const size_t max_frame_length_;
405 const size_t data_length_;
406
407 rtc::scoped_ptr<SwapQueue<std::vector<int16_t>>> sample_queue_;
408 rtc::CriticalSection crit_;
409 ThreadSafeRandomNumberGenerator random_generator_;
410 const rtc::scoped_ptr<EventWrapper> test_complete_;
411 rtc::scoped_ptr<ThreadWrapper> reader_thread_;
412 rtc::scoped_ptr<ThreadWrapper> writer_thread_;
413 std::vector<int16_t> samples_;
414 size_t num_samples_read_ GUARDED_BY(crit_) = 0;
415 size_t num_samples_written_ = 0;
416 int reader_rand_id_;
417 int writer_rand_id_;
418 std::vector<int16_t> buffer_reader_;
419 std::vector<int16_t> buffer_writer_;
420 size_t num_frames_written_ = 0;
421 size_t num_frames_read_ GUARDED_BY(crit_) = 0;
422 };
423
424 // Test parameters for the message queue tests.
425 const size_t kMessageQueueSizes[] = {2, 7, 20};
426 const size_t kMessageQueueDataLengths[] = {100};
427
428 // Test parameters for the sample queue tests.
429 const size_t kSampleQueueSizes[] = {7, 100};
430 const size_t kMaxFrameLengths[] = {77, 160};
431 const size_t kSampleQueueDataLengths[] = {200, 500};
432
433 } // anonymous namespace
434
435 TEST(SwapQueueTest, FullQueue) {
436 SwapQueue<int> queue(2);
437 int i = 0;
438 EXPECT_TRUE(queue.Insert(&i));
439 EXPECT_TRUE(queue.Insert(&i));
440 EXPECT_FALSE(queue.Insert(&i));
441 EXPECT_TRUE(queue.Remove(&i));
442 EXPECT_TRUE(queue.Insert(&i));
443 EXPECT_FALSE(queue.Insert(&i));
444 }
445
446 TEST(SwapQueueTest, EmptyQueue) {
447 SwapQueue<int> queue(2);
448 int i = 0;
449 EXPECT_FALSE(queue.Remove(&i));
450 EXPECT_TRUE(queue.Insert(&i));
451 EXPECT_TRUE(queue.Remove(&i));
452 EXPECT_FALSE(queue.Remove(&i));
453 }
454
455 TEST(SwapQueueTest, InitializeTest) {
456 const size_t kQueueSize = 3;
457 std::vector<std::vector<int>> v(2);
458 v[0].resize(kQueueSize);
459 v[1].resize(kQueueSize);
460 SwapQueue<std::vector<int>> queue(&v);
461 std::vector<int> i(kQueueSize, 0);
462
463 EXPECT_TRUE(queue.Insert(&i));
464 EXPECT_EQ(i.size(), kQueueSize);
465 EXPECT_TRUE(queue.Insert(&i));
466 EXPECT_EQ(i.size(), kQueueSize);
467 EXPECT_TRUE(queue.Remove(&i));
468 EXPECT_EQ(i.size(), kQueueSize);
469 EXPECT_TRUE(queue.Remove(&i));
470 EXPECT_EQ(i.size(), kQueueSize);
471 }
472
473 TEST_P(SwapQueueSampleTest, BitExactness) {
474 // Run test and verify that it did not time out.
475 EXPECT_EQ(kEventSignaled, RunTest());
476 }
477
478 TEST_P(SwapQueueMessageTest, BitExactness) {
479 // Run test and verify that it did not time out.
480 EXPECT_EQ(kEventSignaled, RunTest());
481 }
482
483 INSTANTIATE_TEST_CASE_P(
484 SwapQueueMessageTestAllCombinations,
485 SwapQueueMessageTest,
486 testing::Combine(::testing::ValuesIn(kMessageQueueSizes),
487 ::testing::ValuesIn(kMessageQueueDataLengths)));
488
489 INSTANTIATE_TEST_CASE_P(
490 SwapQueueSampleTestAllCombinations,
491 SwapQueueSampleTest,
492 testing::Combine(::testing::ValuesIn(kSampleQueueSizes),
493 ::testing::ValuesIn(kMaxFrameLengths),
494 ::testing::ValuesIn(kSampleQueueDataLengths)));
495
496 } // namespace webrtc
OLDNEW
« webrtc/common_audio/swap_queue.h ('K') | « webrtc/common_audio/swap_queue.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698