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