1 /*
2  * Copyright (C) 2018 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 
17 #include <chrono>
18 #include <numeric>
19 
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include "ringbuffer.h"
23 using namespace testing;
24 using namespace std::chrono_literals;
25 
26 template <typename Rep, typename Per>
toNsecs(std::chrono::duration<Rep,Per> time)27 nsecs_t toNsecs(std::chrono::duration<Rep, Per> time) {
28   return std::chrono::duration_cast<std::chrono::nanoseconds>(time).count();
29 }
30 
31 template <typename Rep, typename Per>
toMs(std::chrono::duration<Rep,Per> time)32 uint64_t toMs(std::chrono::duration<Rep, Per> time) {
33   return std::chrono::duration_cast<std::chrono::milliseconds>(time).count();
34 }
35 
36 struct TimeKeeperWrapper : histogram::TimeKeeper {
TimeKeeperWrapperTimeKeeperWrapper37   TimeKeeperWrapper(std::shared_ptr<histogram::TimeKeeper> const &tk) : tk(tk) {}
current_timeTimeKeeperWrapper38   nsecs_t current_time() const final { return tk->current_time(); }
39   std::shared_ptr<histogram::TimeKeeper> const tk;
40 };
41 
42 struct TickingTimeKeeper : histogram::TimeKeeper {
tickTickingTimeKeeper43   void tick() { fake_time = fake_time + toNsecs(1ms); }
44 
increment_byTickingTimeKeeper45   void increment_by(std::chrono::nanoseconds inc) { fake_time = fake_time + inc.count(); }
46 
current_timeTickingTimeKeeper47   nsecs_t current_time() const final { return fake_time; }
48 
49  private:
50   nsecs_t mutable fake_time = 0;
51 };
52 
insertFrameIncrementTimeline(histogram::Ringbuffer & rb,TickingTimeKeeper & tk,drm_msm_hist & frame)53 void insertFrameIncrementTimeline(histogram::Ringbuffer &rb, TickingTimeKeeper &tk,
54                                   drm_msm_hist &frame) {
55   rb.insert(frame);
56   tk.tick();
57 }
58 
59 class RingbufferTestCases : public ::testing::Test {
SetUp()60   void SetUp() {
61     for (auto i = 0u; i < HIST_V_SIZE; i++) {
62       frame0.data[i] = fill_frame0;
63       frame1.data[i] = fill_frame1;
64       frame2.data[i] = fill_frame2;
65       frame3.data[i] = fill_frame3;
66       frame4.data[i] = fill_frame4;
67       frame_saturate.data[i] = std::numeric_limits<uint32_t>::max();
68     }
69   }
70 
71  protected:
createFilledRingbuffer(std::shared_ptr<TickingTimeKeeper> const & tk)72   std::unique_ptr<histogram::Ringbuffer> createFilledRingbuffer(
73       std::shared_ptr<TickingTimeKeeper> const &tk) {
74     auto rb = histogram::Ringbuffer::create(4, std::make_unique<TimeKeeperWrapper>(tk));
75     insertFrameIncrementTimeline(*rb, *tk, frame0);
76     insertFrameIncrementTimeline(*rb, *tk, frame1);
77     insertFrameIncrementTimeline(*rb, *tk, frame2);
78     insertFrameIncrementTimeline(*rb, *tk, frame3);
79     return rb;
80   }
81 
82   uint64_t fill_frame0 = 9;
83   uint64_t fill_frame1 = 11;
84   uint64_t fill_frame2 = 303;
85   uint64_t fill_frame3 = 1030;
86   uint64_t fill_frame4 = 112200;
87   drm_msm_hist frame0;
88   drm_msm_hist frame1;
89   drm_msm_hist frame2;
90   drm_msm_hist frame3;
91   drm_msm_hist frame4;
92   drm_msm_hist frame_saturate;
93 
94   int numFrames = 0;
95   std::array<uint64_t, HIST_V_SIZE> bins;
96 };
97 
TEST_F(RingbufferTestCases,ZeroSizedRingbufferReturnsNull)98 TEST_F(RingbufferTestCases, ZeroSizedRingbufferReturnsNull) {
99   EXPECT_THAT(histogram::Ringbuffer::create(0, std::make_unique<TickingTimeKeeper>()), Eq(nullptr));
100 }
101 
TEST_F(RingbufferTestCases,NullTimekeeperReturnsNull)102 TEST_F(RingbufferTestCases, NullTimekeeperReturnsNull) {
103   EXPECT_THAT(histogram::Ringbuffer::create(10, nullptr), Eq(nullptr));
104 }
105 
TEST_F(RingbufferTestCases,CollectionWithNoFrames)106 TEST_F(RingbufferTestCases, CollectionWithNoFrames) {
107   auto rb = histogram::Ringbuffer::create(1, std::make_unique<TickingTimeKeeper>());
108 
109   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
110   EXPECT_THAT(numFrames, Eq(0));
111   EXPECT_THAT(bins, Each(0));
112 }
113 
TEST_F(RingbufferTestCases,SimpleTest)114 TEST_F(RingbufferTestCases, SimpleTest) {
115   static constexpr int numInsertions = 3u;
116   auto tk = std::make_shared<TickingTimeKeeper>();
117   auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique<TimeKeeperWrapper>(tk));
118 
119   drm_msm_hist frame;
120   for (auto i = 0u; i < HIST_V_SIZE; i++) {
121     frame.data[i] = i;
122   }
123 
124   insertFrameIncrementTimeline(*rb, *tk, frame);
125   insertFrameIncrementTimeline(*rb, *tk, frame);
126   insertFrameIncrementTimeline(*rb, *tk, frame);
127 
128   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
129 
130   ASSERT_THAT(bins.size(), Eq(HIST_V_SIZE));
131   for (auto i = 0u; i < bins.size(); i++) {
132     EXPECT_THAT(bins[i], Eq(toMs(3ms) * i));
133   }
134 }
135 
TEST_F(RingbufferTestCases,TestEvictionSingle)136 TEST_F(RingbufferTestCases, TestEvictionSingle) {
137   int fill_frame0 = 9;
138   int fill_frame1 = 111;
139   drm_msm_hist frame0;
140   drm_msm_hist frame1;
141   for (auto i = 0u; i < HIST_V_SIZE; i++) {
142     frame0.data[i] = fill_frame0;
143     frame1.data[i] = fill_frame1;
144   }
145 
146   auto tk = std::make_shared<TickingTimeKeeper>();
147   auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk));
148 
149   insertFrameIncrementTimeline(*rb, *tk, frame0);
150 
151   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
152   EXPECT_THAT(numFrames, Eq(1));
153   EXPECT_THAT(bins, Each(fill_frame0));
154 
155   insertFrameIncrementTimeline(*rb, *tk, frame1);
156   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
157   EXPECT_THAT(numFrames, Eq(1));
158   EXPECT_THAT(bins, Each(fill_frame1));
159 }
160 
TEST_F(RingbufferTestCases,TestEvictionMultiple)161 TEST_F(RingbufferTestCases, TestEvictionMultiple) {
162   auto tk = std::make_shared<TickingTimeKeeper>();
163   auto rb = histogram::Ringbuffer::create(3, std::make_unique<TimeKeeperWrapper>(tk));
164 
165   insertFrameIncrementTimeline(*rb, *tk, frame0);
166   insertFrameIncrementTimeline(*rb, *tk, frame1);
167   insertFrameIncrementTimeline(*rb, *tk, frame2);
168 
169   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
170   EXPECT_THAT(numFrames, Eq(3));
171   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2));
172 
173   insertFrameIncrementTimeline(*rb, *tk, frame3);
174   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
175   EXPECT_THAT(numFrames, Eq(3));
176   EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3));
177 
178   insertFrameIncrementTimeline(*rb, *tk, frame0);
179   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
180   EXPECT_THAT(numFrames, Eq(3));
181   EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3 + fill_frame0));
182 }
183 
TEST_F(RingbufferTestCases,TestResizeToZero)184 TEST_F(RingbufferTestCases, TestResizeToZero) {
185   auto rb = histogram::Ringbuffer::create(4, std::make_unique<TickingTimeKeeper>());
186   EXPECT_FALSE(rb->resize(0));
187 }
188 
TEST_F(RingbufferTestCases,TestResizeDown)189 TEST_F(RingbufferTestCases, TestResizeDown) {
190   auto tk = std::make_shared<TickingTimeKeeper>();
191   auto rb = createFilledRingbuffer(tk);
192 
193   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
194   EXPECT_THAT(numFrames, Eq(4));
195   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3));
196 
197   auto rc = rb->resize(2);
198   EXPECT_THAT(rc, Eq(true));
199   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
200   EXPECT_THAT(numFrames, Eq(2));
201   EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3));
202 
203   insertFrameIncrementTimeline(*rb, *tk, frame0);
204   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
205   EXPECT_THAT(numFrames, Eq(2));
206   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame3));
207 }
208 
TEST_F(RingbufferTestCases,TestResizeUp)209 TEST_F(RingbufferTestCases, TestResizeUp) {
210   auto tk = std::make_shared<TickingTimeKeeper>();
211   auto rb = histogram::Ringbuffer::create(2, std::make_unique<TimeKeeperWrapper>(tk));
212 
213   insertFrameIncrementTimeline(*rb, *tk, frame0);
214   insertFrameIncrementTimeline(*rb, *tk, frame1);
215 
216   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
217   EXPECT_THAT(numFrames, Eq(2));
218   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1));
219 
220   auto rc = rb->resize(3);
221   EXPECT_THAT(rc, Eq(true));
222   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
223   EXPECT_THAT(numFrames, Eq(2));
224   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1));
225 
226   insertFrameIncrementTimeline(*rb, *tk, frame2);
227   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
228   EXPECT_THAT(numFrames, Eq(3));
229   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2));
230 
231   insertFrameIncrementTimeline(*rb, *tk, frame3);
232   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
233   EXPECT_THAT(numFrames, Eq(3));
234   EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3));
235 }
236 
TEST_F(RingbufferTestCases,TestTimestampFiltering)237 TEST_F(RingbufferTestCases, TestTimestampFiltering) {
238   auto rb = createFilledRingbuffer(std::make_shared<TickingTimeKeeper>());
239 
240   std::tie(numFrames, bins) = rb->collect_after(toNsecs(1500us));
241   EXPECT_THAT(numFrames, Eq(2));
242   EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3));
243 
244   std::tie(numFrames, bins) = rb->collect_after(toNsecs(45000us));
245   EXPECT_THAT(numFrames, Eq(0));
246 
247   std::tie(numFrames, bins) = rb->collect_after(0);
248   EXPECT_THAT(numFrames, Eq(4));
249   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3));
250 }
251 
TEST_F(RingbufferTestCases,TestTimestampFilteringSameTimestamp)252 TEST_F(RingbufferTestCases, TestTimestampFilteringSameTimestamp) {
253   auto tk = std::make_shared<TickingTimeKeeper>();
254   auto rb = histogram::Ringbuffer::create(4, std::make_unique<TimeKeeperWrapper>(tk));
255   insertFrameIncrementTimeline(*rb, *tk, frame0);
256   insertFrameIncrementTimeline(*rb, *tk, frame1);
257   insertFrameIncrementTimeline(*rb, *tk, frame2);
258   rb->insert(frame3);
259   rb->insert(frame4);
260   tk->tick();
261 
262   std::tie(numFrames, bins) = rb->collect_after(toNsecs(3ms));
263   EXPECT_THAT(numFrames, Eq(2));
264   EXPECT_THAT(bins, Each(fill_frame4));
265 }
266 
TEST_F(RingbufferTestCases,TestFrameFiltering)267 TEST_F(RingbufferTestCases, TestFrameFiltering) {
268   auto rb = createFilledRingbuffer(std::make_shared<TickingTimeKeeper>());
269 
270   std::tie(numFrames, bins) = rb->collect_max(2);
271   EXPECT_THAT(numFrames, Eq(2));
272   EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3));
273 
274   std::tie(numFrames, bins) = rb->collect_max(0);
275   EXPECT_THAT(numFrames, Eq(0));
276   EXPECT_THAT(bins, Each(0));
277 
278   std::tie(numFrames, bins) = rb->collect_max(3);
279   EXPECT_THAT(numFrames, Eq(3));
280   EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3));
281 
282   std::tie(numFrames, bins) = rb->collect_max(8);
283   EXPECT_THAT(numFrames, Eq(4));
284   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3));
285 }
286 
TEST_F(RingbufferTestCases,TestTimestampAndFrameFiltering)287 TEST_F(RingbufferTestCases, TestTimestampAndFrameFiltering) {
288   auto rb = createFilledRingbuffer(std::make_shared<TickingTimeKeeper>());
289 
290   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(1500us), 1);
291   EXPECT_THAT(numFrames, Eq(1));
292   EXPECT_THAT(bins, Each(fill_frame3));
293 
294   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(2500us), 0);
295   EXPECT_THAT(numFrames, Eq(0));
296   EXPECT_THAT(bins, Each(0));
297 
298   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(10ms), 100);
299   EXPECT_THAT(numFrames, Eq(0));
300   EXPECT_THAT(bins, Each(0));
301 
302   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(0ns), 10);
303   EXPECT_THAT(numFrames, Eq(4));
304   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3));
305 }
306 
TEST_F(RingbufferTestCases,TestTimestampAndFrameFilteringAndResize)307 TEST_F(RingbufferTestCases, TestTimestampAndFrameFilteringAndResize) {
308   auto rb = createFilledRingbuffer(std::make_shared<TickingTimeKeeper>());
309 
310   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 1);
311   EXPECT_THAT(numFrames, Eq(1));
312   EXPECT_THAT(bins, Each(fill_frame3));
313 
314   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 10);
315   EXPECT_THAT(numFrames, Eq(3));
316   EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3));
317 
318   rb->resize(2);
319   std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 10);
320   EXPECT_THAT(numFrames, Eq(2));
321   EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3));
322 }
323 
TEST_F(RingbufferTestCases,TestCumulativeCounts)324 TEST_F(RingbufferTestCases, TestCumulativeCounts) {
325   auto tk = std::make_shared<TickingTimeKeeper>();
326   auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk));
327   insertFrameIncrementTimeline(*rb, *tk, frame0);
328 
329   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
330   EXPECT_THAT(numFrames, Eq(1));
331   EXPECT_THAT(bins, Each(fill_frame0));
332 
333   insertFrameIncrementTimeline(*rb, *tk, frame1);
334   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
335   EXPECT_THAT(numFrames, Eq(1));
336   EXPECT_THAT(bins, Each(fill_frame1));
337 
338   std::tie(numFrames, bins) = rb->collect_cumulative();
339   EXPECT_THAT(numFrames, Eq(2));
340   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1));
341   rb->insert(frame2);
342   auto weight0 = std::chrono::duration_cast<std::chrono::nanoseconds>(1h);
343   tk->increment_by(weight0);
344 
345   std::tie(numFrames, bins) = rb->collect_cumulative();
346   EXPECT_THAT(numFrames, Eq(3));
347   EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 +
348                          (fill_frame2 *
349                           std::chrono::duration_cast<std::chrono::milliseconds>(weight0).count())));
350 
351   auto weight1 = std::chrono::duration_cast<std::chrono::nanoseconds>(2min);
352   tk->increment_by(weight1);
353   std::tie(numFrames, bins) = rb->collect_cumulative();
354   EXPECT_THAT(numFrames, Eq(3));
355   EXPECT_THAT(
356       bins,
357       Each(fill_frame0 + fill_frame1 +
358            (fill_frame2 *
359             std::chrono::duration_cast<std::chrono::milliseconds>(weight0 + weight1).count())));
360 }
361 
TEST_F(RingbufferTestCases,TestCumulativeCountsEmpty)362 TEST_F(RingbufferTestCases, TestCumulativeCountsEmpty) {
363   auto tk = std::make_shared<TickingTimeKeeper>();
364   auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk));
365   std::tie(numFrames, bins) = rb->collect_cumulative();
366   EXPECT_THAT(numFrames, Eq(0));
367 }
368 
TEST_F(RingbufferTestCases,TestCumulativeCountsSaturate)369 TEST_F(RingbufferTestCases, TestCumulativeCountsSaturate) {
370   auto tk = std::make_shared<TickingTimeKeeper>();
371   auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk));
372   insertFrameIncrementTimeline(*rb, *tk, frame_saturate);
373   auto eon = std::chrono::nanoseconds(std::numeric_limits<uint64_t>::max());
374   tk->increment_by(eon);
375   std::tie(numFrames, bins) = rb->collect_cumulative();
376   EXPECT_THAT(numFrames, Eq(1));
377   EXPECT_THAT(bins, Each(std::numeric_limits<uint64_t>::max()));
378 }
379 
TEST_F(RingbufferTestCases,TimeWeightingTest)380 TEST_F(RingbufferTestCases, TimeWeightingTest) {
381   static constexpr int numInsertions = 4u;
382   auto tk = std::make_shared<TickingTimeKeeper>();
383   auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique<TimeKeeperWrapper>(tk));
384 
385   auto weight0 = std::chrono::duration_cast<std::chrono::nanoseconds>(1ms);
386   auto weight1 = std::chrono::duration_cast<std::chrono::nanoseconds>(1h);
387   auto weight2 = std::chrono::duration_cast<std::chrono::nanoseconds>(1s);
388   using gigasecond = std::chrono::duration<uint64_t, std::giga>;
389   auto weight3 = std::chrono::duration_cast<std::chrono::nanoseconds>(gigasecond(4));
390 
391   rb->insert(frame0);
392   tk->increment_by(weight0);
393   rb->insert(frame1);
394   tk->increment_by(weight1);
395   rb->insert(frame2);
396   tk->increment_by(weight2);
397   rb->insert(frame3);
398   tk->increment_by(weight3);
399 
400   std::tie(numFrames, bins) = rb->collect_ringbuffer_all();
401 
402   ASSERT_THAT(bins.size(), Eq(HIST_V_SIZE));
403   uint64_t expected_weight = fill_frame0 * toMs(weight0) + fill_frame1 * toMs(weight1) +
404                              fill_frame2 * toMs(weight2) + fill_frame3 * toMs(weight3);
405   for (auto i = 0u; i < bins.size(); i++) {
406     EXPECT_THAT(bins[i], Eq(expected_weight));
407   }
408 }
409 
main(int argc,char ** argv)410 int main(int argc, char **argv) {
411   ::testing::InitGoogleTest(&argc, argv);
412   return RUN_ALL_TESTS();
413 }
414