/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "ringbuffer.h" using namespace testing; using namespace std::chrono_literals; template nsecs_t toNsecs(std::chrono::duration time) { return std::chrono::duration_cast(time).count(); } template uint64_t toMs(std::chrono::duration time) { return std::chrono::duration_cast(time).count(); } struct TimeKeeperWrapper : histogram::TimeKeeper { TimeKeeperWrapper(std::shared_ptr const &tk) : tk(tk) {} nsecs_t current_time() const final { return tk->current_time(); } std::shared_ptr const tk; }; struct TickingTimeKeeper : histogram::TimeKeeper { void tick() { fake_time = fake_time + toNsecs(1ms); } void increment_by(std::chrono::nanoseconds inc) { fake_time = fake_time + inc.count(); } nsecs_t current_time() const final { return fake_time; } private: nsecs_t mutable fake_time = 0; }; void insertFrameIncrementTimeline(histogram::Ringbuffer &rb, TickingTimeKeeper &tk, drm_msm_hist &frame) { rb.insert(frame); tk.tick(); } class RingbufferTestCases : public ::testing::Test { void SetUp() { for (auto i = 0u; i < HIST_V_SIZE; i++) { frame0.data[i] = fill_frame0; frame1.data[i] = fill_frame1; frame2.data[i] = fill_frame2; frame3.data[i] = fill_frame3; frame4.data[i] = fill_frame4; frame_saturate.data[i] = std::numeric_limits::max(); } } protected: std::unique_ptr createFilledRingbuffer( std::shared_ptr const &tk) { auto rb = histogram::Ringbuffer::create(4, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); insertFrameIncrementTimeline(*rb, *tk, frame1); insertFrameIncrementTimeline(*rb, *tk, frame2); insertFrameIncrementTimeline(*rb, *tk, frame3); return rb; } uint64_t fill_frame0 = 9; uint64_t fill_frame1 = 11; uint64_t fill_frame2 = 303; uint64_t fill_frame3 = 1030; uint64_t fill_frame4 = 112200; drm_msm_hist frame0; drm_msm_hist frame1; drm_msm_hist frame2; drm_msm_hist frame3; drm_msm_hist frame4; drm_msm_hist frame_saturate; int numFrames = 0; std::array bins; }; TEST_F(RingbufferTestCases, ZeroSizedRingbufferReturnsNull) { EXPECT_THAT(histogram::Ringbuffer::create(0, std::make_unique()), Eq(nullptr)); } TEST_F(RingbufferTestCases, NullTimekeeperReturnsNull) { EXPECT_THAT(histogram::Ringbuffer::create(10, nullptr), Eq(nullptr)); } TEST_F(RingbufferTestCases, CollectionWithNoFrames) { auto rb = histogram::Ringbuffer::create(1, std::make_unique()); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(0)); EXPECT_THAT(bins, Each(0)); } TEST_F(RingbufferTestCases, SimpleTest) { static constexpr int numInsertions = 3u; auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique(tk)); drm_msm_hist frame; for (auto i = 0u; i < HIST_V_SIZE; i++) { frame.data[i] = i; } insertFrameIncrementTimeline(*rb, *tk, frame); insertFrameIncrementTimeline(*rb, *tk, frame); insertFrameIncrementTimeline(*rb, *tk, frame); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); ASSERT_THAT(bins.size(), Eq(HIST_V_SIZE)); for (auto i = 0u; i < bins.size(); i++) { EXPECT_THAT(bins[i], Eq(toMs(3ms) * i)); } } TEST_F(RingbufferTestCases, TestEvictionSingle) { int fill_frame0 = 9; int fill_frame1 = 111; drm_msm_hist frame0; drm_msm_hist frame1; for (auto i = 0u; i < HIST_V_SIZE; i++) { frame0.data[i] = fill_frame0; frame1.data[i] = fill_frame1; } auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(1, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame0)); insertFrameIncrementTimeline(*rb, *tk, frame1); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame1)); } TEST_F(RingbufferTestCases, TestEvictionMultiple) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(3, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); insertFrameIncrementTimeline(*rb, *tk, frame1); insertFrameIncrementTimeline(*rb, *tk, frame2); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2)); insertFrameIncrementTimeline(*rb, *tk, frame3); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3)); insertFrameIncrementTimeline(*rb, *tk, frame0); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3 + fill_frame0)); } TEST_F(RingbufferTestCases, TestResizeToZero) { auto rb = histogram::Ringbuffer::create(4, std::make_unique()); EXPECT_FALSE(rb->resize(0)); } TEST_F(RingbufferTestCases, TestResizeDown) { auto tk = std::make_shared(); auto rb = createFilledRingbuffer(tk); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(4)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3)); auto rc = rb->resize(2); EXPECT_THAT(rc, Eq(true)); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3)); insertFrameIncrementTimeline(*rb, *tk, frame0); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame3)); } TEST_F(RingbufferTestCases, TestResizeUp) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(2, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); insertFrameIncrementTimeline(*rb, *tk, frame1); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1)); auto rc = rb->resize(3); EXPECT_THAT(rc, Eq(true)); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1)); insertFrameIncrementTimeline(*rb, *tk, frame2); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2)); insertFrameIncrementTimeline(*rb, *tk, frame3); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3)); } TEST_F(RingbufferTestCases, TestTimestampFiltering) { auto rb = createFilledRingbuffer(std::make_shared()); std::tie(numFrames, bins) = rb->collect_after(toNsecs(1500us)); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3)); std::tie(numFrames, bins) = rb->collect_after(toNsecs(45000us)); EXPECT_THAT(numFrames, Eq(0)); std::tie(numFrames, bins) = rb->collect_after(0); EXPECT_THAT(numFrames, Eq(4)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3)); } TEST_F(RingbufferTestCases, TestTimestampFilteringSameTimestamp) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(4, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); insertFrameIncrementTimeline(*rb, *tk, frame1); insertFrameIncrementTimeline(*rb, *tk, frame2); rb->insert(frame3); rb->insert(frame4); tk->tick(); std::tie(numFrames, bins) = rb->collect_after(toNsecs(3ms)); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame4)); } TEST_F(RingbufferTestCases, TestFrameFiltering) { auto rb = createFilledRingbuffer(std::make_shared()); std::tie(numFrames, bins) = rb->collect_max(2); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3)); std::tie(numFrames, bins) = rb->collect_max(0); EXPECT_THAT(numFrames, Eq(0)); EXPECT_THAT(bins, Each(0)); std::tie(numFrames, bins) = rb->collect_max(3); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3)); std::tie(numFrames, bins) = rb->collect_max(8); EXPECT_THAT(numFrames, Eq(4)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3)); } TEST_F(RingbufferTestCases, TestTimestampAndFrameFiltering) { auto rb = createFilledRingbuffer(std::make_shared()); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(1500us), 1); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame3)); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(2500us), 0); EXPECT_THAT(numFrames, Eq(0)); EXPECT_THAT(bins, Each(0)); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(10ms), 100); EXPECT_THAT(numFrames, Eq(0)); EXPECT_THAT(bins, Each(0)); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(0ns), 10); EXPECT_THAT(numFrames, Eq(4)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + fill_frame2 + fill_frame3)); } TEST_F(RingbufferTestCases, TestTimestampAndFrameFilteringAndResize) { auto rb = createFilledRingbuffer(std::make_shared()); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 1); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame3)); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 10); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame1 + fill_frame2 + fill_frame3)); rb->resize(2); std::tie(numFrames, bins) = rb->collect_max_after(toNsecs(500us), 10); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame2 + fill_frame3)); } TEST_F(RingbufferTestCases, TestCumulativeCounts) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(1, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame0); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame0)); insertFrameIncrementTimeline(*rb, *tk, frame1); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(fill_frame1)); std::tie(numFrames, bins) = rb->collect_cumulative(); EXPECT_THAT(numFrames, Eq(2)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1)); rb->insert(frame2); auto weight0 = std::chrono::duration_cast(1h); tk->increment_by(weight0); std::tie(numFrames, bins) = rb->collect_cumulative(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT(bins, Each(fill_frame0 + fill_frame1 + (fill_frame2 * std::chrono::duration_cast(weight0).count()))); auto weight1 = std::chrono::duration_cast(2min); tk->increment_by(weight1); std::tie(numFrames, bins) = rb->collect_cumulative(); EXPECT_THAT(numFrames, Eq(3)); EXPECT_THAT( bins, Each(fill_frame0 + fill_frame1 + (fill_frame2 * std::chrono::duration_cast(weight0 + weight1).count()))); } TEST_F(RingbufferTestCases, TestCumulativeCountsEmpty) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(1, std::make_unique(tk)); std::tie(numFrames, bins) = rb->collect_cumulative(); EXPECT_THAT(numFrames, Eq(0)); } TEST_F(RingbufferTestCases, TestCumulativeCountsSaturate) { auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(1, std::make_unique(tk)); insertFrameIncrementTimeline(*rb, *tk, frame_saturate); auto eon = std::chrono::nanoseconds(std::numeric_limits::max()); tk->increment_by(eon); std::tie(numFrames, bins) = rb->collect_cumulative(); EXPECT_THAT(numFrames, Eq(1)); EXPECT_THAT(bins, Each(std::numeric_limits::max())); } TEST_F(RingbufferTestCases, TimeWeightingTest) { static constexpr int numInsertions = 4u; auto tk = std::make_shared(); auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique(tk)); auto weight0 = std::chrono::duration_cast(1ms); auto weight1 = std::chrono::duration_cast(1h); auto weight2 = std::chrono::duration_cast(1s); using gigasecond = std::chrono::duration; auto weight3 = std::chrono::duration_cast(gigasecond(4)); rb->insert(frame0); tk->increment_by(weight0); rb->insert(frame1); tk->increment_by(weight1); rb->insert(frame2); tk->increment_by(weight2); rb->insert(frame3); tk->increment_by(weight3); std::tie(numFrames, bins) = rb->collect_ringbuffer_all(); ASSERT_THAT(bins.size(), Eq(HIST_V_SIZE)); uint64_t expected_weight = fill_frame0 * toMs(weight0) + fill_frame1 * toMs(weight1) + fill_frame2 * toMs(weight2) + fill_frame3 * toMs(weight3); for (auto i = 0u; i < bins.size(); i++) { EXPECT_THAT(bins[i], Eq(expected_weight)); } } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }