blob: 75c01cb7b8b8019b4fd658906942eb9e22af01b4 [file] [log] [blame]
// Copyright 2017 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 "platform/scheduler/renderer/renderer_metrics_helper.h"
#include <memory>
#include "base/macros.h"
#include "base/test/histogram_tester.h"
#include "base/test/simple_test_tick_clock.h"
#include "components/viz/test/ordered_simple_task_runner.h"
#include "platform/WebFrameScheduler.h"
#include "platform/scheduler/base/test_time_source.h"
#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h"
#include "platform/scheduler/renderer/renderer_scheduler_impl.h"
#include "platform/scheduler/test/fake_web_frame_scheduler.h"
#include "platform/scheduler/test/fake_web_view_scheduler.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace scheduler {
using QueueType = MainThreadTaskQueue::QueueType;
using testing::ElementsAre;
using testing::UnorderedElementsAre;
using base::Bucket;
class RendererMetricsHelperTest : public ::testing::Test {
public:
RendererMetricsHelperTest() {}
~RendererMetricsHelperTest() {}
void SetUp() {
histogram_tester_.reset(new base::HistogramTester());
clock_ = std::make_unique<base::SimpleTestTickClock>();
mock_task_runner_ =
base::MakeRefCounted<cc::OrderedSimpleTaskRunner>(clock_.get(), true);
delegate_ = SchedulerTqmDelegateForTest::Create(
mock_task_runner_, std::make_unique<TestTimeSource>(clock_.get()));
scheduler_ = std::make_unique<RendererSchedulerImpl>(delegate_);
metrics_helper_ = &scheduler_->main_thread_only().metrics_helper;
}
void TearDown() {
scheduler_->Shutdown();
scheduler_.reset();
}
void RunTask(MainThreadTaskQueue::QueueType queue_type,
base::TimeTicks start,
base::TimeDelta duration) {
DCHECK_LE(clock_->NowTicks(), start);
clock_->SetNowTicks(start + duration);
scoped_refptr<MainThreadTaskQueueForTest> queue(
new MainThreadTaskQueueForTest(queue_type));
metrics_helper_->RecordTaskMetrics(queue.get(), start, start + duration);
}
base::TimeTicks Microseconds(int microseconds) {
return base::TimeTicks() + base::TimeDelta::FromMicroseconds(microseconds);
}
base::TimeTicks Milliseconds(int milliseconds) {
return base::TimeTicks() + base::TimeDelta::FromMilliseconds(milliseconds);
}
void ForceUpdatePolicy() { scheduler_->ForceUpdatePolicy(); }
std::unique_ptr<base::SimpleTestTickClock> clock_;
scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
scoped_refptr<SchedulerTqmDelegate> delegate_;
std::unique_ptr<RendererSchedulerImpl> scheduler_;
RendererMetricsHelper* metrics_helper_; // NOT OWNED
std::unique_ptr<base::HistogramTester> histogram_tester_;
DISALLOW_COPY_AND_ASSIGN(RendererMetricsHelperTest);
};
TEST_F(RendererMetricsHelperTest, Metrics) {
// QueueType::kDefault is checking sub-millisecond task aggregation,
// FRAME_* tasks are checking normal task aggregation and other
// queue types have a single task.
RunTask(QueueType::kDefault, Milliseconds(1),
base::TimeDelta::FromMicroseconds(700));
RunTask(QueueType::kDefault, Milliseconds(2),
base::TimeDelta::FromMicroseconds(700));
RunTask(QueueType::kDefault, Milliseconds(3),
base::TimeDelta::FromMicroseconds(700));
RunTask(QueueType::kDefaultLoading, Milliseconds(200),
base::TimeDelta::FromMilliseconds(20));
RunTask(QueueType::kControl, Milliseconds(400),
base::TimeDelta::FromMilliseconds(30));
RunTask(QueueType::kDefaultTimer, Milliseconds(600),
base::TimeDelta::FromMilliseconds(5));
RunTask(QueueType::kFrameLoading, Milliseconds(800),
base::TimeDelta::FromMilliseconds(70));
RunTask(QueueType::kFramePausable, Milliseconds(1000),
base::TimeDelta::FromMilliseconds(20));
RunTask(QueueType::kCompositor, Milliseconds(1200),
base::TimeDelta::FromMilliseconds(25));
RunTask(QueueType::kTest, Milliseconds(1600),
base::TimeDelta::FromMilliseconds(85));
scheduler_->SetRendererBackgrounded(true);
RunTask(QueueType::kControl, Milliseconds(2000),
base::TimeDelta::FromMilliseconds(25));
RunTask(QueueType::kFrameThrottleable, Milliseconds(2600),
base::TimeDelta::FromMilliseconds(175));
RunTask(QueueType::kUnthrottled, Milliseconds(2800),
base::TimeDelta::FromMilliseconds(25));
RunTask(QueueType::kFrameLoading, Milliseconds(3000),
base::TimeDelta::FromMilliseconds(35));
RunTask(QueueType::kFrameThrottleable, Milliseconds(3200),
base::TimeDelta::FromMilliseconds(5));
RunTask(QueueType::kCompositor, Milliseconds(3400),
base::TimeDelta::FromMilliseconds(20));
RunTask(QueueType::kIdle, Milliseconds(3600),
base::TimeDelta::FromMilliseconds(50));
RunTask(QueueType::kFrameLoading_kControl, Milliseconds(4000),
base::TimeDelta::FromMilliseconds(5));
RunTask(QueueType::kControl, Milliseconds(4200),
base::TimeDelta::FromMilliseconds(20));
RunTask(QueueType::kFrameThrottleable, Milliseconds(4400),
base::TimeDelta::FromMilliseconds(115));
RunTask(QueueType::kFramePausable, Milliseconds(4600),
base::TimeDelta::FromMilliseconds(175));
RunTask(QueueType::kIdle, Milliseconds(5000),
base::TimeDelta::FromMilliseconds(1600));
std::vector<base::Bucket> expected_samples = {
{static_cast<int>(QueueType::kControl), 75},
{static_cast<int>(QueueType::kDefault), 2},
{static_cast<int>(QueueType::kDefaultLoading), 20},
{static_cast<int>(QueueType::kDefaultTimer), 5},
{static_cast<int>(QueueType::kUnthrottled), 25},
{static_cast<int>(QueueType::kFrameLoading), 105},
{static_cast<int>(QueueType::kCompositor), 45},
{static_cast<int>(QueueType::kIdle), 1650},
{static_cast<int>(QueueType::kTest), 85},
{static_cast<int>(QueueType::kFrameLoading_kControl), 5},
{static_cast<int>(QueueType::kFrameThrottleable), 295},
{static_cast<int>(QueueType::kFramePausable), 195}};
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.TaskDurationPerQueueType2"),
testing::ContainerEq(expected_samples));
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.TaskDurationPerQueueType2.Foreground"),
UnorderedElementsAre(
Bucket(static_cast<int>(QueueType::kControl), 30),
Bucket(static_cast<int>(QueueType::kDefault), 2),
Bucket(static_cast<int>(QueueType::kDefaultLoading), 20),
Bucket(static_cast<int>(QueueType::kDefaultTimer), 5),
Bucket(static_cast<int>(QueueType::kFrameLoading), 70),
Bucket(static_cast<int>(QueueType::kCompositor), 25),
Bucket(static_cast<int>(QueueType::kTest), 85),
Bucket(static_cast<int>(QueueType::kFramePausable), 20)));
EXPECT_THAT(
histogram_tester_->GetAllSamples(
"RendererScheduler.TaskDurationPerQueueType2.Background"),
UnorderedElementsAre(
Bucket(static_cast<int>(QueueType::kControl), 45),
Bucket(static_cast<int>(QueueType::kUnthrottled), 25),
Bucket(static_cast<int>(QueueType::kFrameLoading), 35),
Bucket(static_cast<int>(QueueType::kFrameThrottleable), 295),
Bucket(static_cast<int>(QueueType::kFramePausable), 175),
Bucket(static_cast<int>(QueueType::kCompositor), 20),
Bucket(static_cast<int>(QueueType::kIdle), 1650),
Bucket(static_cast<int>(QueueType::kFrameLoading_kControl), 5)));
}
TEST_F(RendererMetricsHelperTest, GetFrameTypeTest) {
DCHECK_EQ(GetFrameType(nullptr), FrameType::kNone);
std::unique_ptr<FakeWebFrameScheduler> frame1 =
FakeWebFrameScheduler::Builder()
.SetFrameType(WebFrameScheduler::FrameType::kMainFrame)
.SetIsPageVisible(true)
.SetIsFrameVisible(true)
.Build();
EXPECT_EQ(GetFrameType(frame1.get()), FrameType::kMainFrameVisible);
std::unique_ptr<FakeWebFrameScheduler> frame2 =
FakeWebFrameScheduler::Builder()
.SetFrameType(WebFrameScheduler::FrameType::kSubframe)
.SetIsPageVisible(true)
.Build();
EXPECT_EQ(GetFrameType(frame2.get()), FrameType::kSameOriginHidden);
std::unique_ptr<FakeWebFrameScheduler> frame3 =
FakeWebFrameScheduler::Builder()
.SetFrameType(WebFrameScheduler::FrameType::kSubframe)
.SetIsPageVisible(true)
.SetIsCrossOrigin(true)
.Build();
EXPECT_EQ(GetFrameType(frame3.get()), FrameType::kCrossOriginHidden);
std::unique_ptr<FakeWebFrameScheduler> frame4 =
FakeWebFrameScheduler::Builder()
.SetFrameType(WebFrameScheduler::FrameType::kSubframe)
.Build();
EXPECT_EQ(GetFrameType(frame4.get()), FrameType::kSameOriginBackground);
std::unique_ptr<FakeWebFrameScheduler> frame5 =
FakeWebFrameScheduler::Builder()
.SetFrameType(WebFrameScheduler::FrameType::kMainFrame)
.SetIsExemptFromThrottling(true)
.Build();
DCHECK_EQ(GetFrameType(frame5.get()),
FrameType::kMainFrameBackgroundExemptSelf);
std::unique_ptr<FakeWebViewScheduler> view1 =
FakeWebViewScheduler::Builder().SetIsPlayingAudio(true).Build();
std::unique_ptr<FakeWebFrameScheduler> frame6 =
FakeWebFrameScheduler::Builder()
.SetWebViewScheduler(view1.get())
.SetIsFrameVisible(true)
.SetFrameType(WebFrameScheduler::FrameType::kSubframe)
.Build();
DCHECK_EQ(GetFrameType(frame6.get()), FrameType::kSameOriginVisibleService);
std::unique_ptr<FakeWebFrameScheduler> frame7 =
FakeWebFrameScheduler::Builder()
.SetWebViewScheduler(view1.get())
.SetIsCrossOrigin(true)
.SetFrameType(WebFrameScheduler::FrameType::kSubframe)
.Build();
DCHECK_EQ(GetFrameType(frame7.get()), FrameType::kCrossOriginHiddenService);
std::unique_ptr<FakeWebViewScheduler> view2 =
FakeWebViewScheduler::Builder().SetIsThrottlingExempt(true).Build();
std::unique_ptr<FakeWebFrameScheduler> frame8 =
FakeWebFrameScheduler::Builder()
.SetWebViewScheduler(view2.get())
.SetFrameType(WebFrameScheduler::FrameType::kMainFrame)
.Build();
DCHECK_EQ(GetFrameType(frame8.get()),
FrameType::kMainFrameBackgroundExemptOther);
}
TEST_F(RendererMetricsHelperTest, BackgroundedRendererTransition) {
scheduler_->SetStoppingWhenBackgroundedEnabled(true);
scheduler_->SetRendererBackgrounded(true);
typedef BackgroundedRendererTransition Transition;
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.BackgroundedRendererTransition"),
UnorderedElementsAre(
Bucket(static_cast<int>(Transition::kBackgrounded), 1)));
scheduler_->SetRendererBackgrounded(false);
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.BackgroundedRendererTransition"),
UnorderedElementsAre(
Bucket(static_cast<int>(Transition::kBackgrounded), 1),
Bucket(static_cast<int>(Transition::kForegrounded), 1)));
scheduler_->SetRendererBackgrounded(true);
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.BackgroundedRendererTransition"),
UnorderedElementsAre(
Bucket(static_cast<int>(Transition::kBackgrounded), 2),
Bucket(static_cast<int>(Transition::kForegrounded), 1)));
// Waste 5+ minutes so that the delayed stop is triggered
RunTask(QueueType::kDefault, Milliseconds(1),
base::TimeDelta::FromSeconds(5 * 61));
// Firing ForceUpdatePolicy multiple times to make sure that the metric is
// only recorded upon an actual change.
ForceUpdatePolicy();
ForceUpdatePolicy();
ForceUpdatePolicy();
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.BackgroundedRendererTransition"),
UnorderedElementsAre(
Bucket(static_cast<int>(Transition::kBackgrounded), 2),
Bucket(static_cast<int>(Transition::kForegrounded), 1),
Bucket(static_cast<int>(Transition::kStoppedAfterDelay), 1)));
scheduler_->SetRendererBackgrounded(false);
ForceUpdatePolicy();
ForceUpdatePolicy();
EXPECT_THAT(histogram_tester_->GetAllSamples(
"RendererScheduler.BackgroundedRendererTransition"),
UnorderedElementsAre(
Bucket(static_cast<int>(Transition::kBackgrounded), 2),
Bucket(static_cast<int>(Transition::kForegrounded), 2),
Bucket(static_cast<int>(Transition::kStoppedAfterDelay), 1),
Bucket(static_cast<int>(Transition::kResumed), 1)));
}
// TODO(crbug.com/754656): Add tests for NthMinute and AfterNthMinute
// histograms.
// TODO(crbug.com/754656): Add tests for TaskDuration.Hidden/Visible histograms.
// TODO(crbug.com/754656): Add tests for non-TaskDuration histograms.
} // namespace scheduler
} // namespace blink