1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 #include "common/libs/utils/simulated_buffer.h"
17 #include <gtest/gtest.h>
18
19 using cvd::time::MonotonicTimePoint;
20 using cvd::time::MonotonicTimePointFactory;
21 using cvd::time::Seconds;
22 using cvd::time::Milliseconds;
23 using cvd::time::Nanoseconds;
24 using cvd::time::kNanosecondsPerSecond;
25
26 class MockTimepointFactory : public MonotonicTimePointFactory {
27 public:
FetchCurrentTime(MonotonicTimePoint * dest) const28 virtual void FetchCurrentTime(MonotonicTimePoint* dest) const override {
29 *dest = system_time_;
30 }
31
SetTime(const MonotonicTimePoint & in)32 void SetTime(const MonotonicTimePoint& in) {
33 system_time_ = in;
34 }
35
36 protected:
37 MonotonicTimePoint system_time_;
38 };
39
40 template <typename T> class MockSimulatedBuffer : public T {
41 public:
MockSimulatedBuffer(int64_t sample_rate,int64_t capacity,MockTimepointFactory * factory)42 MockSimulatedBuffer(
43 int64_t sample_rate,
44 int64_t capacity,
45 MockTimepointFactory* factory) :
46 T(sample_rate, capacity, factory),
47 factory_(factory) { }
48
FetchCurrentTime(MonotonicTimePoint * dest) const49 void FetchCurrentTime(MonotonicTimePoint* dest) const {
50 return factory_->FetchCurrentTime(dest);
51 }
52
SleepUntilTime(const MonotonicTimePoint & tick)53 void SleepUntilTime(const MonotonicTimePoint& tick) {
54 factory_->SetTime(tick);
55 }
56
57 protected:
58 // Save a redundant pointer to avoid downcasting
59 MockTimepointFactory* factory_;
60 };
61
62 static const int64_t kItemRate = 48000;
63 static const int64_t kBufferCapacity = 4800;
64
65 class SimulatedBufferTest : public ::testing::Test {
66 public:
67 MockTimepointFactory clock;
68 MockSimulatedBuffer<SimulatedBufferBase> buffer;
69
SimulatedBufferTest()70 SimulatedBufferTest() : buffer(kItemRate, kBufferCapacity, &clock) { }
71 };
72
TEST_F(SimulatedBufferTest,TimeMocking)73 TEST_F(SimulatedBufferTest, TimeMocking) {
74 // Ensure that the mocked clock starts at the epoch.
75 MonotonicTimePoint epoch_time;
76 MonotonicTimePoint actual_time;
77 buffer.FetchCurrentTime(&actual_time);
78 EXPECT_EQ(epoch_time, actual_time);
79
80 // Ensure that sleeping works
81 MonotonicTimePoint test_time = actual_time + Seconds(10);
82 buffer.SleepUntilTime(test_time);
83 buffer.FetchCurrentTime(&actual_time);
84 EXPECT_EQ(test_time, actual_time);
85
86 // Try one more sleep to make sure that time moves forward
87 test_time += Seconds(5);
88 buffer.SleepUntilTime(test_time);
89 buffer.FetchCurrentTime(&actual_time);
90 EXPECT_EQ(test_time, actual_time);
91 }
92
TEST_F(SimulatedBufferTest,ItemScaling)93 TEST_F(SimulatedBufferTest, ItemScaling) {
94 // Make certain that we start at item 0
95 EXPECT_EQ(0, buffer.GetCurrentItemNum());
96
97 // Make certain that the expected number of items appear in 1 second
98 MonotonicTimePoint actual_time;
99 buffer.FetchCurrentTime(&actual_time);
100 MonotonicTimePoint test_time = actual_time + Seconds(1);
101 buffer.SleepUntilTime(test_time);
102 EXPECT_EQ(kItemRate, buffer.GetCurrentItemNum());
103
104 // Sleep an additional 10 seconds to make certain that the item numbers
105 // increment
106 test_time += Seconds(10);
107 buffer.SleepUntilTime(test_time);
108 EXPECT_EQ(11 * kItemRate, buffer.GetCurrentItemNum());
109
110 // Make certain that partial seconds work
111 test_time += Milliseconds(1500);
112 buffer.SleepUntilTime(test_time);
113 EXPECT_EQ(12.5 * kItemRate, buffer.GetCurrentItemNum());
114
115 // Make certain that we don't get new items when paused
116 buffer.SetPaused(true);
117 test_time += Seconds(10);
118 buffer.SleepUntilTime(test_time);
119 EXPECT_EQ(12.5 * kItemRate, buffer.GetCurrentItemNum());
120
121 // Make certain that we start getting items when pausing stops
122 buffer.SetPaused(false);
123 test_time += Milliseconds(500);
124 buffer.SleepUntilTime(test_time);
125 EXPECT_EQ(13 * kItemRate, buffer.GetCurrentItemNum());
126 }
127
TEST_F(SimulatedBufferTest,ItemSleeping)128 TEST_F(SimulatedBufferTest, ItemSleeping) {
129 // See if sleeping on an time causes the right amount of time to pass
130 EXPECT_EQ(0, buffer.GetCurrentItemNum());
131 MonotonicTimePoint base_time;
132 buffer.FetchCurrentTime(&base_time);
133
134 // Wait for 1500ms worth of samples
135 buffer.SleepUntilItem(kItemRate * 1500 / 1000);
136 EXPECT_EQ(kItemRate * 1500 / 1000, buffer.GetCurrentItemNum());
137 MonotonicTimePoint actual_time;
138 buffer.FetchCurrentTime(&actual_time);
139 EXPECT_EQ(1500, Milliseconds(actual_time - base_time).count());
140
141 // Now wait again for more samples
142 buffer.SleepUntilItem(kItemRate * 2500 / 1000);
143 EXPECT_EQ(kItemRate * 2500 / 1000, buffer.GetCurrentItemNum());
144 buffer.FetchCurrentTime(&actual_time);
145 EXPECT_EQ(2500, Milliseconds(actual_time - base_time).count());
146 }
147
148 class OutputBufferTest : public ::testing::Test {
149 public:
150 MockTimepointFactory clock;
151 MockSimulatedBuffer<SimulatedOutputBuffer> buffer;
152
OutputBufferTest()153 OutputBufferTest() : buffer(kItemRate, kBufferCapacity, &clock) { }
154 };
155
TEST_F(OutputBufferTest,NonBlockingQueueing)156 TEST_F(OutputBufferTest, NonBlockingQueueing) {
157 int64_t half_buffer = kBufferCapacity / 2;
158 EXPECT_EQ(0, buffer.GetCurrentItemNum());
159
160 // Filling half of the buffer should not block
161 MonotonicTimePoint test_time;
162 buffer.FetchCurrentTime(&test_time);
163 EXPECT_EQ(half_buffer, buffer.AddToOutputBuffer(half_buffer, false));
164 MonotonicTimePoint actual_time;
165 buffer.FetchCurrentTime(&actual_time);
166 EXPECT_EQ(test_time, actual_time);
167 EXPECT_EQ(half_buffer, buffer.GetOutputBufferSize());
168
169 // Filling all but one entry of the buffer should not block
170 EXPECT_EQ(half_buffer - 1,
171 buffer.AddToOutputBuffer(half_buffer - 1, false));
172 buffer.FetchCurrentTime(&actual_time);
173 EXPECT_EQ(test_time, actual_time);
174 EXPECT_EQ(kBufferCapacity - 1, buffer.GetOutputBufferSize());
175
176 // Filling the entire buffer should not block
177 EXPECT_EQ(1, buffer.AddToOutputBuffer(half_buffer, false));
178 buffer.FetchCurrentTime(&actual_time);
179 EXPECT_EQ(actual_time, test_time);
180 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
181
182 // The buffer should reject additional data but not block
183 EXPECT_EQ(0, buffer.AddToOutputBuffer(half_buffer, false));
184 buffer.FetchCurrentTime(&actual_time);
185 EXPECT_EQ(test_time, actual_time);
186 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
187
188 // One quarter of the buffer should drain in the expected time
189 Nanoseconds quarter_drain_time(
190 kBufferCapacity / 4 * kNanosecondsPerSecond / kItemRate);
191 test_time += quarter_drain_time;
192 buffer.SleepUntilTime(test_time);
193 buffer.FetchCurrentTime(&actual_time);
194 EXPECT_EQ(actual_time, test_time);
195 EXPECT_EQ(kBufferCapacity * 3 / 4, buffer.GetOutputBufferSize());
196
197 // The buffer should now accept new data without blocking
198 EXPECT_EQ(kBufferCapacity / 4,
199 buffer.AddToOutputBuffer(half_buffer, false));
200 buffer.FetchCurrentTime(&actual_time);
201 EXPECT_EQ(test_time, actual_time);
202 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
203
204 // Now that the buffer is full it should reject additional data but
205 // not block
206 EXPECT_EQ(0, buffer.AddToOutputBuffer(half_buffer, false));
207 buffer.FetchCurrentTime(&actual_time);
208 EXPECT_EQ(test_time, actual_time);
209 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
210
211 // Wait for 3/4 of the buffer to drain
212 test_time += Nanoseconds(3 * quarter_drain_time.count());
213 buffer.SleepUntilTime(test_time);
214 buffer.FetchCurrentTime(&actual_time);
215 EXPECT_EQ(test_time, actual_time);
216 EXPECT_EQ(kBufferCapacity / 4, buffer.GetOutputBufferSize());
217
218 // The entire buffer should drain on schedule
219 test_time += Nanoseconds(quarter_drain_time.count() - 1);
220 buffer.SleepUntilTime(test_time);
221 buffer.FetchCurrentTime(&actual_time);
222 EXPECT_EQ(test_time, actual_time);
223 EXPECT_EQ(1, buffer.GetOutputBufferSize());
224 test_time += Nanoseconds(1);
225 buffer.SleepUntilTime(test_time);
226 buffer.FetchCurrentTime(&actual_time);
227 EXPECT_EQ(test_time, actual_time);
228 EXPECT_EQ(0, buffer.GetOutputBufferSize());
229
230 // It should be possible to fill the buffer in a single shot
231 EXPECT_EQ(kBufferCapacity,
232 buffer.AddToOutputBuffer(kBufferCapacity, false));
233 buffer.FetchCurrentTime(&actual_time);
234 EXPECT_EQ(test_time, actual_time);
235 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
236
237 // The buffer shouldn't accept additional data but shouldn't block
238 EXPECT_EQ(0, buffer.AddToOutputBuffer(1, false));
239 buffer.FetchCurrentTime(&actual_time);
240 EXPECT_EQ(test_time, actual_time);
241 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
242
243 // The buffer should underflow sanely
244 test_time += Nanoseconds(6 * quarter_drain_time.count());
245 buffer.SleepUntilTime(test_time);
246 buffer.FetchCurrentTime(&actual_time);
247 EXPECT_EQ(test_time, actual_time);
248 EXPECT_EQ(0, buffer.GetOutputBufferSize());
249
250 // The underflow shouldn't increase the buffer's capacity
251 EXPECT_EQ(kBufferCapacity,
252 buffer.AddToOutputBuffer(kBufferCapacity + 1, false));
253 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
254 buffer.FetchCurrentTime(&actual_time);
255 EXPECT_EQ(test_time, actual_time);
256 }
257
TEST_F(OutputBufferTest,BlockingQueueing)258 TEST_F(OutputBufferTest, BlockingQueueing) {
259 int64_t half_buffer = kBufferCapacity / 2;
260
261 // Check the initial setup
262 EXPECT_EQ(0, buffer.GetCurrentItemNum());
263 MonotonicTimePoint test_time;
264 buffer.FetchCurrentTime(&test_time);
265
266 // Filling half the buffer works without blocking
267 EXPECT_EQ(half_buffer, buffer.AddToOutputBuffer(half_buffer, true));
268 MonotonicTimePoint actual_time;
269 buffer.FetchCurrentTime(&actual_time);
270 EXPECT_EQ(test_time, actual_time);
271 EXPECT_EQ(half_buffer, buffer.GetOutputBufferSize());
272
273 // Filling all but one entry of the buffer also works without blocking
274 EXPECT_EQ(half_buffer - 1,
275 buffer.AddToOutputBuffer(half_buffer - 1, true));
276 buffer.FetchCurrentTime(&actual_time);
277 EXPECT_EQ(test_time, actual_time);
278 EXPECT_EQ(kBufferCapacity - 1, buffer.GetOutputBufferSize());
279
280 // Putting the last sample into the buffer doesn't block
281 EXPECT_EQ(1, buffer.AddToOutputBuffer(1, true));
282 buffer.FetchCurrentTime(&actual_time);
283 EXPECT_EQ(test_time, actual_time);
284 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
285
286 // Putting more data into the buffer causes blocking
287 EXPECT_EQ(half_buffer, buffer.AddToOutputBuffer(half_buffer, true));
288 Nanoseconds half_drain_time(
289 ((kBufferCapacity / 2) * kNanosecondsPerSecond + kItemRate - 1) /
290 kItemRate);
291 Nanoseconds quarter_drain_time(half_drain_time.count() / 2);
292 test_time += half_drain_time;
293 buffer.FetchCurrentTime(&actual_time);
294 EXPECT_EQ(test_time, actual_time);
295 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
296
297 // The buffer drains as expected
298 test_time += quarter_drain_time;
299 buffer.SleepUntilTime(test_time);
300 buffer.FetchCurrentTime(&actual_time);
301 EXPECT_EQ(test_time, actual_time);
302 EXPECT_EQ(kBufferCapacity * 3 / 4, buffer.GetOutputBufferSize());
303
304 // Overfilling the drained buffer also causes blocking
305 EXPECT_EQ(half_buffer, buffer.AddToOutputBuffer(half_buffer, true));
306 test_time += quarter_drain_time;
307 buffer.FetchCurrentTime(&actual_time);
308 EXPECT_EQ(test_time, actual_time);
309 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
310
311 // The buffer drains on schedule
312 test_time += Nanoseconds(half_drain_time.count() * 2 - 1);
313 buffer.SleepUntilTime(test_time);
314 buffer.FetchCurrentTime(&actual_time);
315 EXPECT_EQ(test_time, actual_time);
316 EXPECT_EQ(1, buffer.GetOutputBufferSize());
317 test_time += Nanoseconds(1);
318 buffer.SleepUntilTime(test_time);
319 buffer.FetchCurrentTime(&actual_time);
320 EXPECT_EQ(test_time, actual_time);
321 EXPECT_EQ(0, buffer.GetOutputBufferSize());
322
323 // It's possible to fill the entire output buffer in 1 shot without blocking
324 EXPECT_EQ(kBufferCapacity,
325 buffer.AddToOutputBuffer(kBufferCapacity, true));
326 buffer.FetchCurrentTime(&actual_time);
327 EXPECT_EQ(test_time, actual_time);
328 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
329
330 // Adding a single extra sample causes some blocking
331 EXPECT_EQ(1, buffer.AddToOutputBuffer(1, true));
332 buffer.FetchCurrentTime(&actual_time);
333 EXPECT_LT(test_time, actual_time);
334 EXPECT_EQ(kBufferCapacity, buffer.GetOutputBufferSize());
335 }
336
337 class InputBufferTest : public ::testing::Test {
338 public:
339 MockTimepointFactory clock;
340 MockSimulatedBuffer<SimulatedInputBuffer> buffer;
341
InputBufferTest()342 InputBufferTest() : buffer(kItemRate, kBufferCapacity, &clock) { }
343 };
344
TEST_F(InputBufferTest,NonBlockingInput)345 TEST_F(InputBufferTest, NonBlockingInput) {
346 Nanoseconds quarter_fill_time(kBufferCapacity / 4 * kNanosecondsPerSecond /
347 kItemRate);
348 // Verify that the buffer starts empty
349 EXPECT_EQ(0, buffer.GetCurrentItemNum());
350 MonotonicTimePoint actual_time;
351 buffer.FetchCurrentTime(&actual_time);
352 EXPECT_EQ(0, buffer.RemoveFromInputBuffer(kBufferCapacity, false));
353 EXPECT_EQ(0, buffer.GetLostInputItems());
354
355 // Wait for 1/4 of the buffer to fill
356 MonotonicTimePoint test_time = actual_time + quarter_fill_time;
357 buffer.SleepUntilTime(test_time);
358 buffer.FetchCurrentTime(&actual_time);
359 EXPECT_EQ(test_time, actual_time);
360 EXPECT_EQ(0, buffer.GetLostInputItems());
361
362 // Verify that we can read the samples in two groups
363 EXPECT_EQ(kBufferCapacity / 8,
364 buffer.RemoveFromInputBuffer(kBufferCapacity / 8, false));
365 EXPECT_EQ(kBufferCapacity / 8,
366 buffer.RemoveFromInputBuffer(kBufferCapacity, false));
367
368 // Verify that there are no samples left and that we did not block
369 EXPECT_EQ(0, buffer.RemoveFromInputBuffer(kBufferCapacity, false));
370 buffer.FetchCurrentTime(&actual_time);
371 EXPECT_EQ(test_time, actual_time);
372
373 // Verify that the buffer fills on schedule
374 test_time += Nanoseconds(4 * quarter_fill_time.count() - 1);
375 buffer.SleepUntilTime(test_time);
376 EXPECT_EQ(kBufferCapacity - 1,
377 buffer.RemoveFromInputBuffer(kBufferCapacity, false));
378 test_time += Nanoseconds(1);
379 buffer.SleepUntilTime(test_time);
380 EXPECT_EQ(1, buffer.RemoveFromInputBuffer(kBufferCapacity, false));
381 buffer.FetchCurrentTime(&actual_time);
382 EXPECT_EQ(test_time, actual_time);
383 EXPECT_EQ(0, buffer.GetLostInputItems());
384
385 // Verify that the buffer overflows as expected
386 test_time += Nanoseconds(5 * quarter_fill_time.count());
387 buffer.SleepUntilTime(test_time);
388 buffer.FetchCurrentTime(&actual_time);
389 EXPECT_EQ(test_time, actual_time);
390 EXPECT_EQ(kBufferCapacity / 4, buffer.GetLostInputItems());
391 EXPECT_EQ(0, buffer.GetLostInputItems());
392
393 EXPECT_EQ(kBufferCapacity,
394 buffer.RemoveFromInputBuffer(2 * kBufferCapacity, false));
395 EXPECT_EQ(0, buffer.RemoveFromInputBuffer(kBufferCapacity, false));
396 }
397
TEST_F(InputBufferTest,BlockingInput)398 TEST_F(InputBufferTest, BlockingInput) {
399 Nanoseconds quarter_fill_time(kBufferCapacity / 4 * kNanosecondsPerSecond /
400 kItemRate);
401 // Verify that the buffer starts empty
402 EXPECT_EQ(0, buffer.GetCurrentItemNum());
403 MonotonicTimePoint actual_time;
404 buffer.FetchCurrentTime(&actual_time);
405 EXPECT_EQ(0, buffer.GetLostInputItems());
406
407 // Wait for 1/4 of the buffer to fill
408 MonotonicTimePoint test_time = actual_time + quarter_fill_time;
409 EXPECT_EQ(kBufferCapacity / 4,
410 buffer.RemoveFromInputBuffer(kBufferCapacity / 4, true));
411 buffer.FetchCurrentTime(&actual_time);
412 EXPECT_EQ(test_time, actual_time);
413 EXPECT_EQ(0, buffer.GetLostInputItems());
414
415 // Verify that the buffer fills on schedule
416 test_time += Nanoseconds(4 * quarter_fill_time.count());
417 EXPECT_EQ(kBufferCapacity,
418 buffer.RemoveFromInputBuffer(kBufferCapacity, true));
419 buffer.FetchCurrentTime(&actual_time);
420 EXPECT_EQ(test_time, actual_time);
421 EXPECT_EQ(0, buffer.GetLostInputItems());
422
423 // Verify that the buffer overflows as expected
424 test_time += Nanoseconds(5 * quarter_fill_time.count());
425 buffer.SleepUntilTime(test_time);
426 buffer.FetchCurrentTime(&actual_time);
427 EXPECT_EQ(test_time, actual_time);
428 EXPECT_EQ(kBufferCapacity / 4, buffer.GetLostInputItems());
429 EXPECT_EQ(0, buffer.GetLostInputItems());
430 EXPECT_EQ(kBufferCapacity,
431 buffer.RemoveFromInputBuffer(kBufferCapacity, true));
432 buffer.FetchCurrentTime(&actual_time);
433 EXPECT_EQ(test_time, actual_time);
434
435 // Verify that reads bigger than the buffer work as expected
436 test_time += Nanoseconds(8 * quarter_fill_time.count());
437 EXPECT_EQ(kBufferCapacity * 2,
438 buffer.RemoveFromInputBuffer(kBufferCapacity * 2, true));
439 EXPECT_EQ(0, buffer.GetLostInputItems());
440 buffer.FetchCurrentTime(&actual_time);
441 EXPECT_EQ(test_time, actual_time);
442 }
443