diff options
Diffstat (limited to 'libhistogram/ringbuffer_test.cpp')
-rw-r--r-- | libhistogram/ringbuffer_test.cpp | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/libhistogram/ringbuffer_test.cpp b/libhistogram/ringbuffer_test.cpp new file mode 100644 index 00000000..8e01aad0 --- /dev/null +++ b/libhistogram/ringbuffer_test.cpp @@ -0,0 +1,410 @@ +/* + * 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 <chrono> +#include <numeric> + +#include <gtest/gtest.h> +#include <gmock/gmock.h> +#include "ringbuffer.h" +using namespace testing; +using namespace std::chrono_literals; + +template <typename Rep, typename Per> +nsecs_t toNsecs(std::chrono::duration<Rep, Per> time) { + return std::chrono::duration_cast<std::chrono::nanoseconds>(time).count(); +} + +template <typename Rep, typename Per> +uint64_t toMs(std::chrono::duration<Rep, Per> time) { + return std::chrono::duration_cast<std::chrono::milliseconds>(time).count(); +} + +struct TimeKeeperWrapper : histogram::TimeKeeper { + TimeKeeperWrapper(std::shared_ptr<histogram::TimeKeeper> const &tk) : tk(tk) {} + nsecs_t current_time() const final { return tk->current_time(); } + std::shared_ptr<histogram::TimeKeeper> 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<uint32_t>::max(); + } + } + +protected: + std::unique_ptr<histogram::Ringbuffer> createFilledRingbuffer( + std::shared_ptr<TickingTimeKeeper> const &tk) { + auto rb = histogram::Ringbuffer::create(4, std::make_unique<TimeKeeperWrapper>(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<uint64_t, HIST_V_SIZE> bins; +}; + +TEST_F(RingbufferTestCases, ZeroSizedRingbufferReturnsNull) { + EXPECT_THAT(histogram::Ringbuffer::create(0, std::make_unique<TickingTimeKeeper>()), + 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<TickingTimeKeeper>()); + + 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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique<TimeKeeperWrapper>(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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(3, std::make_unique<TimeKeeperWrapper>(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<TickingTimeKeeper>()); + EXPECT_FALSE(rb->resize(0)); +} + +TEST_F(RingbufferTestCases, TestResizeDown) { + auto tk = std::make_shared<TickingTimeKeeper>(); + 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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(2, std::make_unique<TimeKeeperWrapper>(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<TickingTimeKeeper>()); + + 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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(4, std::make_unique<TimeKeeperWrapper>(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<TickingTimeKeeper>()); + + 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<TickingTimeKeeper>()); + + 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<TickingTimeKeeper>()); + + 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<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(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<std::chrono::nanoseconds>(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<std::chrono::milliseconds>(weight0).count()))); + + auto weight1 = std::chrono::duration_cast<std::chrono::nanoseconds>(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<std::chrono::milliseconds>(weight0 + weight1).count()))); +} + +TEST_F(RingbufferTestCases, TestCumulativeCountsEmpty) { + auto tk = std::make_shared<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk)); + std::tie(numFrames, bins) = rb->collect_cumulative(); + EXPECT_THAT(numFrames, Eq(0)); +} + +TEST_F(RingbufferTestCases, TestCumulativeCountsSaturate) { + auto tk = std::make_shared<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(1, std::make_unique<TimeKeeperWrapper>(tk)); + insertFrameIncrementTimeline(*rb, *tk, frame_saturate); + auto eon = std::chrono::nanoseconds(std::numeric_limits<uint64_t>::max()); + tk->increment_by(eon); + std::tie(numFrames, bins) = rb->collect_cumulative(); + EXPECT_THAT(numFrames, Eq(1)); + EXPECT_THAT(bins, Each(std::numeric_limits<uint64_t>::max())); +} + +TEST_F(RingbufferTestCases, TimeWeightingTest) { + static constexpr int numInsertions = 4u; + auto tk = std::make_shared<TickingTimeKeeper>(); + auto rb = histogram::Ringbuffer::create(numInsertions, std::make_unique<TimeKeeperWrapper>(tk)); + + auto weight0 = std::chrono::duration_cast<std::chrono::nanoseconds>(1ms); + auto weight1 = std::chrono::duration_cast<std::chrono::nanoseconds>(1h); + auto weight2 = std::chrono::duration_cast<std::chrono::nanoseconds>(1s); + using gigasecond = std::chrono::duration<uint64_t, std::giga>; + auto weight3 = std::chrono::duration_cast<std::chrono::nanoseconds>(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(); +} |