1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h"
6 
7 #include <memory>
8 #include "base/macros.h"
9 #include "base/task/sequence_manager/test/fake_task.h"
10 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
11 #include "base/test/metrics/histogram_tester.h"
12 #include "base/test/scoped_feature_list.h"
13 #include "base/test/task_environment.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/blink/public/common/features.h"
17 #include "third_party/blink/public/common/page/launching_process_state.h"
18 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
19 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
20 #include "third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h"
21 #include "third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h"
22 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
23 
24 using base::sequence_manager::TaskQueue;
25 using base::sequence_manager::FakeTask;
26 using base::sequence_manager::FakeTaskTiming;
27 
28 namespace blink {
29 namespace scheduler {
30 
31 namespace {
32 class MainThreadSchedulerImplForTest : public MainThreadSchedulerImpl {
33  public:
MainThreadSchedulerImplForTest(std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,base::Optional<base::Time> initial_virtual_time)34   MainThreadSchedulerImplForTest(
35       std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,
36       base::Optional<base::Time> initial_virtual_time)
37       : MainThreadSchedulerImpl(std::move(sequence_manager),
38                                 initial_virtual_time) {}
39 
40   using MainThreadSchedulerImpl::SetCurrentUseCaseForTest;
41 };
42 }  // namespace
43 
44 using QueueType = MainThreadTaskQueue::QueueType;
45 using base::Bucket;
46 using testing::ElementsAre;
47 using testing::UnorderedElementsAre;
48 
49 class MainThreadMetricsHelperTest : public testing::Test {
50  public:
MainThreadMetricsHelperTest()51   MainThreadMetricsHelperTest()
52       : task_environment_(
53             base::test::TaskEnvironment::TimeSource::MOCK_TIME,
54             base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
55 
56   ~MainThreadMetricsHelperTest() override = default;
57 
SetUp()58   void SetUp() override {
59     scoped_feature_list_.InitWithFeatures(
60         {} /* enabled_features */,
61         {features::
62              kPurgeRendererMemoryWhenBackgrounded} /* disabled_features */);
63     histogram_tester_.reset(new base::HistogramTester());
64     scheduler_ = std::make_unique<MainThreadSchedulerImplForTest>(
65         base::sequence_manager::SequenceManagerForTest::Create(
66             nullptr, task_environment_.GetMainThreadTaskRunner(),
67             task_environment_.GetMockTickClock()),
68         base::nullopt);
69     metrics_helper_ = &scheduler_->main_thread_only().metrics_helper;
70   }
71 
TearDown()72   void TearDown() override {
73     scheduler_->Shutdown();
74     scheduler_.reset();
75   }
76 
Now()77   base::TimeTicks Now() {
78     return task_environment_.GetMockTickClock()->NowTicks();
79   }
80 
FastForwardTo(base::TimeTicks time)81   void FastForwardTo(base::TimeTicks time) {
82     CHECK_LE(Now(), time);
83     task_environment_.FastForwardBy(time - Now());
84   }
85 
RunTask(MainThreadTaskQueue::QueueType queue_type,base::TimeTicks start,base::TimeDelta duration)86   void RunTask(MainThreadTaskQueue::QueueType queue_type,
87                base::TimeTicks start,
88                base::TimeDelta duration) {
89     DCHECK_LE(Now(), start);
90     FastForwardTo(start + duration);
91     scoped_refptr<MainThreadTaskQueueForTest> queue;
92     if (queue_type != MainThreadTaskQueue::QueueType::kDetached) {
93       queue = scoped_refptr<MainThreadTaskQueueForTest>(
94           new MainThreadTaskQueueForTest(queue_type));
95     }
96 
97     metrics_helper_->RecordTaskMetrics(queue.get(), FakeTask(),
98                                        FakeTaskTiming(start, start + duration));
99   }
100 
RunTask(FrameSchedulerImpl * scheduler,base::TimeTicks start,base::TimeDelta duration)101   void RunTask(FrameSchedulerImpl* scheduler,
102                base::TimeTicks start,
103                base::TimeDelta duration) {
104     DCHECK_LE(Now(), start);
105     FastForwardTo(start + duration);
106     scoped_refptr<MainThreadTaskQueueForTest> queue(
107         new MainThreadTaskQueueForTest(QueueType::kDefault));
108     queue->SetFrameSchedulerForTest(scheduler);
109     metrics_helper_->RecordTaskMetrics(queue.get(), FakeTask(),
110                                        FakeTaskTiming(start, start + duration));
111   }
112 
RunTask(UseCase use_case,base::TimeTicks start,base::TimeDelta duration)113   void RunTask(UseCase use_case,
114                base::TimeTicks start,
115                base::TimeDelta duration) {
116     DCHECK_LE(Now(), start);
117     FastForwardTo(start + duration);
118     scoped_refptr<MainThreadTaskQueueForTest> queue(
119         new MainThreadTaskQueueForTest(QueueType::kDefault));
120     scheduler_->SetCurrentUseCaseForTest(use_case);
121     metrics_helper_->RecordTaskMetrics(queue.get(), FakeTask(),
122                                        FakeTaskTiming(start, start + duration));
123   }
124 
ForceUpdatePolicy()125   void ForceUpdatePolicy() { scheduler_->ForceUpdatePolicy(); }
126 
CreateFakeFrameSchedulerWithType(FrameStatus frame_status)127   std::unique_ptr<FakeFrameScheduler> CreateFakeFrameSchedulerWithType(
128       FrameStatus frame_status) {
129     FakeFrameScheduler::Builder builder;
130     switch (frame_status) {
131       case FrameStatus::kNone:
132       case FrameStatus::kDetached:
133         return nullptr;
134       case FrameStatus::kMainFrameVisible:
135         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
136             .SetIsPageVisible(true)
137             .SetIsFrameVisible(true);
138         break;
139       case FrameStatus::kMainFrameVisibleService:
140         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
141             .SetPageScheduler(playing_view_.get())
142             .SetIsFrameVisible(true);
143         break;
144       case FrameStatus::kMainFrameHidden:
145         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
146             .SetIsPageVisible(true);
147         break;
148       case FrameStatus::kMainFrameHiddenService:
149         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
150             .SetPageScheduler(playing_view_.get());
151         break;
152       case FrameStatus::kMainFrameBackground:
153         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame);
154         break;
155       case FrameStatus::kMainFrameBackgroundExemptSelf:
156         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
157             .SetIsExemptFromThrottling(true);
158         break;
159       case FrameStatus::kMainFrameBackgroundExemptOther:
160         builder.SetFrameType(FrameScheduler::FrameType::kMainFrame)
161             .SetPageScheduler(throtting_exempt_view_.get());
162         break;
163       case FrameStatus::kSameOriginVisible:
164         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
165             .SetIsPageVisible(true)
166             .SetIsFrameVisible(true);
167         break;
168       case FrameStatus::kSameOriginVisibleService:
169         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
170             .SetPageScheduler(playing_view_.get())
171             .SetIsFrameVisible(true);
172         break;
173       case FrameStatus::kSameOriginHidden:
174         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
175             .SetIsPageVisible(true);
176         break;
177       case FrameStatus::kSameOriginHiddenService:
178         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
179             .SetPageScheduler(playing_view_.get());
180         break;
181       case FrameStatus::kSameOriginBackground:
182         builder.SetFrameType(FrameScheduler::FrameType::kSubframe);
183         break;
184       case FrameStatus::kSameOriginBackgroundExemptSelf:
185         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
186             .SetIsExemptFromThrottling(true);
187         break;
188       case FrameStatus::kSameOriginBackgroundExemptOther:
189         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
190             .SetPageScheduler(throtting_exempt_view_.get());
191         break;
192       case FrameStatus::kCrossOriginVisible:
193         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
194             .SetIsCrossOriginToMainFrame(true)
195             .SetIsPageVisible(true)
196             .SetIsFrameVisible(true);
197         break;
198       case FrameStatus::kCrossOriginVisibleService:
199         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
200             .SetIsCrossOriginToMainFrame(true)
201             .SetPageScheduler(playing_view_.get())
202             .SetIsFrameVisible(true);
203         break;
204       case FrameStatus::kCrossOriginHidden:
205         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
206             .SetIsCrossOriginToMainFrame(true)
207             .SetIsPageVisible(true);
208         break;
209       case FrameStatus::kCrossOriginHiddenService:
210         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
211             .SetIsCrossOriginToMainFrame(true)
212             .SetPageScheduler(playing_view_.get());
213         break;
214       case FrameStatus::kCrossOriginBackground:
215         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
216             .SetIsCrossOriginToMainFrame(true);
217         break;
218       case FrameStatus::kCrossOriginBackgroundExemptSelf:
219         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
220             .SetIsCrossOriginToMainFrame(true)
221             .SetIsExemptFromThrottling(true);
222         break;
223       case FrameStatus::kCrossOriginBackgroundExemptOther:
224         builder.SetFrameType(FrameScheduler::FrameType::kSubframe)
225             .SetIsCrossOriginToMainFrame(true)
226             .SetPageScheduler(throtting_exempt_view_.get());
227         break;
228       case FrameStatus::kCount:
229         NOTREACHED();
230         return nullptr;
231     }
232     return builder.Build();
233   }
234 
235   base::test::ScopedFeatureList scoped_feature_list_;
236   base::test::TaskEnvironment task_environment_;
237   std::unique_ptr<MainThreadSchedulerImplForTest> scheduler_;
238   MainThreadMetricsHelper* metrics_helper_;  // NOT OWNED
239   std::unique_ptr<base::HistogramTester> histogram_tester_;
240   std::unique_ptr<FakePageScheduler> playing_view_ =
241       FakePageScheduler::Builder().SetIsAudioPlaying(true).Build();
242   std::unique_ptr<FakePageScheduler> throtting_exempt_view_ =
243       FakePageScheduler::Builder().SetIsThrottlingExempt(true).Build();
244 
245   DISALLOW_COPY_AND_ASSIGN(MainThreadMetricsHelperTest);
246 };
247 
TEST_F(MainThreadMetricsHelperTest,Metrics_PerQueueType)248 TEST_F(MainThreadMetricsHelperTest, Metrics_PerQueueType) {
249   // QueueType::kDefault is checking sub-millisecond task aggregation,
250   // FRAME_* tasks are checking normal task aggregation and other
251   // queue types have a single task.
252 
253   // Make sure that it starts in a foregrounded state.
254   if (kLaunchingProcessIsBackgrounded)
255     scheduler_->SetRendererBackgrounded(false);
256 
257   const base::TimeTicks start = Now();
258 
259   RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(1),
260           base::TimeDelta::FromMilliseconds(700));
261   RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(2),
262           base::TimeDelta::FromMilliseconds(700));
263   RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(3),
264           base::TimeDelta::FromMilliseconds(700));
265 
266   RunTask(QueueType::kControl, start + base::TimeDelta::FromSeconds(4),
267           base::TimeDelta::FromSeconds(3));
268   RunTask(QueueType::kFrameLoading, start + base::TimeDelta::FromSeconds(8),
269           base::TimeDelta::FromSeconds(6));
270   RunTask(QueueType::kFramePausable, start + base::TimeDelta::FromSeconds(16),
271           base::TimeDelta::FromSeconds(2));
272   RunTask(QueueType::kCompositor, start + base::TimeDelta::FromSeconds(19),
273           base::TimeDelta::FromSeconds(2));
274   RunTask(QueueType::kTest, start + base::TimeDelta::FromSeconds(22),
275           base::TimeDelta::FromSeconds(4));
276 
277   scheduler_->SetRendererBackgrounded(true);
278   // Wait for internally triggered tasks to run.
279   constexpr int kCoolingOfTimeSeconds = 10;
280 
281   RunTask(QueueType::kControl,
282           start + base::TimeDelta::FromSeconds(26 + kCoolingOfTimeSeconds),
283           base::TimeDelta::FromSeconds(2));
284   RunTask(QueueType::kFrameThrottleable,
285           start + base::TimeDelta::FromSeconds(28 + kCoolingOfTimeSeconds),
286           base::TimeDelta::FromSeconds(8));
287   RunTask(QueueType::kUnthrottled,
288           start + base::TimeDelta::FromSeconds(38 + kCoolingOfTimeSeconds),
289           base::TimeDelta::FromSeconds(5));
290   RunTask(QueueType::kFrameLoading,
291           start + base::TimeDelta::FromSeconds(45 + kCoolingOfTimeSeconds),
292           base::TimeDelta::FromSeconds(10));
293   RunTask(QueueType::kFrameThrottleable,
294           start + base::TimeDelta::FromSeconds(60 + kCoolingOfTimeSeconds),
295           base::TimeDelta::FromSeconds(5));
296   RunTask(QueueType::kCompositor,
297           start + base::TimeDelta::FromSeconds(70 + kCoolingOfTimeSeconds),
298           base::TimeDelta::FromSeconds(20));
299   RunTask(QueueType::kIdle,
300           start + base::TimeDelta::FromSeconds(90 + kCoolingOfTimeSeconds),
301           base::TimeDelta::FromSeconds(5));
302   RunTask(QueueType::kFrameLoadingControl,
303           start + base::TimeDelta::FromSeconds(100 + kCoolingOfTimeSeconds),
304           base::TimeDelta::FromSeconds(5));
305   RunTask(QueueType::kControl,
306           start + base::TimeDelta::FromSeconds(106 + kCoolingOfTimeSeconds),
307           base::TimeDelta::FromSeconds(6));
308   RunTask(QueueType::kFrameThrottleable,
309           start + base::TimeDelta::FromSeconds(114 + kCoolingOfTimeSeconds),
310           base::TimeDelta::FromSeconds(6));
311   RunTask(QueueType::kFramePausable,
312           start + base::TimeDelta::FromSeconds(120 + kCoolingOfTimeSeconds),
313           base::TimeDelta::FromSeconds(17));
314   RunTask(QueueType::kIdle,
315           start + base::TimeDelta::FromSeconds(140 + kCoolingOfTimeSeconds),
316           base::TimeDelta::FromSeconds(15));
317 
318   RunTask(QueueType::kDetached,
319           start + base::TimeDelta::FromSeconds(156 + kCoolingOfTimeSeconds),
320           base::TimeDelta::FromSeconds(2));
321 
322   std::vector<base::Bucket> expected_samples = {
323       {static_cast<int>(QueueType::kControl), 11},
324       {static_cast<int>(QueueType::kDefault), 2},
325       {static_cast<int>(QueueType::kUnthrottled), 5},
326       {static_cast<int>(QueueType::kFrameLoading), 16},
327       {static_cast<int>(QueueType::kCompositor), 22},
328       {static_cast<int>(QueueType::kIdle), 20},
329       {static_cast<int>(QueueType::kTest), 4},
330       {static_cast<int>(QueueType::kFrameLoadingControl), 5},
331       {static_cast<int>(QueueType::kFrameThrottleable), 19},
332       {static_cast<int>(QueueType::kFramePausable), 19},
333       {static_cast<int>(QueueType::kDetached), 2},
334   };
335   EXPECT_THAT(histogram_tester_->GetAllSamples(
336                   "RendererScheduler.TaskDurationPerQueueType3"),
337               testing::ContainerEq(expected_samples));
338 
339   EXPECT_THAT(histogram_tester_->GetAllSamples(
340                   "RendererScheduler.TaskDurationPerQueueType3.Foreground"),
341               UnorderedElementsAre(
342                   Bucket(static_cast<int>(QueueType::kControl), 3),
343                   Bucket(static_cast<int>(QueueType::kDefault), 2),
344                   Bucket(static_cast<int>(QueueType::kFrameLoading), 6),
345                   Bucket(static_cast<int>(QueueType::kCompositor), 2),
346                   Bucket(static_cast<int>(QueueType::kTest), 4),
347                   Bucket(static_cast<int>(QueueType::kFramePausable), 2)));
348 
349   EXPECT_THAT(histogram_tester_->GetAllSamples(
350                   "RendererScheduler.TaskDurationPerQueueType3.Background"),
351               UnorderedElementsAre(
352                   Bucket(static_cast<int>(QueueType::kControl), 8),
353                   Bucket(static_cast<int>(QueueType::kUnthrottled), 5),
354                   Bucket(static_cast<int>(QueueType::kFrameLoading), 10),
355                   Bucket(static_cast<int>(QueueType::kFrameThrottleable), 19),
356                   Bucket(static_cast<int>(QueueType::kFramePausable), 17),
357                   Bucket(static_cast<int>(QueueType::kCompositor), 20),
358                   Bucket(static_cast<int>(QueueType::kIdle), 20),
359                   Bucket(static_cast<int>(QueueType::kFrameLoadingControl), 5),
360                   Bucket(static_cast<int>(QueueType::kDetached), 2)));
361 }
362 
TEST_F(MainThreadMetricsHelperTest,Metrics_PerUseCase)363 TEST_F(MainThreadMetricsHelperTest, Metrics_PerUseCase) {
364   const base::TimeTicks start = Now();
365 
366   RunTask(UseCase::kNone, start + base::TimeDelta::FromMilliseconds(500),
367           base::TimeDelta::FromMilliseconds(400));
368 
369   RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(1),
370           base::TimeDelta::FromSeconds(2));
371   RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(3),
372           base::TimeDelta::FromMilliseconds(300));
373   RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(4),
374           base::TimeDelta::FromMilliseconds(300));
375 
376   RunTask(UseCase::kCompositorGesture, start + base::TimeDelta::FromSeconds(5),
377           base::TimeDelta::FromSeconds(5));
378   RunTask(UseCase::kCompositorGesture, start + base::TimeDelta::FromSeconds(10),
379           base::TimeDelta::FromSeconds(3));
380 
381   RunTask(UseCase::kMainThreadCustomInputHandling,
382           start + base::TimeDelta::FromSeconds(14),
383           base::TimeDelta::FromSeconds(2));
384   RunTask(UseCase::kSynchronizedGesture,
385           start + base::TimeDelta::FromSeconds(17),
386           base::TimeDelta::FromSeconds(2));
387   RunTask(UseCase::kMainThreadCustomInputHandling,
388           start + base::TimeDelta::FromSeconds(19),
389           base::TimeDelta::FromSeconds(5));
390   RunTask(UseCase::kLoading, start + base::TimeDelta::FromSeconds(25),
391           base::TimeDelta::FromSeconds(6));
392   RunTask(UseCase::kMainThreadGesture, start + base::TimeDelta::FromSeconds(31),
393           base::TimeDelta::FromSeconds(6));
394   EXPECT_THAT(
395       histogram_tester_->GetAllSamples(
396           "RendererScheduler.TaskDurationPerUseCase2"),
397       UnorderedElementsAre(
398           Bucket(static_cast<int>(UseCase::kTouchstart), 3),
399           Bucket(static_cast<int>(UseCase::kCompositorGesture), 8),
400           Bucket(static_cast<int>(UseCase::kMainThreadCustomInputHandling), 7),
401           Bucket(static_cast<int>(UseCase::kSynchronizedGesture), 2),
402           Bucket(static_cast<int>(UseCase::kLoading), 6),
403           Bucket(static_cast<int>(UseCase::kMainThreadGesture), 6)));
404 }
405 
TEST_F(MainThreadMetricsHelperTest,GetFrameStatusTest)406 TEST_F(MainThreadMetricsHelperTest, GetFrameStatusTest) {
407   DCHECK_EQ(GetFrameStatus(nullptr), FrameStatus::kNone);
408 
409   FrameStatus frame_statuses_tested[] = {
410       FrameStatus::kMainFrameVisible,
411       FrameStatus::kSameOriginHidden,
412       FrameStatus::kCrossOriginHidden,
413       FrameStatus::kSameOriginBackground,
414       FrameStatus::kMainFrameBackgroundExemptSelf,
415       FrameStatus::kSameOriginVisibleService,
416       FrameStatus::kCrossOriginHiddenService,
417       FrameStatus::kMainFrameBackgroundExemptOther};
418   for (FrameStatus frame_status : frame_statuses_tested) {
419     std::unique_ptr<FakeFrameScheduler> frame =
420         CreateFakeFrameSchedulerWithType(frame_status);
421     EXPECT_EQ(GetFrameStatus(frame.get()), frame_status);
422   }
423 }
424 
TEST_F(MainThreadMetricsHelperTest,TaskCountPerFrameStatus)425 TEST_F(MainThreadMetricsHelperTest, TaskCountPerFrameStatus) {
426   int task_count = 0;
427   struct CountPerFrameStatus {
428     FrameStatus frame_status;
429     int count;
430   };
431   CountPerFrameStatus test_data[] = {
432       {FrameStatus::kNone, 4},
433       {FrameStatus::kMainFrameVisible, 8},
434       {FrameStatus::kMainFrameBackgroundExemptSelf, 5},
435       {FrameStatus::kCrossOriginHidden, 3},
436       {FrameStatus::kCrossOriginHiddenService, 7},
437       {FrameStatus::kCrossOriginVisible, 1},
438       {FrameStatus::kMainFrameBackgroundExemptOther, 2},
439       {FrameStatus::kSameOriginVisible, 10},
440       {FrameStatus::kSameOriginBackground, 9},
441       {FrameStatus::kSameOriginVisibleService, 6}};
442 
443   const base::TimeTicks start = Now();
444 
445   for (const auto& data : test_data) {
446     std::unique_ptr<FakeFrameScheduler> frame =
447         CreateFakeFrameSchedulerWithType(data.frame_status);
448     for (int i = 0; i < data.count; ++i) {
449       RunTask(frame.get(),
450               start + base::TimeDelta::FromMilliseconds(++task_count),
451               base::TimeDelta::FromMicroseconds(100));
452     }
453   }
454 
455   EXPECT_THAT(
456       histogram_tester_->GetAllSamples(
457           "RendererScheduler.TaskCountPerFrameType"),
458       UnorderedElementsAre(
459           Bucket(static_cast<int>(FrameStatus::kNone), 4),
460           Bucket(static_cast<int>(FrameStatus::kMainFrameVisible), 8),
461           Bucket(static_cast<int>(FrameStatus::kMainFrameBackgroundExemptSelf),
462                  5),
463           Bucket(static_cast<int>(FrameStatus::kMainFrameBackgroundExemptOther),
464                  2),
465           Bucket(static_cast<int>(FrameStatus::kSameOriginVisible), 10),
466           Bucket(static_cast<int>(FrameStatus::kSameOriginVisibleService), 6),
467           Bucket(static_cast<int>(FrameStatus::kSameOriginBackground), 9),
468           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisible), 1),
469           Bucket(static_cast<int>(FrameStatus::kCrossOriginHidden), 3),
470           Bucket(static_cast<int>(FrameStatus::kCrossOriginHiddenService), 7)));
471 }
472 
TEST_F(MainThreadMetricsHelperTest,TaskCountPerFrameTypeLongerThan)473 TEST_F(MainThreadMetricsHelperTest, TaskCountPerFrameTypeLongerThan) {
474   int total_duration = 0;
475   struct TasksPerFrameStatus {
476     FrameStatus frame_status;
477     Vector<int> durations;
478   };
479   TasksPerFrameStatus test_data[] = {
480       {FrameStatus::kSameOriginHidden,
481        {2, 15, 16, 20, 25, 30, 49, 50, 73, 99, 100, 110, 140, 150, 800, 1000,
482         1200}},
483       {FrameStatus::kCrossOriginVisibleService,
484        {5, 10, 18, 19, 20, 55, 75, 220}},
485       {FrameStatus::kMainFrameBackground,
486        {21, 31, 41, 51, 61, 71, 81, 91, 101, 1001}},
487   };
488 
489   const base::TimeTicks start = Now();
490 
491   for (const auto& data : test_data) {
492     std::unique_ptr<FakeFrameScheduler> frame =
493         CreateFakeFrameSchedulerWithType(data.frame_status);
494     for (size_t i = 0; i < data.durations.size(); ++i) {
495       RunTask(frame.get(),
496               start + base::TimeDelta::FromMilliseconds(++total_duration),
497               base::TimeDelta::FromMilliseconds(data.durations[i]));
498       total_duration += data.durations[i];
499     }
500   }
501 
502   EXPECT_THAT(
503       histogram_tester_->GetAllSamples(
504           "RendererScheduler.TaskCountPerFrameType"),
505       UnorderedElementsAre(
506           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 10),
507           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 17),
508           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService),
509                  8)));
510 
511   EXPECT_THAT(
512       histogram_tester_->GetAllSamples(
513           "RendererScheduler.TaskCountPerFrameType."
514           "LongerThan16ms"),
515       UnorderedElementsAre(
516           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 10),
517           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 15),
518           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService),
519                  6)));
520 
521   EXPECT_THAT(
522       histogram_tester_->GetAllSamples(
523           "RendererScheduler.TaskCountPerFrameType."
524           "LongerThan50ms"),
525       UnorderedElementsAre(
526           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 7),
527           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 10),
528           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService),
529                  3)));
530 
531   EXPECT_THAT(
532       histogram_tester_->GetAllSamples(
533           "RendererScheduler.TaskCountPerFrameType."
534           "LongerThan100ms"),
535       UnorderedElementsAre(
536           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 2),
537           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 7),
538           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService),
539                  1)));
540 
541   EXPECT_THAT(
542       histogram_tester_->GetAllSamples(
543           "RendererScheduler.TaskCountPerFrameType."
544           "LongerThan150ms"),
545       UnorderedElementsAre(
546           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 1),
547           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 4),
548           Bucket(static_cast<int>(FrameStatus::kCrossOriginVisibleService),
549                  1)));
550 
551   EXPECT_THAT(
552       histogram_tester_->GetAllSamples(
553           "RendererScheduler.TaskCountPerFrameType.LongerThan1s"),
554       UnorderedElementsAre(
555           Bucket(static_cast<int>(FrameStatus::kMainFrameBackground), 1),
556           Bucket(static_cast<int>(FrameStatus::kSameOriginHidden), 2)));
557 }
558 
559 // TODO(crbug.com/754656): Add tests for NthMinute and
560 // AfterNthMinute histograms.
561 
562 // TODO(crbug.com/754656): Add tests for
563 // TaskDuration.Hidden/Visible histograms.
564 
565 // TODO(crbug.com/754656): Add tests for non-TaskDuration
566 // histograms.
567 
568 // TODO(crbug.com/754656): Add tests for
569 // RendererScheduler.TasksWithSafepoints histograms.
570 
571 }  // namespace scheduler
572 }  // namespace blink
573