summaryrefslogtreecommitdiffstats
path: root/libhistogram/ringbuffer_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libhistogram/ringbuffer_test.cpp')
-rw-r--r--libhistogram/ringbuffer_test.cpp410
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();
+}