blob: ab7480fc3fc5932e979c5c793fd224c87031a79d [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/latency/histograms.h"
#include <algorithm>
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/sample_vector.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
#include "ui/latency/fixed_point.h"
#include "ui/latency/frame_metrics_test_common.h"
namespace ui {
namespace frame_metrics {
constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(2);
// A version of RatioHistogram based on the default implementations
// of base::BucketRanges and base::SampleVector.
class RatioHistogramBaseline : public Histogram {
public:
RatioHistogramBaseline()
: ratio_boundaries_(),
bucket_ranges_(ratio_boundaries_.size()),
sample_vector_(&bucket_ranges_) {
size_t i = 0;
for (const auto& b : ratio_boundaries_.boundaries) {
bucket_ranges_.set_range(i++, std::min<uint64_t>(b, INT_MAX));
}
}
~RatioHistogramBaseline() override = default;
void AddSample(uint32_t microseconds, uint32_t weight) override {
sample_vector_.Accumulate(microseconds, weight);
}
PercentileResults ComputePercentiles() const override {
return PercentileResults();
}
void Reset() override {}
private:
TestRatioBoundaries ratio_boundaries_;
base::BucketRanges bucket_ranges_;
base::SampleVector sample_vector_;
DISALLOW_COPY_AND_ASSIGN(RatioHistogramBaseline);
};
TEST(FrameMetricsHistogramsPerfTest, RatioEntireRange) {
const int kStride = 0x1000;
RatioHistogramBaseline vh_base;
RatioHistogram vh_impl;
base::TimeDelta impl_time;
base::TimeDelta base_time;
base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
while (base::TimeTicks::Now() < finish_time) {
// Impl then Base
for (int i = 0; i < INT_MAX - kStride; i += kStride) {
int value = (i * 37) & 0x3FFFFFFF;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
impl_time += t1 - t0 - (t3 - t2);
base_time += t2 - t1 - (t3 - t2);
}
// Base then Impl
for (int i = 0; i < INT_MAX - kStride; i += kStride) {
int value = (i * 37) & 0x3FFFFFFF;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
base_time += t1 - t0 - (t3 - t2);
impl_time += t2 - t1 - (t3 - t2);
}
}
double X = base_time.InSecondsF() / impl_time.InSecondsF();
perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
}
TEST(FrameMetricsHistogramsPerfTest, RatioCommonRange) {
const int kStride = 0x100;
RatioHistogramBaseline vh_base;
RatioHistogram vh_impl;
base::TimeDelta impl_time;
base::TimeDelta base_time;
base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
while (base::TimeTicks::Now() < finish_time) {
// Impl then Base
for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
int value = i;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
impl_time += t1 - t0 - (t3 - t2);
base_time += t2 - t1 - (t3 - t2);
}
// Base then Impl
for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
int value = i;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
base_time += t1 - t0 - (t3 - t2);
impl_time += t2 - t1 - (t3 - t2);
}
}
double X = base_time.InSecondsF() / impl_time.InSecondsF();
perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
}
// A version of VSyncHistogram based on the default implementations
// of base::BucketRanges and base::SampleVector.
class VSyncHistogramBaseline : public Histogram {
public:
VSyncHistogramBaseline()
: bucket_ranges_(kTestVSyncBoundries.size() + 1),
sample_vector_(&bucket_ranges_) {
size_t i = 0;
for (const auto& b : kTestVSyncBoundries) {
bucket_ranges_.set_range(i++, b);
}
// BucketRanges needs the last element set to INT_MAX.
bucket_ranges_.set_range(i++, INT_MAX);
}
~VSyncHistogramBaseline() override = default;
void AddSample(uint32_t microseconds, uint32_t weight) override {
sample_vector_.Accumulate(microseconds, weight);
}
PercentileResults ComputePercentiles() const override {
return PercentileResults();
}
void Reset() override {}
private:
base::BucketRanges bucket_ranges_;
base::SampleVector sample_vector_;
DISALLOW_COPY_AND_ASSIGN(VSyncHistogramBaseline);
};
TEST(FrameMetricsHistogramsPerfTest, VSyncEntireRange) {
const int kStride = 0x1000;
VSyncHistogramBaseline vh_base;
VSyncHistogram vh_impl;
base::TimeDelta impl_time;
base::TimeDelta base_time;
base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
while (base::TimeTicks::Now() < finish_time) {
// Impl then Base
for (int i = 0; i < INT_MAX - kStride; i += kStride) {
int value = (i * 37) % 64000000;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
impl_time += t1 - t0 - (t3 - t2);
base_time += t2 - t1 - (t3 - t2);
}
// Base then Impl
for (int i = 0; i < INT_MAX - kStride; i += kStride) {
int value = (i * 37) % 64000000;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
base_time += t1 - t0 - (t3 - t2);
impl_time += t2 - t1 - (t3 - t2);
}
}
double X = base_time.InSecondsF() / impl_time.InSecondsF();
perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
}
TEST(FrameMetricsHistogramsPerfTest, VSyncCommonRange) {
const int kStride = 0x100;
VSyncHistogramBaseline vh_base;
VSyncHistogram vh_impl;
base::TimeDelta impl_time;
base::TimeDelta base_time;
base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
while (base::TimeTicks::Now() < finish_time) {
// Impl then Base
for (int i = 0; i < 100000; i += kStride) {
int value = i;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
impl_time += t1 - t0 - (t3 - t2);
base_time += t2 - t1 - (t3 - t2);
}
// Base then Impl
for (int i = 0; i < 100000; i += kStride) {
int value = i;
base::TimeTicks t0 = base::TimeTicks::Now();
vh_base.AddSample(value, 1);
base::TimeTicks t1 = base::TimeTicks::Now();
vh_impl.AddSample(value, 1);
base::TimeTicks t2 = base::TimeTicks::Now();
base::TimeTicks t3 = base::TimeTicks::Now();
base_time += t1 - t0 - (t3 - t2);
impl_time += t2 - t1 - (t3 - t2);
}
}
double X = base_time.InSecondsF() / impl_time.InSecondsF();
perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
}
} // namespace frame_metrics
} // namespace ui