blob: 8e01aad0f782ff1646633654fd68cfc984b52729 [file] [log] [blame]
/*
* 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();
}