// 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 #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(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