OLD | NEW |
---|---|
(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
| |
OLD | NEW |