diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc b/chromium/third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc new file mode 100644 index 00000000000..34f40ea9c16 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc @@ -0,0 +1,607 @@ +// 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 "third_party/blink/renderer/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 "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/page/launching_process_state.h" +#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" +#include "third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h" +#include "third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h" +#include "third_party/blink/renderer/platform/scheduler/test/task_queue_manager_for_test.h" + +namespace blink { +namespace scheduler { + +namespace { +class MainThreadSchedulerImplForTest : public MainThreadSchedulerImpl { + public: + MainThreadSchedulerImplForTest( + std::unique_ptr<TaskQueueManager> task_queue_manager, + base::Optional<base::Time> initial_virtual_time) + : MainThreadSchedulerImpl(std::move(task_queue_manager), + initial_virtual_time){}; + + using MainThreadSchedulerImpl::SetCurrentUseCaseForTest; +}; +} // namespace + +using QueueType = MainThreadTaskQueue::QueueType; +using base::Bucket; +using testing::ElementsAre; +using testing::UnorderedElementsAre; + +class RendererMetricsHelperTest : public testing::Test { + public: + RendererMetricsHelperTest() = default; + ~RendererMetricsHelperTest() = default; + + void SetUp() { + histogram_tester_.reset(new base::HistogramTester()); + mock_task_runner_ = + base::MakeRefCounted<cc::OrderedSimpleTaskRunner>(&clock_, true); + scheduler_ = std::make_unique<MainThreadSchedulerImplForTest>( + TaskQueueManagerForTest::Create(nullptr, mock_task_runner_, &clock_), + base::nullopt); + 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; + if (queue_type != MainThreadTaskQueue::QueueType::kDetached) { + queue = scoped_refptr<MainThreadTaskQueueForTest>( + new MainThreadTaskQueueForTest(queue_type)); + } + + // Pass an empty task for recording. + TaskQueue::PostedTask posted_task(base::OnceClosure(), FROM_HERE); + TaskQueue::Task task(std::move(posted_task), base::TimeTicks()); + metrics_helper_->RecordTaskMetrics(queue.get(), task, start, + start + duration, base::nullopt); + } + + void RunTask(FrameScheduler* scheduler, + base::TimeTicks start, + base::TimeDelta duration) { + DCHECK_LE(clock_.NowTicks(), start); + clock_.SetNowTicks(start + duration); + scoped_refptr<MainThreadTaskQueueForTest> queue( + new MainThreadTaskQueueForTest(QueueType::kDefault)); + queue->SetFrameScheduler(scheduler); + // Pass an empty task for recording. + TaskQueue::PostedTask posted_task(base::OnceClosure(), FROM_HERE); + TaskQueue::Task task(std::move(posted_task), base::TimeTicks()); + metrics_helper_->RecordTaskMetrics(queue.get(), task, start, + start + duration, base::nullopt); + } + + void RunTask(UseCase use_case, + base::TimeTicks start, + base::TimeDelta duration) { + DCHECK_LE(clock_.NowTicks(), start); + clock_.SetNowTicks(start + duration); + scoped_refptr<MainThreadTaskQueueForTest> queue( + new MainThreadTaskQueueForTest(QueueType::kDefault)); + scheduler_->SetCurrentUseCaseForTest(use_case); + // Pass an empty task for recording. + TaskQueue::PostedTask posted_task(base::OnceClosure(), FROM_HERE); + TaskQueue::Task task(std::move(posted_task), base::TimeTicks()); + metrics_helper_->RecordTaskMetrics(queue.get(), task, start, + start + duration, base::nullopt); + } + + base::TimeTicks Milliseconds(int milliseconds) { + return base::TimeTicks() + base::TimeDelta::FromMilliseconds(milliseconds); + } + + void ForceUpdatePolicy() { scheduler_->ForceUpdatePolicy(); } + + std::unique_ptr<FakeFrameScheduler> CreateFakeFrameSchedulerWithType( + FrameStatus frame_status) { + FakeFrameScheduler::Builder builder; + switch (frame_status) { + case FrameStatus::kNone: + case FrameStatus::kDetached: + return nullptr; + case FrameStatus::kMainFrameVisible: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetIsPageVisible(true) + .SetIsFrameVisible(true); + break; + case FrameStatus::kMainFrameVisibleService: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetPageScheduler(playing_view_.get()) + .SetIsFrameVisible(true); + break; + case FrameStatus::kMainFrameHidden: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetIsPageVisible(true); + break; + case FrameStatus::kMainFrameHiddenService: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetPageScheduler(playing_view_.get()); + break; + case FrameStatus::kMainFrameBackground: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame); + break; + case FrameStatus::kMainFrameBackgroundExemptSelf: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetIsExemptFromThrottling(true); + break; + case FrameStatus::kMainFrameBackgroundExemptOther: + builder.SetFrameType(FrameScheduler::FrameType::kMainFrame) + .SetPageScheduler(throtting_exempt_view_.get()); + break; + case FrameStatus::kSameOriginVisible: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsPageVisible(true) + .SetIsFrameVisible(true); + break; + case FrameStatus::kSameOriginVisibleService: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetPageScheduler(playing_view_.get()) + .SetIsFrameVisible(true); + break; + case FrameStatus::kSameOriginHidden: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsPageVisible(true); + break; + case FrameStatus::kSameOriginHiddenService: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetPageScheduler(playing_view_.get()); + break; + case FrameStatus::kSameOriginBackground: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe); + break; + case FrameStatus::kSameOriginBackgroundExemptSelf: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsExemptFromThrottling(true); + break; + case FrameStatus::kSameOriginBackgroundExemptOther: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetPageScheduler(throtting_exempt_view_.get()); + break; + case FrameStatus::kCrossOriginVisible: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetIsPageVisible(true) + .SetIsFrameVisible(true); + break; + case FrameStatus::kCrossOriginVisibleService: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetPageScheduler(playing_view_.get()) + .SetIsFrameVisible(true); + break; + case FrameStatus::kCrossOriginHidden: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetIsPageVisible(true); + break; + case FrameStatus::kCrossOriginHiddenService: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetPageScheduler(playing_view_.get()); + break; + case FrameStatus::kCrossOriginBackground: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true); + break; + case FrameStatus::kCrossOriginBackgroundExemptSelf: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetIsExemptFromThrottling(true); + break; + case FrameStatus::kCrossOriginBackgroundExemptOther: + builder.SetFrameType(FrameScheduler::FrameType::kSubframe) + .SetIsCrossOrigin(true) + .SetPageScheduler(throtting_exempt_view_.get()); + break; + case FrameStatus::kCount: + NOTREACHED(); + return nullptr; + } + return builder.Build(); + } + + base::SimpleTestTickClock clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + std::unique_ptr<MainThreadSchedulerImplForTest> scheduler_; + RendererMetricsHelper* metrics_helper_; // NOT OWNED + std::unique_ptr<base::HistogramTester> histogram_tester_; + std::unique_ptr<FakePageScheduler> playing_view_ = + FakePageScheduler::Builder().SetIsPlayingAudio(true).Build(); + std::unique_ptr<FakePageScheduler> throtting_exempt_view_ = + FakePageScheduler::Builder().SetIsThrottlingExempt(true).Build(); + + DISALLOW_COPY_AND_ASSIGN(RendererMetricsHelperTest); +}; + +TEST_F(RendererMetricsHelperTest, Metrics_PerQueueType) { + // QueueType::kDefault is checking sub-millisecond task aggregation, + // FRAME_* tasks are checking normal task aggregation and other + // queue types have a single task. + + // Make sure that it starts in a foregrounded state. + if (kLaunchingProcessIsBackgrounded) + scheduler_->SetRendererBackgrounded(false); + + 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::kControl, Milliseconds(400), + base::TimeDelta::FromMilliseconds(30)); + 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::kFrameLoadingControl, 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)); + + RunTask(QueueType::kDetached, Milliseconds(8000), + base::TimeDelta::FromMilliseconds(150)); + + std::vector<base::Bucket> expected_samples = { + {static_cast<int>(QueueType::kControl), 75}, + {static_cast<int>(QueueType::kDefault), 2}, + {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::kFrameLoadingControl), 5}, + {static_cast<int>(QueueType::kFrameThrottleable), 295}, + {static_cast<int>(QueueType::kFramePausable), 195}, + {static_cast<int>(QueueType::kDetached), 150}, + }; + 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::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::kFrameLoadingControl), 5), + Bucket(static_cast<int>(QueueType::kDetached), 150))); +} + +TEST_F(RendererMetricsHelperTest, Metrics_PerUseCase) { + RunTask(UseCase::kNone, Milliseconds(500), + base::TimeDelta::FromMilliseconds(4000)); + + RunTask(UseCase::kTouchstart, Milliseconds(7000), + base::TimeDelta::FromMilliseconds(25)); + RunTask(UseCase::kTouchstart, Milliseconds(7050), + base::TimeDelta::FromMilliseconds(25)); + RunTask(UseCase::kTouchstart, Milliseconds(7100), + base::TimeDelta::FromMilliseconds(25)); + + RunTask(UseCase::kCompositorGesture, Milliseconds(7150), + base::TimeDelta::FromMilliseconds(5)); + RunTask(UseCase::kCompositorGesture, Milliseconds(7200), + base::TimeDelta::FromMilliseconds(30)); + + RunTask(UseCase::kMainThreadCustomInputHandling, Milliseconds(7300), + base::TimeDelta::FromMilliseconds(2)); + RunTask(UseCase::kSynchronizedGesture, Milliseconds(7400), + base::TimeDelta::FromMilliseconds(250)); + RunTask(UseCase::kMainThreadCustomInputHandling, Milliseconds(7700), + base::TimeDelta::FromMilliseconds(150)); + RunTask(UseCase::kLoading, Milliseconds(7900), + base::TimeDelta::FromMilliseconds(50)); + RunTask(UseCase::kMainThreadGesture, Milliseconds(8000), + base::TimeDelta::FromMilliseconds(60)); + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskDurationPerUseCase"), + UnorderedElementsAre( + Bucket(static_cast<int>(UseCase::kNone), 4000), + Bucket(static_cast<int>(UseCase::kCompositorGesture), 35), + Bucket(static_cast<int>(UseCase::kMainThreadCustomInputHandling), + 152), + Bucket(static_cast<int>(UseCase::kSynchronizedGesture), 250), + Bucket(static_cast<int>(UseCase::kTouchstart), 75), + Bucket(static_cast<int>(UseCase::kLoading), 50), + Bucket(static_cast<int>(UseCase::kMainThreadGesture), 60))); +} + +TEST_F(RendererMetricsHelperTest, GetFrameStatusTest) { + DCHECK_EQ(GetFrameStatus(nullptr), FrameStatus::kNone); + + FrameStatus frame_statuses_tested[] = { + FrameStatus::kMainFrameVisible, + FrameStatus::kSameOriginHidden, + FrameStatus::kCrossOriginHidden, + FrameStatus::kSameOriginBackground, + FrameStatus::kMainFrameBackgroundExemptSelf, + FrameStatus::kSameOriginVisibleService, + FrameStatus::kCrossOriginHiddenService, + FrameStatus::kMainFrameBackgroundExemptOther}; + for (FrameStatus frame_status : frame_statuses_tested) { + std::unique_ptr<FakeFrameScheduler> frame = + CreateFakeFrameSchedulerWithType(frame_status); + EXPECT_EQ(GetFrameStatus(frame.get()), frame_status); + } +} + +TEST_F(RendererMetricsHelperTest, BackgroundedRendererTransition) { + scheduler_->SetStoppingWhenBackgroundedEnabled(true); + typedef BackgroundedRendererTransition Transition; + + int backgrounding_transitions = 0; + int foregrounding_transitions = 0; + if (!kLaunchingProcessIsBackgrounded) { + scheduler_->SetRendererBackgrounded(true); + backgrounding_transitions++; + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.BackgroundedRendererTransition"), + UnorderedElementsAre(Bucket(static_cast<int>(Transition::kBackgrounded), + backgrounding_transitions))); + scheduler_->SetRendererBackgrounded(false); + foregrounding_transitions++; + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.BackgroundedRendererTransition"), + UnorderedElementsAre(Bucket(static_cast<int>(Transition::kBackgrounded), + backgrounding_transitions), + Bucket(static_cast<int>(Transition::kForegrounded), + foregrounding_transitions))); + } else { + scheduler_->SetRendererBackgrounded(false); + foregrounding_transitions++; + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.BackgroundedRendererTransition"), + UnorderedElementsAre(Bucket(static_cast<int>(Transition::kForegrounded), + foregrounding_transitions))); + } + + scheduler_->SetRendererBackgrounded(true); + backgrounding_transitions++; + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.BackgroundedRendererTransition"), + UnorderedElementsAre(Bucket(static_cast<int>(Transition::kBackgrounded), + backgrounding_transitions), + Bucket(static_cast<int>(Transition::kForegrounded), + foregrounding_transitions))); + + // 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), + backgrounding_transitions), + Bucket(static_cast<int>(Transition::kForegrounded), + foregrounding_transitions), + Bucket(static_cast<int>(Transition::kStoppedAfterDelay), 1))); + + scheduler_->SetRendererBackgrounded(false); + foregrounding_transitions++; + ForceUpdatePolicy(); + ForceUpdatePolicy(); + EXPECT_THAT(histogram_tester_->GetAllSamples( + "RendererScheduler.BackgroundedRendererTransition"), + UnorderedElementsAre( + Bucket(static_cast<int>(Transition::kBackgrounded), + backgrounding_transitions), + Bucket(static_cast<int>(Transition::kForegrounded), + foregrounding_transitions), + Bucket(static_cast<int>(Transition::kStoppedAfterDelay), 1), + Bucket(static_cast<int>(Transition::kResumed), 1))); +} + +TEST_F(RendererMetricsHelperTest, TaskCountPerFrameStatus) { + int task_count = 0; + struct CountPerFrameStatus { + FrameStatus frame_status; + int count; + }; + CountPerFrameStatus test_data[] = { + {FrameStatus::kNone, 4}, + {FrameStatus::kMainFrameVisible, 8}, + {FrameStatus::kMainFrameBackgroundExemptSelf, 5}, + {FrameStatus::kCrossOriginHidden, 3}, + {FrameStatus::kCrossOriginHiddenService, 7}, + {FrameStatus::kCrossOriginVisible, 1}, + {FrameStatus::kMainFrameBackgroundExemptOther, 2}, + {FrameStatus::kSameOriginVisible, 10}, + {FrameStatus::kSameOriginBackground, 9}, + {FrameStatus::kSameOriginVisibleService, 6}}; + + for (const auto& data : test_data) { + std::unique_ptr<FakeFrameScheduler> frame = + CreateFakeFrameSchedulerWithType(data.frame_status); + for (int i = 0; i < data.count; ++i) { + RunTask(frame.get(), Milliseconds(++task_count), + base::TimeDelta::FromMicroseconds(100)); + } + } + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kNone), 4), + Bucket(static_cast<int>(FrameStatus::kMainFrameVisible), 8), + Bucket(static_cast<int>(FrameStatus::kMainFrameBackgroundExemptSelf), + 5), + Bucket(static_cast<int>(FrameStatus::kMainFrameBackgroundExemptOther), + 2), + Bucket(static_cast<int>(FrameStatus::kSameOriginVisible), 10), + Bucket(static_cast<int>(FrameStatus::kSameOriginVisibleService), 6), + Bucket(static_cast<int>(FrameStatus::kSameOriginBackground), 9), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisible), 1), + Bucket(static_cast<int>(FrameStatus::kCrossOriginHidden), 3), + Bucket(static_cast<int>(FrameStatus::kCrossOriginHiddenService), 7))); +} + +TEST_F(RendererMetricsHelperTest, TaskCountPerFrameTypeLongerThan) { + int total_duration = 0; + struct TasksPerFrameStatus { + FrameStatus frame_status; + std::vector<int> durations; + }; + TasksPerFrameStatus test_data[] = { + {FrameStatus::kSameOriginHidden, + {2, 15, 16, 20, 25, 30, 49, 50, 73, 99, 100, 110, 140, 150, 800, 1000, + 1200}}, + {FrameStatus::kCrossOriginVisibleService, + {5, 10, 18, 19, 20, 55, 75, 220}}, + {FrameStatus::kMainFrameBackground, + {21, 31, 41, 51, 61, 71, 81, 91, 101, 1001}}, + }; + + for (const auto& data : test_data) { + std::unique_ptr<FakeFrameScheduler> frame = + CreateFakeFrameSchedulerWithType(data.frame_status); + for (size_t i = 0; i < data.durations.size(); ++i) { + RunTask(frame.get(), Milliseconds(++total_duration), + base::TimeDelta::FromMilliseconds(data.durations[i])); + total_duration += data.durations[i]; + } + } + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 10), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 17), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService), + 8))); + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType." + "LongerThan16ms"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 10), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 15), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService), + 6))); + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType." + "LongerThan50ms"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 7), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 10), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService), + 3))); + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType." + "LongerThan100ms"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 2), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 7), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService), + 1))); + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType." + "LongerThan150ms"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 1), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 4), + Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService), + 1))); + + EXPECT_THAT( + histogram_tester_->GetAllSamples( + "RendererScheduler.TaskCountPerFrameType.LongerThan1s"), + UnorderedElementsAre( + Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 1), + Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 2))); +} + +// 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 |