• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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