1 // Copyright 2018 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 "content/browser/scheduler/responsiveness/calculator.h"
6 
7 #include "build/build_config.h"
8 #include "content/public/test/browser_task_environment.h"
9 #include "testing/gmock/include/gmock/gmock.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace content {
13 namespace responsiveness {
14 
15 using JankType = Calculator::JankType;
16 using ::testing::_;
17 
18 namespace {
19 // Copied from calculator.cc.
20 constexpr int kMeasurementIntervalInMs = 30 * 1000;
21 constexpr int kJankThresholdInMs = 100;
22 
23 class FakeCalculator : public Calculator {
24  public:
25   MOCK_METHOD3(EmitResponsiveness,
26                void(JankType jank_type,
27                     size_t janky_slices,
28                     bool was_process_suspended));
29 
30   using Calculator::GetLastCalculationTime;
31 };
32 
33 }  // namespace
34 
35 class ResponsivenessCalculatorTest : public testing::Test {
36  public:
SetUp()37   void SetUp() override {
38     calculator_ = std::make_unique<testing::StrictMock<FakeCalculator>>();
39     last_calculation_time_ = calculator_->GetLastCalculationTime();
40 #if defined(OS_ANDROID)
41     base::android::ApplicationStatusListener::NotifyApplicationStateChange(
42         base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
43     base::RunLoop().RunUntilIdle();
44 #endif
45   }
46 
AddEventUI(int queue_time_in_ms,int execution_start_time_in_ms,int execution_finish_time_in_ms)47   void AddEventUI(int queue_time_in_ms,
48                   int execution_start_time_in_ms,
49                   int execution_finish_time_in_ms) {
50     calculator_->TaskOrEventFinishedOnUIThread(
51         last_calculation_time_ +
52             base::TimeDelta::FromMilliseconds(queue_time_in_ms),
53         last_calculation_time_ +
54             base::TimeDelta::FromMilliseconds(execution_start_time_in_ms),
55         last_calculation_time_ +
56             base::TimeDelta::FromMilliseconds(execution_finish_time_in_ms));
57   }
58 
AddEventIO(int queue_time_in_ms,int execution_start_time_in_ms,int execution_finish_time_in_ms)59   void AddEventIO(int queue_time_in_ms,
60                   int execution_start_time_in_ms,
61                   int execution_finish_time_in_ms) {
62     calculator_->TaskOrEventFinishedOnIOThread(
63         last_calculation_time_ +
64             base::TimeDelta::FromMilliseconds(queue_time_in_ms),
65         last_calculation_time_ +
66             base::TimeDelta::FromMilliseconds(execution_start_time_in_ms),
67         last_calculation_time_ +
68             base::TimeDelta::FromMilliseconds(execution_finish_time_in_ms));
69   }
70 
TriggerCalculation()71   void TriggerCalculation() {
72     AddEventUI(kMeasurementIntervalInMs + 1, kMeasurementIntervalInMs + 1,
73                kMeasurementIntervalInMs + 1);
74     last_calculation_time_ = calculator_->GetLastCalculationTime();
75   }
76 
77  protected:
78   // This member sets up BrowserThread::IO and BrowserThread::UI. It must be the
79   // first member, as other members may depend on these abstractions.
80   content::BrowserTaskEnvironment task_environment_;
81 
82   std::unique_ptr<FakeCalculator> calculator_;
83   base::TimeTicks last_calculation_time_;
84 };
85 
86 #define EXPECT_EXECUTION_JANKY_SLICES(num_slices) \
87   EXPECT_CALL(*calculator_,                       \
88               EmitResponsiveness(JankType::kExecution, num_slices, false));
89 #define EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(num_slices)                  \
90   EXPECT_CALL(*calculator_, EmitResponsiveness(JankType::kQueueAndExecution, \
91                                                num_slices, false));
92 
93 // A single event executing slightly longer than kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,ShortExecutionJank)94 TEST_F(ResponsivenessCalculatorTest, ShortExecutionJank) {
95   constexpr int kQueueTime = 35;
96   constexpr int kStartTime = 40;
97   constexpr int kFinishTime = kStartTime + kJankThresholdInMs + 5;
98 
99   AddEventUI(kQueueTime, kStartTime, kFinishTime);
100   EXPECT_EXECUTION_JANKY_SLICES(1u);
101   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
102   TriggerCalculation();
103 }
104 
105 // A single event queued slightly longer than kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,ShortQueueJank)106 TEST_F(ResponsivenessCalculatorTest, ShortQueueJank) {
107   constexpr int kQueueTime = 35;
108   constexpr int kStartTime = kQueueTime + kJankThresholdInMs + 5;
109   constexpr int kFinishTime = kStartTime + 5;
110 
111   AddEventUI(kQueueTime, kStartTime, kFinishTime);
112   EXPECT_EXECUTION_JANKY_SLICES(0u);
113   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
114   TriggerCalculation();
115 }
116 
117 // A single event whose queuing and execution time together take longer than
118 // kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,ShortCombinedQueueAndExecutionJank)119 TEST_F(ResponsivenessCalculatorTest, ShortCombinedQueueAndExecutionJank) {
120   constexpr int kQueueTime = 35;
121   constexpr int kStartTime = kQueueTime + (kJankThresholdInMs / 2);
122   constexpr int kFinishTime = kStartTime + (kJankThresholdInMs / 2) + 1;
123 
124   AddEventUI(kQueueTime, kStartTime, kFinishTime);
125   EXPECT_EXECUTION_JANKY_SLICES(0u);
126   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
127   TriggerCalculation();
128 }
129 
130 // A single event executing slightly longer than 10 * kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,LongExecutionJank)131 TEST_F(ResponsivenessCalculatorTest, LongExecutionJank) {
132   constexpr int kQueueTime = 35;
133   constexpr int kStartTime = 40;
134   constexpr int kFinishTime = kStartTime + 10 * kJankThresholdInMs + 5;
135 
136   AddEventUI(kQueueTime, kStartTime, kFinishTime);
137   EXPECT_EXECUTION_JANKY_SLICES(10u);
138   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(10u);
139   TriggerCalculation();
140 }
141 
142 // A single event executing slightly longer than 10 * kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,LongQueueJank)143 TEST_F(ResponsivenessCalculatorTest, LongQueueJank) {
144   constexpr int kQueueTime = 35;
145   constexpr int kStartTime = kQueueTime + 10 * kJankThresholdInMs + 5;
146   constexpr int kFinishTime = kStartTime + 5;
147 
148   AddEventUI(kQueueTime, kStartTime, kFinishTime);
149   EXPECT_EXECUTION_JANKY_SLICES(0u);
150   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(10u);
151   TriggerCalculation();
152 }
153 
154 // Events that execute in less than 100ms do not jank, regardless of start time.
TEST_F(ResponsivenessCalculatorTest,NoExecutionJank)155 TEST_F(ResponsivenessCalculatorTest, NoExecutionJank) {
156   int base_time = 30;
157   for (int i = 0; i < kJankThresholdInMs; ++i) {
158     AddEventUI(base_time, base_time, base_time + i);
159   }
160 
161   base_time += kJankThresholdInMs;
162   for (int i = 0; i < kJankThresholdInMs; ++i) {
163     AddEventUI(base_time + i, base_time + i, base_time + 2 * i);
164   }
165 
166   EXPECT_EXECUTION_JANKY_SLICES(0u);
167   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(0u);
168   TriggerCalculation();
169 }
170 
171 // Events that are queued and execute in less than 100ms do not jank, regardless
172 // of start time.
TEST_F(ResponsivenessCalculatorTest,NoQueueJank)173 TEST_F(ResponsivenessCalculatorTest, NoQueueJank) {
174   int base_time = 30;
175   for (int i = 0; i < kJankThresholdInMs; ++i) {
176     AddEventUI(base_time, base_time + i, base_time + i);
177   }
178 
179   base_time += kJankThresholdInMs;
180   for (int i = 0; i < kJankThresholdInMs; ++i) {
181     AddEventUI(base_time + i, base_time + 2 * i, base_time + 2 * i);
182   }
183 
184   EXPECT_EXECUTION_JANKY_SLICES(0u);
185   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(0u);
186   TriggerCalculation();
187 }
188 
189 // 10 execution jank events, but very closely overlapping. Time slices are
190 // discretized and fixed, e.g. [0 100] [100 200] [200 300]. In this test, the
191 // events all start in the [0 100] slice and end in the [100 200] slice. All of
192 // them end up marking the [100 200] slice as janky.
TEST_F(ResponsivenessCalculatorTest,OverlappingExecutionJank)193 TEST_F(ResponsivenessCalculatorTest, OverlappingExecutionJank) {
194   int base_time = 30;
195   for (int i = 0; i < 10; ++i) {
196     const int queue_time = base_time;
197     const int start_time = base_time;
198     const int finish_time = start_time + kJankThresholdInMs + i;
199     AddEventUI(queue_time, start_time, finish_time);
200   }
201 
202   EXPECT_EXECUTION_JANKY_SLICES(1u);
203   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
204   TriggerCalculation();
205 }
206 
207 // 10 queue jank events, but very closely overlapping. Time slices are
208 // discretized and fixed, e.g. [0 100] [100 200] [200 300]. In this test, the
209 // events are all queued in the [0 100] slice and start executing in the [100
210 // 200] slice. All of them end up marking the [100 200] slice as janky.
TEST_F(ResponsivenessCalculatorTest,OverlappingQueueJank)211 TEST_F(ResponsivenessCalculatorTest, OverlappingQueueJank) {
212   int base_time = 30;
213   for (int i = 0; i < 10; ++i) {
214     const int queue_time = base_time;
215     const int start_time = base_time + kJankThresholdInMs + i;
216     const int finish_time = start_time + 1;
217     AddEventUI(queue_time, start_time, finish_time);
218   }
219 
220   EXPECT_EXECUTION_JANKY_SLICES(0u);
221   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
222   TriggerCalculation();
223 }
224 
225 // UI thread has 3 execution jank events on slices 1, 2, 3
226 // IO thread has 3 execution jank events on slices 3, 4, 5,
227 // There should be a total of 5 jank events.
TEST_F(ResponsivenessCalculatorTest,OverlappingExecutionJankMultipleThreads)228 TEST_F(ResponsivenessCalculatorTest, OverlappingExecutionJankMultipleThreads) {
229   int base_time = 105;
230   for (int i = 0; i < 3; ++i) {
231     const int queue_time = base_time + i * kJankThresholdInMs;
232     const int start_time = queue_time;
233     const int finish_time = start_time + kJankThresholdInMs + 10;
234     AddEventUI(queue_time, start_time, finish_time);
235   }
236 
237   base_time = 305;
238   for (int i = 0; i < 3; ++i) {
239     const int queue_time = base_time + i * kJankThresholdInMs;
240     const int start_time = queue_time;
241     const int finish_time = start_time + kJankThresholdInMs + 10;
242     AddEventIO(queue_time, start_time, finish_time);
243   }
244 
245   EXPECT_EXECUTION_JANKY_SLICES(5u);
246   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(5u);
247   TriggerCalculation();
248 }
249 
250 // UI thread has 3 queue jank events on slices 1, 2, 3
251 // IO thread has 3 queue jank events on slices 3, 4, 5,
252 // There should be a total of 5 jank events.
TEST_F(ResponsivenessCalculatorTest,OverlappingQueueJankMultipleThreads)253 TEST_F(ResponsivenessCalculatorTest, OverlappingQueueJankMultipleThreads) {
254   int base_time = 105;
255   for (int i = 0; i < 3; ++i) {
256     const int queue_time = base_time + i * kJankThresholdInMs;
257     const int start_time = queue_time + kJankThresholdInMs + 10;
258     const int finish_time = start_time;
259     AddEventUI(queue_time, start_time, finish_time);
260   }
261 
262   base_time = 305;
263   for (int i = 0; i < 3; ++i) {
264     const int queue_time = base_time + i * kJankThresholdInMs;
265     const int start_time = queue_time + kJankThresholdInMs + 10;
266     const int finish_time = start_time;
267     AddEventIO(queue_time, start_time, finish_time);
268   }
269 
270   EXPECT_EXECUTION_JANKY_SLICES(0u);
271   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(5u);
272   TriggerCalculation();
273 }
274 
275 // Three execution janks, each of length 2, separated by some shorter events.
TEST_F(ResponsivenessCalculatorTest,SeparatedExecutionJanks)276 TEST_F(ResponsivenessCalculatorTest, SeparatedExecutionJanks) {
277   int base_time = 105;
278 
279   for (int i = 0; i < 3; ++i) {
280     {
281       const int queue_time = base_time;
282       const int start_time = base_time;
283       const int finish_time = base_time + 1;
284       AddEventUI(queue_time, start_time, finish_time);
285     }
286     {
287       const int queue_time = base_time;
288       const int start_time = base_time;
289       const int finish_time = base_time + 2 * kJankThresholdInMs + 1;
290       AddEventUI(queue_time, start_time, finish_time);
291     }
292     base_time += 10 * kJankThresholdInMs;
293   }
294 
295   EXPECT_EXECUTION_JANKY_SLICES(6u);
296   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(6u);
297   TriggerCalculation();
298 }
299 
300 // Three queue janks, each of length 2, separated by some shorter events.
TEST_F(ResponsivenessCalculatorTest,SeparatedQueueJanks)301 TEST_F(ResponsivenessCalculatorTest, SeparatedQueueJanks) {
302   int base_time = 105;
303 
304   for (int i = 0; i < 3; ++i) {
305     {
306       const int queue_time = base_time;
307       const int start_time = base_time + 1;
308       const int finish_time = start_time;
309       AddEventUI(queue_time, start_time, finish_time);
310     }
311     {
312       const int queue_time = base_time;
313       const int start_time = base_time + 2 * kJankThresholdInMs + 1;
314       const int finish_time = start_time;
315       AddEventUI(queue_time, start_time, finish_time);
316     }
317     base_time += 10 * kJankThresholdInMs;
318   }
319 
320   EXPECT_EXECUTION_JANKY_SLICES(0u);
321   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(6u);
322   TriggerCalculation();
323 }
324 
TEST_F(ResponsivenessCalculatorTest,MultipleTrigger)325 TEST_F(ResponsivenessCalculatorTest, MultipleTrigger) {
326   int base_time = 105;
327 
328   // 3 Janks, then trigger, then repeat.
329   for (int i = 0; i < 10; ++i) {
330     for (int j = 0; j < 3; ++j) {
331       AddEventUI(base_time, base_time, base_time + 3 * kJankThresholdInMs + 1);
332       base_time += 3 * kJankThresholdInMs;
333     }
334 
335     EXPECT_EXECUTION_JANKY_SLICES(9u);
336     EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(9u);
337     TriggerCalculation();
338     testing::Mock::VerifyAndClear(calculator_.get());
339   }
340 }
341 
342 // A long delay means that the machine likely went to sleep.
TEST_F(ResponsivenessCalculatorTest,LongDelay)343 TEST_F(ResponsivenessCalculatorTest, LongDelay) {
344   int base_time = 105;
345   AddEventUI(base_time, base_time, base_time + 3 * kJankThresholdInMs + 1);
346   base_time += 10 * kMeasurementIntervalInMs;
347   AddEventUI(base_time, base_time, base_time + 1);
348 
349   EXPECT_CALL(*calculator_, EmitResponsiveness(_, _, _)).Times(0);
350 }
351 
352 // A long event means that the machine likely went to sleep.
TEST_F(ResponsivenessCalculatorTest,LongEvent)353 TEST_F(ResponsivenessCalculatorTest, LongEvent) {
354   int base_time = 105;
355   AddEventUI(base_time, base_time, base_time + 10 * kMeasurementIntervalInMs);
356 
357   EXPECT_CALL(*calculator_, EmitResponsiveness(_, _, _)).Times(0);
358 }
359 
360 #if defined(OS_ANDROID)
361 // Metric should not be recorded when application is in background.
TEST_F(ResponsivenessCalculatorTest,ApplicationInBackground)362 TEST_F(ResponsivenessCalculatorTest, ApplicationInBackground) {
363   constexpr int kQueueTime = 35;
364   constexpr int kStartTime = 40;
365   constexpr int kFinishTime = kStartTime + kJankThresholdInMs + 5;
366   AddEventUI(kQueueTime, kStartTime, kFinishTime);
367 
368   base::android::ApplicationStatusListener::NotifyApplicationStateChange(
369       base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
370   base::RunLoop().RunUntilIdle();
371 
372   AddEventUI(kQueueTime, kStartTime + 1, kFinishTime + 1);
373 
374   EXPECT_CALL(*calculator_, EmitResponsiveness(_, _, _)).Times(0);
375   TriggerCalculation();
376 }
377 #endif
378 
379 // The suspended state must be passed to EmitResponsiveness(...).
380 // A single event executing slightly longer than 10 * kJankThresholdInMs.
TEST_F(ResponsivenessCalculatorTest,JankWithPowerSuspend)381 TEST_F(ResponsivenessCalculatorTest, JankWithPowerSuspend) {
382   constexpr int kQueueTime = 35;
383   constexpr int kStartTime = 40;
384   constexpr int kFinishTime = kStartTime + 10 * kJankThresholdInMs + 5;
385 
386   AddEventUI(kQueueTime, kStartTime, kFinishTime);
387   EXPECT_CALL(*calculator_,
388               EmitResponsiveness(JankType::kExecution, 10, false));
389   EXPECT_CALL(*calculator_,
390               EmitResponsiveness(JankType::kQueueAndExecution, 10, false));
391   TriggerCalculation();
392 
393   calculator_->SetProcessSuspended(true);
394   AddEventUI(kQueueTime, kStartTime, kFinishTime);
395   EXPECT_CALL(*calculator_, EmitResponsiveness(JankType::kExecution, 10, true));
396   EXPECT_CALL(*calculator_,
397               EmitResponsiveness(JankType::kQueueAndExecution, 10, true));
398   TriggerCalculation();
399 
400   calculator_->SetProcessSuspended(false);
401   AddEventUI(kQueueTime, kStartTime, kFinishTime);
402   EXPECT_CALL(*calculator_, EmitResponsiveness(JankType::kExecution, 10, true));
403   EXPECT_CALL(*calculator_,
404               EmitResponsiveness(JankType::kQueueAndExecution, 10, true));
405   TriggerCalculation();
406 
407   calculator_->SetProcessSuspended(true);
408   AddEventUI(kQueueTime, kStartTime, kFinishTime);
409   calculator_->SetProcessSuspended(false);
410   EXPECT_CALL(*calculator_, EmitResponsiveness(JankType::kExecution, 10, true));
411   EXPECT_CALL(*calculator_,
412               EmitResponsiveness(JankType::kQueueAndExecution, 10, true));
413   TriggerCalculation();
414 
415   // The whole slice must be flagged as containing suspend/resume events.
416   calculator_->SetProcessSuspended(true);
417   calculator_->SetProcessSuspended(false);
418   AddEventUI(kQueueTime, kStartTime, kFinishTime);
419   EXPECT_CALL(*calculator_, EmitResponsiveness(JankType::kExecution, 10, true));
420   EXPECT_CALL(*calculator_,
421               EmitResponsiveness(JankType::kQueueAndExecution, 10, true));
422   TriggerCalculation();
423 
424   AddEventUI(kQueueTime, kStartTime, kFinishTime);
425   EXPECT_CALL(*calculator_,
426               EmitResponsiveness(JankType::kExecution, 10, false));
427   EXPECT_CALL(*calculator_,
428               EmitResponsiveness(JankType::kQueueAndExecution, 10, false));
429   TriggerCalculation();
430 }
431 
432 // An event execution that crosses a measurement interval boundary should count
433 // towards both measurement intervals.
TEST_F(ResponsivenessCalculatorTest,ExecutionCrossesBoundary)434 TEST_F(ResponsivenessCalculatorTest, ExecutionCrossesBoundary) {
435   // Dummy event so that Calculator doesn't think the process is suspended.
436   {
437     const int kTime = 0.5 * kMeasurementIntervalInMs;
438     AddEventUI(kTime, kTime, kTime);
439   }
440 
441   // The event goes from [29801, 30150]. It should count as 1 jank in the first
442   // measurement interval and 2 in the second.
443   {
444     EXPECT_EXECUTION_JANKY_SLICES(1u);
445     EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
446     const int queue_time =
447         kMeasurementIntervalInMs - 2 * kJankThresholdInMs + 1;
448     const int start_time = queue_time;
449     const int finish_time = kMeasurementIntervalInMs + 1.5 * kJankThresholdInMs;
450     AddEventUI(queue_time, start_time, finish_time);
451   }
452 
453   // Dummy event so that Calculator doesn't think the process is suspended.
454   {
455     const int kTime = 1.5 * kMeasurementIntervalInMs;
456     AddEventUI(kTime, kTime, kTime);
457   }
458 
459   // Trigger another calculation.
460   EXPECT_EXECUTION_JANKY_SLICES(2u);
461   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(2u);
462 
463   const int kTime = 2 * kMeasurementIntervalInMs + 1;
464   AddEventUI(kTime, kTime, kTime);
465 }
466 
467 // An event queuing that crosses a measurement interval boundary should count
468 // towards both measurement intervals.
TEST_F(ResponsivenessCalculatorTest,QueuingCrossesBoundary)469 TEST_F(ResponsivenessCalculatorTest, QueuingCrossesBoundary) {
470   // Dummy event so that Calculator doesn't think the process is suspended.
471   {
472     const int kTime = 0.5 * kMeasurementIntervalInMs;
473     AddEventUI(kTime, kTime, kTime);
474   }
475 
476   // The event goes from [29801, 30150]. It should count as 1 jank in the first
477   // measurement interval and 2 in the second.
478   {
479     EXPECT_EXECUTION_JANKY_SLICES(0u);
480     EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(1u);
481     const int queue_time =
482         kMeasurementIntervalInMs - 2 * kJankThresholdInMs + 1;
483     const int start_time = kMeasurementIntervalInMs + 1.5 * kJankThresholdInMs;
484     const int finish_time = start_time;
485     AddEventUI(queue_time, start_time, finish_time);
486   }
487 
488   // Dummy event so that Calculator doesn't think the process is suspended.
489   {
490     const int kTime = 1.5 * kMeasurementIntervalInMs;
491     AddEventUI(kTime, kTime, kTime);
492   }
493 
494   // Trigger another calculation.
495   EXPECT_EXECUTION_JANKY_SLICES(0u);
496   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(2u);
497 
498   const int kTime = 2 * kMeasurementIntervalInMs + 1;
499   AddEventUI(kTime, kTime, kTime);
500 }
501 
502 // Events may not be ordered by start or end time.
TEST_F(ResponsivenessCalculatorTest,UnorderedEvents)503 TEST_F(ResponsivenessCalculatorTest, UnorderedEvents) {
504   // We add the following tasks:
505   //   [100, 100, 250]
506   //   [150, 150, 300]
507   //   [50, 50, 200]
508   //   [50, 50, 390] <- A
509   //
510   //   [1100, 1250, 1251]
511   //   [1150, 1300, 1301]
512   //   [1050, 1200, 1201]
513   //   [1050, 1390, 1391] <- B
514   //
515   // The execution jank in A subsumes all other execution janks. The queue jank
516   // in B subsumes all other queue janks.
517   AddEventUI(100, 100, 250);
518   AddEventUI(150, 150, 300);
519   AddEventUI(50, 50, 200);
520   AddEventUI(50, 50, 390);
521 
522   AddEventUI(1100, 1250, 1251);
523   AddEventUI(1150, 1300, 1301);
524   AddEventUI(1050, 1200, 1201);
525   AddEventUI(1050, 1390, 1391);
526 
527   EXPECT_EXECUTION_JANKY_SLICES(3u);
528   EXPECT_QUEUE_AND_EXECUTION_JANKY_SLICES(6u);
529   TriggerCalculation();
530 }
531 
532 }  // namespace responsiveness
533 }  // namespace content
534