[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / frame_sequence_tracker_unittest.cc
1 // Copyright 2019 The Chromium Authors
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 "cc/metrics/frame_sequence_tracker.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/memory/raw_ptr.h"
12 #include "base/test/bind.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "cc/metrics/compositor_frame_reporting_controller.h"
15 #include "cc/metrics/frame_sequence_tracker_collection.h"
16 #include "components/viz/common/frame_sinks/begin_frame_args.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/gfx/presentation_feedback.h"
20
21 namespace cc {
22
23 namespace {
24
25 const char* ParseNumber(const char* str, uint64_t* retvalue) {
26   uint64_t number = 0;
27   for (; *str >= '0' && *str <= '9'; ++str) {
28     number *= 10;
29     number += *str - '0';
30   }
31   *retvalue = number;
32   return str;
33 }
34
35 }  // namespace
36
37 class FrameSequenceTrackerTest : public testing::Test {
38  public:
39   const uint32_t kImplDamage = 0x1;
40   const uint32_t kMainDamage = 0x2;
41
42   FrameSequenceTrackerTest()
43       : compositor_frame_reporting_controller_(
44             std::make_unique<CompositorFrameReportingController>(
45                 /*should_report_histograms=*/true,
46                 /*should_report_ukm=*/false,
47                 /*layer_tree_host_id=*/1)),
48         collection_(/*is_single_threaded=*/false,
49                     compositor_frame_reporting_controller_.get()) {
50     tracker_ = collection_.StartScrollSequence(
51         FrameSequenceTrackerType::kTouchScroll,
52         FrameInfo::SmoothEffectDrivingThread::kCompositor);
53   }
54   ~FrameSequenceTrackerTest() override = default;
55
56   void CreateNewTracker(FrameInfo::SmoothEffectDrivingThread thread_type =
57                             FrameInfo::SmoothEffectDrivingThread::kCompositor) {
58     tracker_ = collection_.StartScrollSequence(
59         FrameSequenceTrackerType::kTouchScroll, thread_type);
60   }
61
62   viz::BeginFrameArgs CreateBeginFrameArgs(
63       uint64_t source_id,
64       uint64_t sequence_number,
65       base::TimeTicks now = base::TimeTicks::Now()) {
66     auto interval = base::Milliseconds(16);
67     auto deadline = now + interval;
68     return viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, source_id,
69                                        sequence_number, now, deadline, interval,
70                                        viz::BeginFrameArgs::NORMAL);
71   }
72
73   void StartImplAndMainFrames(const viz::BeginFrameArgs& args) {
74     collection_.NotifyBeginImplFrame(args);
75     collection_.NotifyBeginMainFrame(args);
76   }
77
78   uint32_t DispatchCompleteFrame(const viz::BeginFrameArgs& args,
79                                  uint32_t damage_type,
80                                  bool has_missing_content = false) {
81     StartImplAndMainFrames(args);
82
83     if (damage_type & kImplDamage) {
84       if (!(damage_type & kMainDamage)) {
85         collection_.NotifyMainFrameCausedNoDamage(args, false);
86       } else {
87         collection_.NotifyMainFrameProcessed(args);
88       }
89       uint32_t frame_token = NextFrameToken();
90       collection_.NotifySubmitFrame(frame_token, has_missing_content,
91                                     viz::BeginFrameAck(args, true), args);
92       collection_.NotifyFrameEnd(args, args);
93       return frame_token;
94     } else {
95       collection_.NotifyImplFrameCausedNoDamage(
96           viz::BeginFrameAck(args, false));
97       collection_.NotifyMainFrameCausedNoDamage(args, true);
98       collection_.NotifyFrameEnd(args, args);
99     }
100     return 0;
101   }
102
103   uint32_t NextFrameToken() {
104     static uint32_t frame_token = 0;
105     return ++frame_token;
106   }
107
108   // Check whether a type of tracker exists in |frame_trackers_| or not.
109   bool TrackerExists(FrameSequenceTrackerType type) const {
110     auto key =
111         std::make_pair(type, FrameInfo::SmoothEffectDrivingThread::kUnknown);
112     if (type == FrameSequenceTrackerType::kTouchScroll ||
113         type == FrameSequenceTrackerType::kWheelScroll ||
114         type == FrameSequenceTrackerType::kScrollbarScroll) {
115       key = std::make_pair(type,
116                            FrameInfo::SmoothEffectDrivingThread::kCompositor);
117       if (!collection_.frame_trackers_.contains(key))
118         key = std::make_pair(type, FrameInfo::SmoothEffectDrivingThread::kMain);
119     }
120     return collection_.frame_trackers_.contains(key);
121   }
122
123   bool RemovalTrackerExists(unsigned index,
124                             FrameSequenceTrackerType type) const {
125     DCHECK_GT(collection_.removal_trackers_.size(), index);
126     return collection_.removal_trackers_[index]->type() == type;
127   }
128
129   void GenerateSequence(const char* str) {
130     const uint64_t source_id = 1;
131     uint64_t current_frame = 0;
132     viz::BeginFrameArgs last_activated_main_args;
133     while (*str) {
134       const char command = *str++;
135       uint64_t sequence = 0, dummy = 0, last_activated_main = 0;
136       switch (command) {
137         case 'b':
138         case 'P':
139         case 'n':
140         case 's':
141         case 'E':
142           ASSERT_EQ(*str, '(') << command;
143           str = ParseNumber(++str, &sequence);
144           ASSERT_EQ(*str, ')');
145           ++str;
146           break;
147
148         case 'B':
149         case 'N':
150           ASSERT_EQ(*str, '(');
151           str = ParseNumber(++str, &dummy);
152           ASSERT_EQ(*str, ',');
153           str = ParseNumber(++str, &sequence);
154           ASSERT_EQ(*str, ')');
155           ++str;
156           break;
157
158         case 'e':
159           ASSERT_EQ(*str, '(');
160           str = ParseNumber(++str, &sequence);
161           ASSERT_EQ(*str, ',');
162           str = ParseNumber(++str, &last_activated_main);
163           ASSERT_EQ(*str, ')');
164           ++str;
165           break;
166
167         case 'R':
168           break;
169
170         default:
171           NOTREACHED() << command << str;
172       }
173
174       switch (command) {
175         case 'b':
176           current_frame = sequence;
177           collection_.NotifyBeginImplFrame(
178               CreateBeginFrameArgs(source_id, sequence));
179           break;
180
181         case 'P':
182           collection_.NotifyFramePresented(
183               sequence, {base::TimeTicks::Now(),
184                          viz::BeginFrameArgs::DefaultInterval(), 0});
185           break;
186
187         case 'R':
188           collection_.NotifyPauseFrameProduction();
189           break;
190
191         case 'n':
192           collection_.NotifyImplFrameCausedNoDamage(
193               viz::BeginFrameAck(source_id, sequence, false, 0));
194           break;
195
196         case 's': {
197           auto frame_token = sequence;
198           if (current_frame == 0)
199             current_frame = 1;
200           auto args = CreateBeginFrameArgs(source_id, current_frame);
201           auto main_args = args;
202           if (*str == 'S') {
203             ++str;
204             ASSERT_EQ(*str, '(');
205             str = ParseNumber(++str, &sequence);
206             ASSERT_EQ(*str, ')');
207             ++str;
208             main_args = CreateBeginFrameArgs(source_id, sequence);
209           }
210           collection_.NotifySubmitFrame(
211               frame_token, /*has_missing_content=*/false,
212               viz::BeginFrameAck(args, true), main_args);
213           break;
214         }
215
216         case 'e': {
217           auto args = CreateBeginFrameArgs(source_id, sequence);
218           if (last_activated_main != 0)
219             DCHECK_EQ(last_activated_main_args.frame_id.sequence_number,
220                       last_activated_main);
221           collection_.NotifyFrameEnd(args, last_activated_main_args);
222           break;
223         }
224
225         case 'E':
226           last_activated_main_args = CreateBeginFrameArgs(source_id, sequence);
227           collection_.NotifyMainFrameProcessed(last_activated_main_args);
228           break;
229
230         case 'B':
231           collection_.NotifyBeginMainFrame(
232               CreateBeginFrameArgs(source_id, sequence));
233           break;
234
235         case 'N':
236           collection_.NotifyMainFrameCausedNoDamage(
237               CreateBeginFrameArgs(source_id, sequence), true);
238           break;
239
240         default:
241           NOTREACHED();
242       }
243     }
244   }
245
246   void ReportMetrics() { tracker_->metrics_->ReportMetrics(); }
247
248   base::TimeDelta TimeDeltaToReport() const {
249     return tracker_->time_delta_to_report_;
250   }
251
252   unsigned NumberOfTrackers() const {
253     return collection_.frame_trackers_.size();
254   }
255   unsigned NumberOfCustomTrackers() const {
256     return collection_.custom_frame_trackers_.size();
257   }
258   unsigned NumberOfRemovalTrackers() const {
259     return collection_.removal_trackers_.size();
260   }
261
262   uint64_t BeginImplFrameDataPreviousSequence() const {
263     return tracker_->begin_impl_frame_data_.previous_sequence;
264   }
265
266   uint64_t BeginMainFrameDataPreviousSequence() const {
267     return tracker_->begin_main_frame_data_.previous_sequence;
268   }
269
270   base::flat_set<uint32_t> IgnoredFrameTokens() const {
271     return tracker_->ignored_frame_tokens_;
272   }
273
274   FrameSequenceMetrics::ThroughputData& ImplThroughput(
275       FrameSequenceTracker* tracker) const {
276     return tracker->impl_throughput();
277   }
278
279   FrameSequenceMetrics::ThroughputData& ImplThroughput() const {
280     return tracker_->impl_throughput();
281   }
282
283   FrameSequenceMetrics::ThroughputData& MainThroughput(
284       FrameSequenceTracker* tracker) const {
285     return tracker->main_throughput();
286   }
287
288   FrameSequenceMetrics::ThroughputData& MainThroughput() const {
289     return tracker_->main_throughput();
290   }
291
292   FrameSequenceTracker::TerminationStatus GetTerminationStatus(
293       FrameSequenceTracker* tracker) {
294     return tracker->termination_status_;
295   }
296   FrameSequenceTracker::TerminationStatus GetTerminationStatus() {
297     return tracker_->termination_status_;
298   }
299
300   uint32_t NumberOfFramesCheckerboarded() const {
301     return tracker_->metrics_->frames_checkerboarded();
302   }
303
304  protected:
305   std::unique_ptr<CompositorFrameReportingController>
306       compositor_frame_reporting_controller_;
307   FrameSequenceTrackerCollection collection_;
308   raw_ptr<FrameSequenceTracker> tracker_;
309 };
310
311 // Tests that the tracker works correctly when the source-id for the
312 // begin-frames change.
313 TEST_F(FrameSequenceTrackerTest, SourceIdChangeDuringSequence) {
314   const uint64_t source_1 = 1;
315   uint64_t sequence_1 = 0;
316
317   // Dispatch some frames, both causing damage to impl/main, and both impl and
318   // main providing damage to the frame.
319   auto args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
320   DispatchCompleteFrame(args_1, kImplDamage | kMainDamage);
321   args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
322   DispatchCompleteFrame(args_1, kImplDamage | kMainDamage);
323
324   // Start a new tracker.
325   CreateNewTracker();
326
327   // Change the source-id, and start an impl frame. This time, the main-frame
328   // does not provide any damage.
329   const uint64_t source_2 = 2;
330   uint64_t sequence_2 = 0;
331   auto args_2 = CreateBeginFrameArgs(source_2, ++sequence_2);
332   collection_.NotifyBeginImplFrame(args_2);
333   collection_.NotifyBeginMainFrame(args_2);
334   collection_.NotifyMainFrameCausedNoDamage(args_2, true);
335   // Since the main-frame did not have any new damage from the latest
336   // BeginFrameArgs, the submit-frame will carry the previous BeginFrameArgs
337   // (from source_1);
338   collection_.NotifySubmitFrame(NextFrameToken(), /*has_missing_content=*/false,
339                                 viz::BeginFrameAck(args_2, true), args_1);
340 }
341
342 TEST_F(FrameSequenceTrackerTest, TestNotifyFramePresented) {
343   collection_.StartSequence(FrameSequenceTrackerType::kCompositorAnimation);
344   collection_.StartSequence(FrameSequenceTrackerType::kMainThreadAnimation);
345   EXPECT_EQ(NumberOfTrackers(), 3u);
346
347   collection_.StopSequence(FrameSequenceTrackerType::kCompositorAnimation);
348   EXPECT_EQ(NumberOfTrackers(), 2u);
349   EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kMainThreadAnimation));
350   EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kTouchScroll));
351   // StopSequence should have destroyed all trackers because there is no frame
352   // awaiting presentation.
353   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
354 }
355
356 TEST_F(FrameSequenceTrackerTest, TestJankWithZeroIntervalInFeedback) {
357   // Test if jank can be correctly counted if presentation feedback reports
358   // zero frame interval.
359   const uint64_t source = 1;
360   uint64_t sequence = 1;
361   uint64_t frame_token = sequence;
362   const char* histogram_name =
363       "Graphics.Smoothness.Jank.Compositor.TouchScroll";
364   const base::TimeDelta zero_interval = base::Milliseconds(0);
365   base::HistogramTester histogram_tester;
366
367   CreateNewTracker();
368   base::TimeTicks args_timestamp = base::TimeTicks::Now();
369   auto args = CreateBeginFrameArgs(source, sequence, args_timestamp);
370
371   // Frame 1
372   collection_.NotifyBeginImplFrame(args);
373   collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
374                                 args);
375   collection_.NotifyFrameEnd(args, args);
376
377   collection_.NotifyFramePresented(
378       frame_token,
379       /*feedback=*/{args_timestamp, zero_interval, 0});
380
381   // Frame 2
382   ++sequence;
383   ++frame_token;
384   args_timestamp += base::Milliseconds(16.67);
385   args = CreateBeginFrameArgs(source, sequence, args_timestamp);
386   collection_.NotifyBeginImplFrame(args);
387   collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
388                                 args);
389   collection_.NotifyFrameEnd(args, args);
390   collection_.NotifyFramePresented(
391       frame_token,
392       /*feedback=*/{args_timestamp, zero_interval, 0});
393
394   // Frame 3: There is one jank (frame interval incremented from 16.67ms
395   // to 30.0ms)
396   ++sequence;
397   ++frame_token;
398   args_timestamp += base::Milliseconds(30.0);
399   args = CreateBeginFrameArgs(source, sequence, args_timestamp);
400   collection_.NotifyBeginImplFrame(args);
401   collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
402                                 args);
403   collection_.NotifyFrameEnd(args, args);
404   collection_.NotifyFramePresented(
405       frame_token,
406       /*feedback=*/{args_timestamp, zero_interval, 0});
407
408   // Frame 4: There is no jank since the increment from 30ms to  31ms is too
409   // small. This tests if |NotifyFramePresented| can correctly handle the
410   // situation when the frame interval reported in presentation feedback is 0.
411   ++sequence;
412   ++frame_token;
413   args_timestamp += base::Milliseconds(31.0);
414   args = CreateBeginFrameArgs(source, sequence, args_timestamp);
415   collection_.NotifyBeginImplFrame(args);
416   collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
417                                 args);
418   collection_.NotifyFrameEnd(args, args);
419   collection_.NotifyFramePresented(
420       frame_token,
421       /*feedback=*/{args_timestamp, zero_interval, 0});
422   ImplThroughput().frames_expected = 100u;
423   ReportMetrics();
424   histogram_tester.ExpectTotalCount(
425       "Graphics.Smoothness.Jank.Compositor.TouchScroll", 1u);
426
427   // There should be only one jank for frame 3.
428   EXPECT_THAT(histogram_tester.GetAllSamples(histogram_name),
429               testing::ElementsAre(base::Bucket(1, 1)));
430 }
431
432 // Base case for checkerboarding: present a single frame with checkerboarding,
433 // followed by a non-checkerboard frame.
434 TEST_F(FrameSequenceTrackerTest, CheckerboardingSimple) {
435   CreateNewTracker();
436   base::HistogramTester histogram_tester;
437
438   const uint64_t source_1 = 1;
439   uint64_t sequence_1 = 0;
440
441   // Dispatch some frames, both causing damage to impl/main, and both impl and
442   // main providing damage to the frame.
443   auto args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
444   bool has_missing_content = true;
445   auto frame_token = DispatchCompleteFrame(args_1, kImplDamage | kMainDamage,
446                                            has_missing_content);
447
448   const auto interval = viz::BeginFrameArgs::DefaultInterval();
449   gfx::PresentationFeedback feedback(base::TimeTicks::Now(), interval, 0);
450   collection_.NotifyFramePresented(frame_token, feedback);
451
452   // Submit another frame with no checkerboarding.
453   has_missing_content = false;
454   frame_token =
455       DispatchCompleteFrame(CreateBeginFrameArgs(source_1, ++sequence_1),
456                             kImplDamage | kMainDamage, has_missing_content);
457   feedback =
458       gfx::PresentationFeedback(base::TimeTicks::Now() + interval, interval, 0);
459   collection_.NotifyFramePresented(frame_token, feedback);
460
461   EXPECT_EQ(1u, NumberOfFramesCheckerboarded());
462
463   // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
464   // in order to report checkerboarding histogram, the minimum frames for
465   // ThroughputMetric is 100.
466   ImplThroughput().frames_expected = 100u;
467   ReportMetrics();
468   histogram_tester.ExpectTotalCount(
469       "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
470 }
471
472 // Present a single frame with checkerboarding, followed by a non-checkerboard
473 // frame after a few vsyncs.
474 TEST_F(FrameSequenceTrackerTest, CheckerboardingMultipleFrames) {
475   CreateNewTracker();
476   base::HistogramTester histogram_tester;
477
478   const uint64_t source_1 = 1;
479   uint64_t sequence_1 = 0;
480
481   // Dispatch some frames, both causing damage to impl/main, and both impl and
482   // main providing damage to the frame.
483   auto args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
484   bool has_missing_content = true;
485   auto frame_token = DispatchCompleteFrame(args_1, kImplDamage | kMainDamage,
486                                            has_missing_content);
487
488   const auto interval = viz::BeginFrameArgs::DefaultInterval();
489   gfx::PresentationFeedback feedback(base::TimeTicks::Now(), interval, 0);
490   collection_.NotifyFramePresented(frame_token, feedback);
491
492   // Submit another frame with no checkerboarding.
493   has_missing_content = false;
494   frame_token =
495       DispatchCompleteFrame(CreateBeginFrameArgs(source_1, ++sequence_1),
496                             kImplDamage | kMainDamage, has_missing_content);
497   feedback = gfx::PresentationFeedback(base::TimeTicks::Now() + interval * 3,
498                                        interval, 0);
499   collection_.NotifyFramePresented(frame_token, feedback);
500
501   EXPECT_EQ(3u, NumberOfFramesCheckerboarded());
502
503   // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
504   // in order to report checkerboarding histogram, the minimum frames for
505   // ThroughputMetric is 100.
506   ImplThroughput().frames_expected = 100u;
507   ReportMetrics();
508   histogram_tester.ExpectTotalCount(
509       "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
510 }
511
512 // Present multiple checkerboarded frames, followed by a non-checkerboard
513 // frame.
514 TEST_F(FrameSequenceTrackerTest, MultipleCheckerboardingFrames) {
515   CreateNewTracker();
516   base::HistogramTester histogram_tester;
517
518   const uint32_t kFrames = 3;
519   const uint64_t source_1 = 1;
520   uint64_t sequence_1 = 0;
521
522   // Submit |kFrames| number of frames with checkerboarding.
523   std::vector<uint32_t> frames;
524   for (uint32_t i = 0; i < kFrames; ++i) {
525     auto args_1 = CreateBeginFrameArgs(source_1, ++sequence_1);
526     bool has_missing_content = true;
527     auto frame_token = DispatchCompleteFrame(args_1, kImplDamage | kMainDamage,
528                                              has_missing_content);
529     frames.push_back(frame_token);
530   }
531
532   base::TimeTicks present_now = base::TimeTicks::Now();
533   const auto interval = viz::BeginFrameArgs::DefaultInterval();
534   for (auto frame_token : frames) {
535     gfx::PresentationFeedback feedback(present_now, interval, 0);
536     collection_.NotifyFramePresented(frame_token, feedback);
537     present_now += interval;
538   }
539
540   // Submit another frame with no checkerboarding.
541   bool has_missing_content = false;
542   auto frame_token =
543       DispatchCompleteFrame(CreateBeginFrameArgs(source_1, ++sequence_1),
544                             kImplDamage | kMainDamage, has_missing_content);
545   gfx::PresentationFeedback feedback(present_now, interval, 0);
546   collection_.NotifyFramePresented(frame_token, feedback);
547
548   EXPECT_EQ(kFrames, NumberOfFramesCheckerboarded());
549
550   // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
551   // in order to report checkerboarding histogram, the minimum frames for
552   // ThroughputMetric is 100.
553   ImplThroughput().frames_expected = 100u;
554   ReportMetrics();
555   histogram_tester.ExpectTotalCount(
556       "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
557 }
558
559 TEST_F(FrameSequenceTrackerTest, ReportMetrics) {
560   base::HistogramTester histogram_tester;
561
562   // Test that there is no main thread frames expected.
563   ImplThroughput().frames_expected = 100u;
564   ImplThroughput().frames_produced = 85u;
565   ReportMetrics();
566   histogram_tester.ExpectTotalCount(
567       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll",
568       1u);
569   histogram_tester.ExpectTotalCount(
570       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll", 0u);
571
572   // Test that both are reported.
573   ImplThroughput().frames_expected = 100u;
574   ImplThroughput().frames_produced = 85u;
575   MainThroughput().frames_expected = 150u;
576   MainThroughput().frames_produced = 25u;
577   ReportMetrics();
578   histogram_tester.ExpectTotalCount(
579       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll",
580       2u);
581   histogram_tester.ExpectTotalCount(
582       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll", 1u);
583
584   // Test that none is reported.
585   MainThroughput().frames_expected = 2u;
586   MainThroughput().frames_produced = 1u;
587   ImplThroughput().frames_expected = 2u;
588   ImplThroughput().frames_produced = 1u;
589   ReportMetrics();
590   histogram_tester.ExpectTotalCount(
591       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll",
592       2u);
593   histogram_tester.ExpectTotalCount(
594       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll", 1u);
595
596   // Test the case where compositor and main thread have the same throughput.
597   ImplThroughput().frames_expected = 120u;
598   ImplThroughput().frames_produced = 118u;
599   MainThroughput().frames_expected = 120u;
600   MainThroughput().frames_produced = 118u;
601   ReportMetrics();
602   histogram_tester.ExpectTotalCount(
603       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll",
604       3u);
605   histogram_tester.ExpectTotalCount(
606       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll", 2u);
607 }
608
609 TEST_F(FrameSequenceTrackerTest, ReportMetricsAtFixedInterval) {
610   const uint64_t source = 1;
611   uint64_t sequence = 0;
612   base::TimeDelta first_time_delta = base::Seconds(1);
613   auto args = CreateBeginFrameArgs(source, ++sequence,
614                                    base::TimeTicks::Now() + first_time_delta);
615
616   // args.frame_time is less than 5s of the tracker creation time, so won't
617   // schedule this tracker to report its throughput.
618   collection_.NotifyBeginImplFrame(args);
619   collection_.NotifyImplFrameCausedNoDamage(viz::BeginFrameAck(args, false));
620   collection_.NotifyFrameEnd(args, args);
621
622   EXPECT_EQ(NumberOfTrackers(), 1u);
623   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
624
625   ImplThroughput().frames_expected += 101;
626   // Now args.frame_time is 5s since the tracker creation time, so this tracker
627   // should be scheduled to report its throughput.
628   args = CreateBeginFrameArgs(source, ++sequence,
629                               args.frame_time + TimeDeltaToReport());
630   collection_.NotifyBeginImplFrame(args);
631   collection_.NotifyImplFrameCausedNoDamage(viz::BeginFrameAck(args, false));
632   collection_.NotifyFrameEnd(args, args);
633   EXPECT_EQ(NumberOfTrackers(), 1u);
634   // At NotifyFrameEnd, the tracker is removed from removal_tracker_ list.
635   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
636 }
637
638 TEST_F(FrameSequenceTrackerTest, ReportWithoutBeginImplFrame) {
639   const uint64_t source = 1;
640   uint64_t sequence = 0;
641
642   auto args = CreateBeginFrameArgs(source, ++sequence);
643   collection_.NotifyBeginMainFrame(args);
644
645   EXPECT_EQ(BeginImplFrameDataPreviousSequence(), 0u);
646   // Call to ReportBeginMainFrame should early exit.
647   EXPECT_EQ(BeginMainFrameDataPreviousSequence(), 0u);
648
649   uint32_t frame_token = NextFrameToken();
650   collection_.NotifySubmitFrame(frame_token, false,
651                                 viz::BeginFrameAck(args, true), args);
652
653   // Call to ReportSubmitFrame should early exit.
654   EXPECT_TRUE(IgnoredFrameTokens().contains(frame_token));
655
656   gfx::PresentationFeedback feedback;
657   collection_.NotifyFramePresented(frame_token, feedback);
658   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
659   EXPECT_EQ(MainThroughput().frames_produced, 0u);
660 }
661
662 TEST_F(FrameSequenceTrackerTest, MainFrameTracking) {
663   const uint64_t source = 1;
664   uint64_t sequence = 0;
665
666   auto args = CreateBeginFrameArgs(source, ++sequence);
667   auto frame_1 = DispatchCompleteFrame(args, kImplDamage | kMainDamage);
668
669   args = CreateBeginFrameArgs(source, ++sequence);
670   auto frame_2 = DispatchCompleteFrame(args, kImplDamage);
671
672   gfx::PresentationFeedback feedback;
673   collection_.NotifyFramePresented(frame_1, feedback);
674   collection_.NotifyFramePresented(frame_2, feedback);
675 }
676
677 TEST_F(FrameSequenceTrackerTest, MainFrameNoDamageTracking) {
678   const uint64_t source = 1;
679   uint64_t sequence = 0;
680
681   const auto first_args = CreateBeginFrameArgs(source, ++sequence);
682   DispatchCompleteFrame(first_args, kImplDamage | kMainDamage);
683
684   // Now, start the next frame, but for main, respond with the previous args.
685   const auto second_args = CreateBeginFrameArgs(source, ++sequence);
686   StartImplAndMainFrames(second_args);
687
688   uint32_t frame_token = NextFrameToken();
689   collection_.NotifySubmitFrame(frame_token, /*has_missing_content=*/false,
690                                 viz::BeginFrameAck(second_args, true),
691                                 first_args);
692   collection_.NotifyFrameEnd(second_args, second_args);
693
694   // Start and submit the next frame, with no damage from main.
695   auto args = CreateBeginFrameArgs(source, ++sequence);
696   collection_.NotifyBeginImplFrame(args);
697   frame_token = NextFrameToken();
698   collection_.NotifySubmitFrame(frame_token, /*has_missing_content=*/false,
699                                 viz::BeginFrameAck(args, true), first_args);
700   collection_.NotifyFrameEnd(args, args);
701
702   // Now, submit a frame with damage from main from |second_args|.
703   collection_.NotifyMainFrameProcessed(second_args);
704   args = CreateBeginFrameArgs(source, ++sequence);
705   StartImplAndMainFrames(args);
706   frame_token = NextFrameToken();
707   collection_.NotifySubmitFrame(frame_token, /*has_missing_content=*/false,
708                                 viz::BeginFrameAck(args, true), second_args);
709   collection_.NotifyFrameEnd(args, args);
710 }
711
712 TEST_F(FrameSequenceTrackerTest, BeginMainFrameSubmit) {
713   // Start with a bunch of frames so that the metric does get reported at the
714   // end of the test.
715   ImplThroughput().frames_expected = 98u;
716   ImplThroughput().frames_produced = 98u;
717   MainThroughput().frames_expected = 98u;
718   MainThroughput().frames_produced = 98u;
719
720   const char sequence[] =
721       "b(1)B(0,1)n(1)e(1,0)b(2)E(1)B(1,2)s(1)S(1)e(2,1)P(1)";
722   GenerateSequence(sequence);
723   EXPECT_EQ(ImplThroughput().frames_expected, 99u);
724   EXPECT_EQ(MainThroughput().frames_expected, 100u);
725
726   base::HistogramTester histogram_tester;
727   ReportMetrics();
728
729   const char metric[] =
730       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll";
731   histogram_tester.ExpectTotalCount(metric, 1u);
732   EXPECT_THAT(histogram_tester.GetAllSamples(metric),
733               testing::ElementsAre(base::Bucket(1, 1)));
734 }
735
736 TEST_F(FrameSequenceTrackerTest, ScrollingThreadMetricCompositorThread) {
737   // Start with a bunch of frames so that the metric does get reported at the
738   // end of the test.
739   ImplThroughput().frames_expected = 100u;
740   ImplThroughput().frames_produced = 100u;
741   MainThroughput().frames_expected = 100u;
742   MainThroughput().frames_produced = 90u;
743
744   base::HistogramTester histogram_tester;
745   ReportMetrics();
746
747   const char metric[] =
748       "Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.TouchScroll";
749   histogram_tester.ExpectTotalCount(metric, 1u);
750   EXPECT_THAT(histogram_tester.GetAllSamples(metric),
751               testing::ElementsAre(base::Bucket(0, 1)));
752 }
753
754 TEST_F(FrameSequenceTrackerTest, ScrollingThreadMetricMainThread) {
755   CreateNewTracker(FrameInfo::SmoothEffectDrivingThread::kMain);
756
757   // Start with a bunch of frames so that the metric does get reported at the
758   // end of the test.
759   ImplThroughput().frames_expected = 100u;
760   ImplThroughput().frames_produced = 100u;
761   MainThroughput().frames_expected = 100u;
762   MainThroughput().frames_produced = 90u;
763
764   base::HistogramTester histogram_tester;
765   ReportMetrics();
766
767   const char metric[] =
768       "Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.TouchScroll";
769   histogram_tester.ExpectTotalCount(metric, 1u);
770   EXPECT_THAT(histogram_tester.GetAllSamples(metric),
771               testing::ElementsAre(base::Bucket(10, 1)));
772 }
773
774 TEST_F(FrameSequenceTrackerTest, SimpleSequenceOneFrame) {
775   const char sequence[] = "b(1)B(0,1)s(1)S(1)e(1,0)P(1)";
776   GenerateSequence(sequence);
777   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
778   EXPECT_EQ(MainThroughput().frames_expected, 1u);
779   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
780   EXPECT_EQ(MainThroughput().frames_produced, 1u);
781 }
782
783 TEST_F(FrameSequenceTrackerTest, SimpleSequenceOneFrameNoDamage) {
784   const char sequence[] = "b(1)B(0,1)N(1,1)n(1)e(1,0)";
785   GenerateSequence(sequence);
786   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
787   EXPECT_EQ(MainThroughput().frames_expected, 0u);
788   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
789   EXPECT_EQ(MainThroughput().frames_produced, 0u);
790
791   const char second_sequence[] = "b(2)B(1,2)n(2)N(2,2)e(2,0)";
792   GenerateSequence(second_sequence);
793   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
794   EXPECT_EQ(MainThroughput().frames_expected, 0u);
795   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
796   EXPECT_EQ(MainThroughput().frames_produced, 0u);
797 }
798
799 TEST_F(FrameSequenceTrackerTest, MultipleNoDamageNotifications) {
800   const char sequence[] = "b(1)n(1)n(1)e(1,0)";
801   GenerateSequence(sequence);
802   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
803   EXPECT_EQ(MainThroughput().frames_expected, 0u);
804   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
805   EXPECT_EQ(MainThroughput().frames_produced, 0u);
806 }
807
808 TEST_F(FrameSequenceTrackerTest, MultipleNoDamageNotificationsFromMain) {
809   const char sequence[] = "b(1)B(0,1)N(1,1)n(1)N(0,1)e(1,0)";
810   GenerateSequence(sequence);
811   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
812   EXPECT_EQ(MainThroughput().frames_expected, 0u);
813   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
814   EXPECT_EQ(MainThroughput().frames_produced, 0u);
815 }
816
817 TEST_F(FrameSequenceTrackerTest, DelayedMainFrameNoDamage) {
818   const char sequence[] =
819       "b(1)B(0,1)n(1)e(1,0)b(2)n(2)e(2,0)b(3)N(0,1)n(3)e(3,0)";
820   GenerateSequence(sequence);
821   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
822   EXPECT_EQ(MainThroughput().frames_expected, 0u);
823   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
824   EXPECT_EQ(MainThroughput().frames_produced, 0u);
825 }
826
827 TEST_F(FrameSequenceTrackerTest, DelayedMainFrameNoDamageFromOlderFrame) {
828   // Start a sequence, and receive a 'no damage' from an earlier frame.
829   const char second_sequence[] = "b(2)B(0,2)N(2,1)n(2)N(2,2)e(2,0)";
830   GenerateSequence(second_sequence);
831   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
832   EXPECT_EQ(MainThroughput().frames_expected, 0u);
833   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
834   EXPECT_EQ(MainThroughput().frames_produced, 0u);
835 }
836
837 // This tests when a BeginMainFrame leads to No Damage, after the next Main
838 // Frame has started. This should not crash.
839 TEST_F(FrameSequenceTrackerTest, DelayedMainFrameNoDamageAfterNextMainFrame) {
840   const char sequence[] =
841       "b(1)B(0,1)n(1)e(1,0)E(1)b(2)B(0,2)N(0,1)n(2)N(0,2)e(2,0)";
842   GenerateSequence(sequence);
843   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
844   EXPECT_EQ(MainThroughput().frames_expected, 0u);
845   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
846   EXPECT_EQ(MainThroughput().frames_produced, 0u);
847 }
848
849 TEST_F(FrameSequenceTrackerTest, StateResetDuringSequence) {
850   const char sequence[] = "b(1)B(0,1)n(1)N(1,1)Re(1,0)b(2)n(2)e(2,0)";
851   GenerateSequence(sequence);
852   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
853   EXPECT_EQ(MainThroughput().frames_expected, 0u);
854   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
855   EXPECT_EQ(MainThroughput().frames_produced, 0u);
856 }
857
858 TEST_F(FrameSequenceTrackerTest, NoCompositorDamageSubmitFrame) {
859   const char sequence[] = "b(1)n(1)B(0,1)E(1)s(1)S(1)e(1,1)P(1)b(2)";
860   GenerateSequence(sequence);
861   EXPECT_EQ(ImplThroughput().frames_expected, 2u);
862   EXPECT_EQ(MainThroughput().frames_expected, 1u);
863   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
864   EXPECT_EQ(MainThroughput().frames_produced, 1u);
865 }
866
867 TEST_F(FrameSequenceTrackerTest, SequenceStateResetsDuringFrame) {
868   const char sequence[] = "b(1)Rn(1)e(1,0)";
869   GenerateSequence(sequence);
870   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
871   EXPECT_EQ(MainThroughput().frames_expected, 0u);
872   EXPECT_EQ(ImplThroughput().frames_produced, 0u);
873   EXPECT_EQ(MainThroughput().frames_produced, 0u);
874
875   GenerateSequence("b(2)s(1)e(2,0)P(1)b(4)");
876   EXPECT_EQ(ImplThroughput().frames_expected, 3u);
877   EXPECT_EQ(MainThroughput().frames_expected, 0u);
878   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
879   EXPECT_EQ(MainThroughput().frames_produced, 0u);
880 }
881
882 TEST_F(FrameSequenceTrackerTest, BeginImplFrameBeforeTerminate) {
883   const char sequence[] = "b(1)s(1)e(1,0)b(4)P(1)";
884   GenerateSequence(sequence);
885   EXPECT_EQ(ImplThroughput().frames_expected, 4u);
886   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
887   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
888   EXPECT_EQ(ImplThroughput().frames_expected, 4u);
889   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
890 }
891
892 // b(2417)B(0,2417)E(2417)n(2417)N(2417,2417)
893 TEST_F(FrameSequenceTrackerTest, SequenceNumberReset) {
894   const char sequence[] =
895       "b(6)B(0,6)n(6)e(6,0)Rb(1)B(0,1)N(1,1)n(1)e(1,0)b(2)B(1,2)n(2)e(2,0)";
896   GenerateSequence(sequence);
897   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
898   EXPECT_EQ(MainThroughput().frames_expected, 1u);
899 }
900
901 TEST_F(FrameSequenceTrackerTest, MainThroughputWithHighLatency) {
902   const char sequence[] = "b(1)B(0,1)n(1)e(1,0)b(2)E(1)s(1)S(1)e(2,1)P(1)";
903   GenerateSequence(sequence);
904   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
905   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
906   EXPECT_EQ(MainThroughput().frames_expected, 2u);
907   EXPECT_EQ(MainThroughput().frames_produced, 1u);
908 }
909
910 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame1) {
911   GenerateSequence("b(1)s(1)e(1,0)b(4)");
912   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
913   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
914   FrameSequenceTracker* removal_tracker =
915       collection_.GetRemovalTrackerForTesting(
916           FrameSequenceTrackerType::kTouchScroll);
917   EXPECT_EQ(GetTerminationStatus(removal_tracker),
918             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
919   GenerateSequence("P(1)");
920   // There is still one impl-frame not processed not, so the tracker is not yet
921   // ready for termination.
922   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
923   EXPECT_EQ(GetTerminationStatus(removal_tracker),
924             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
925 }
926
927 // Following 3 cases are for: b(1)s(1)e(1,0)P(1), and StopSequence can happen
928 // anywhere after b and before P.
929 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame2) {
930   base::HistogramTester histogram_tester;
931   // Ensure we have enough data to report.
932   ImplThroughput().frames_expected = 100u;
933   ImplThroughput().frames_produced = 100u;
934
935   GenerateSequence("b(1)");
936   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
937   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
938   FrameSequenceTracker* removal_tracker =
939       collection_.GetRemovalTrackerForTesting(
940           FrameSequenceTrackerType::kTouchScroll);
941   EXPECT_EQ(GetTerminationStatus(removal_tracker),
942             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
943   GenerateSequence("s(1)e(1,0)P(1)");
944   // Now the |removal_tracker| should have been destroyed.
945   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
946
947   std::string metric =
948       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
949   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
950 }
951
952 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame3) {
953   base::HistogramTester histogram_tester;
954   // Ensure we have enough data to report.
955   ImplThroughput().frames_expected = 100u;
956   ImplThroughput().frames_produced = 100u;
957
958   GenerateSequence("b(1)s(1)");
959   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
960   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
961   FrameSequenceTracker* removal_tracker =
962       collection_.GetRemovalTrackerForTesting(
963           FrameSequenceTrackerType::kTouchScroll);
964   EXPECT_EQ(GetTerminationStatus(removal_tracker),
965             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
966   GenerateSequence("e(1,0)P(1)");
967   // Now the |removal_tracker| should have been destroyed.
968   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
969
970   std::string metric =
971       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
972   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
973 }
974
975 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame4) {
976   base::HistogramTester histogram_tester;
977   // Ensure we have enough data to report.
978   ImplThroughput().frames_expected = 100u;
979   ImplThroughput().frames_produced = 100u;
980
981   GenerateSequence("b(1)s(1)e(1,0)");
982   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
983   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
984   FrameSequenceTracker* removal_tracker =
985       collection_.GetRemovalTrackerForTesting(
986           FrameSequenceTrackerType::kTouchScroll);
987   EXPECT_EQ(GetTerminationStatus(removal_tracker),
988             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
989   GenerateSequence("P(1)");
990   // Now the |removal_tracker| should have been destroyed.
991   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
992
993   std::string metric =
994       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
995   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
996 }
997
998 // Following 2 cases are for: b(1)s(1)P(1), and StopSequence can happen
999 // anywhere after b and before P. Because there is no e when P happens, the
1000 // tracker is not ready for termination.
1001 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame5) {
1002   GenerateSequence("b(1)");
1003   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1004   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1005   FrameSequenceTracker* removal_tracker =
1006       collection_.GetRemovalTrackerForTesting(
1007           FrameSequenceTrackerType::kTouchScroll);
1008   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1009             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1010   GenerateSequence("s(1)P(1)");
1011   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1012   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1013             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1014 }
1015
1016 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame6) {
1017   GenerateSequence("b(1)s(1)");
1018   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1019   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1020   FrameSequenceTracker* removal_tracker =
1021       collection_.GetRemovalTrackerForTesting(
1022           FrameSequenceTrackerType::kTouchScroll);
1023   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1024             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1025   GenerateSequence("P(1)");
1026   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1027   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1028             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1029 }
1030
1031 // All the following cases are for one complete impl + one incomplete:
1032 // b(1)s(1)e(1,0)xxxxxxxxP(1)
1033 // The 'xxxxx' is an incomplete impl frame that has no damage, it could be
1034 // 1. b(2)n(2)e(2,0)P(1), and StopSequence can happen anywhere after b and
1035 //    before P.
1036 // 2. b(2)n(2)P(1), and StopSequence can happen anywhere after b and before P.
1037 //    In this case, the tracker is not ready for termination yet because e never
1038 //    happens.
1039 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame7) {
1040   base::HistogramTester histogram_tester;
1041   // Ensure we have enough data to report.
1042   ImplThroughput().frames_expected = 100u;
1043   ImplThroughput().frames_produced = 100u;
1044
1045   GenerateSequence("b(1)s(1)e(1,0)b(2)");
1046   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1047   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1048   FrameSequenceTracker* removal_tracker =
1049       collection_.GetRemovalTrackerForTesting(
1050           FrameSequenceTrackerType::kTouchScroll);
1051   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1052             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1053   GenerateSequence("n(2)e(2,0)P(1)");
1054   // Now the |removal_tracker| should have been destroyed.
1055   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1056
1057   std::string metric =
1058       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1059   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1060 }
1061
1062 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame8) {
1063   base::HistogramTester histogram_tester;
1064   // Ensure we have enough data to report.
1065   ImplThroughput().frames_expected = 100u;
1066   ImplThroughput().frames_produced = 100u;
1067
1068   GenerateSequence("b(1)s(1)e(1,0)b(2)n(2)");
1069   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1070   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1071   FrameSequenceTracker* removal_tracker =
1072       collection_.GetRemovalTrackerForTesting(
1073           FrameSequenceTrackerType::kTouchScroll);
1074   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1075             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1076   GenerateSequence("e(2,0)P(1)");
1077   // Now the |removal_tracker| should have been destroyed.
1078   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1079
1080   std::string metric =
1081       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1082   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1083 }
1084
1085 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame9) {
1086   base::HistogramTester histogram_tester;
1087   // Ensure we have enough data to report.
1088   ImplThroughput().frames_expected = 100u;
1089   ImplThroughput().frames_produced = 100u;
1090
1091   GenerateSequence("b(1)s(1)e(1,0)b(2)n(2)e(2,0)");
1092   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1093   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1094   FrameSequenceTracker* removal_tracker =
1095       collection_.GetRemovalTrackerForTesting(
1096           FrameSequenceTrackerType::kTouchScroll);
1097   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1098             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1099   GenerateSequence("P(1)");
1100   // Now the |removal_tracker| should have been destroyed.
1101   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1102
1103   std::string metric =
1104       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1105   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1106 }
1107
1108 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame10) {
1109   GenerateSequence("b(1)s(1)e(1,0)b(2)");
1110   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1111   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1112   FrameSequenceTracker* removal_tracker =
1113       collection_.GetRemovalTrackerForTesting(
1114           FrameSequenceTrackerType::kTouchScroll);
1115   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1116             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1117   GenerateSequence("n(2)P(1)");
1118   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1119   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1120             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1121 }
1122
1123 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame11) {
1124   GenerateSequence("b(1)s(1)e(1,0)b(2)n(2)");
1125   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1126   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1127   FrameSequenceTracker* removal_tracker =
1128       collection_.GetRemovalTrackerForTesting(
1129           FrameSequenceTrackerType::kTouchScroll);
1130   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1131             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1132   GenerateSequence("P(1)");
1133   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1134   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1135             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1136 }
1137
1138 // Following tests are for the case where the last impl-frame has no damage.
1139 // Basically b(1)s(1)e(1)P(1)b(2)n(2)e(2). And StopSequence can happen any time
1140 // after b(2).
1141 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame12) {
1142   base::HistogramTester histogram_tester;
1143   // Ensure we have enough data to report.
1144   ImplThroughput().frames_expected = 100u;
1145   ImplThroughput().frames_produced = 100u;
1146
1147   GenerateSequence("b(1)s(1)e(1,0)P(1)b(2)");
1148   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1149   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1150   FrameSequenceTracker* removal_tracker =
1151       collection_.GetRemovalTrackerForTesting(
1152           FrameSequenceTrackerType::kTouchScroll);
1153   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1154             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1155   GenerateSequence("n(2)e(2,0)");
1156   // Now the |removal_tracker| should have been destroyed.
1157   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1158
1159   std::string metric =
1160       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1161   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1162 }
1163
1164 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame13) {
1165   base::HistogramTester histogram_tester;
1166   // Ensure we have enough data to report.
1167   ImplThroughput().frames_expected = 100u;
1168   ImplThroughput().frames_produced = 100u;
1169
1170   GenerateSequence("b(1)s(1)e(1,0)P(1)b(2)n(2)");
1171   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1172   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1173   FrameSequenceTracker* removal_tracker =
1174       collection_.GetRemovalTrackerForTesting(
1175           FrameSequenceTrackerType::kTouchScroll);
1176   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1177             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1178   GenerateSequence("e(2,0)");
1179   // Now the |removal_tracker| should have been destroyed.
1180   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1181
1182   std::string metric =
1183       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1184   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1185 }
1186
1187 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame14) {
1188   base::HistogramTester histogram_tester;
1189   // Ensure we have enough data to report.
1190   ImplThroughput().frames_expected = 100u;
1191   ImplThroughput().frames_produced = 100u;
1192
1193   GenerateSequence("b(1)s(1)e(1,0)P(1)b(2)n(2)e(2,0)");
1194   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1195   // The tracker should have been removed from the removal_tracker_ list.
1196   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1197
1198   std::string metric =
1199       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1200   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1201 }
1202
1203 // Following tests are for the case where the presentation of the first impl
1204 // frame arrives late, and a second impl frame has started, and the tracker is
1205 // scheduled to terminate before the second impl frame starts. Basically:
1206 // 1. b(1)s(1)e(1,0)b(2)s(2)e(2,0)P(1), and StopSequence happens anywhere after
1207 // b(1) and before b(2)
1208 // 2. b(1)s(1)e(1,0)b(2)n(2)e(2,0)P(1), and StopSequence happens anywhere after
1209 // b(1) and before b(2)
1210 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame15) {
1211   base::HistogramTester histogram_tester;
1212   // Ensure we have enough data to report.
1213   ImplThroughput().frames_expected = 100u;
1214   ImplThroughput().frames_produced = 100u;
1215
1216   GenerateSequence("b(1)");
1217   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1218   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1219   FrameSequenceTracker* removal_tracker =
1220       collection_.GetRemovalTrackerForTesting(
1221           FrameSequenceTrackerType::kTouchScroll);
1222   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1223             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1224   GenerateSequence("s(1)e(1,0)b(2)s(2)e(2,0)P(1)");
1225   // Now the |removal_tracker| should have been destroyed.
1226   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1227
1228   std::string metric =
1229       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1230   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1231 }
1232
1233 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame16) {
1234   base::HistogramTester histogram_tester;
1235   // Ensure we have enough data to report.
1236   ImplThroughput().frames_expected = 100u;
1237   ImplThroughput().frames_produced = 100u;
1238
1239   GenerateSequence("b(1)s(1)");
1240   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1241   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1242   FrameSequenceTracker* removal_tracker =
1243       collection_.GetRemovalTrackerForTesting(
1244           FrameSequenceTrackerType::kTouchScroll);
1245   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1246             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1247   GenerateSequence("e(1,0)b(2)s(2)e(2,0)P(1)");
1248   // Now the |removal_tracker| should have been destroyed.
1249   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1250
1251   std::string metric =
1252       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1253   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1254 }
1255
1256 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame17) {
1257   base::HistogramTester histogram_tester;
1258   // Ensure we have enough data to report.
1259   ImplThroughput().frames_expected = 100u;
1260   ImplThroughput().frames_produced = 100u;
1261
1262   GenerateSequence("b(1)s(1)e(1,0)");
1263   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1264   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1265   FrameSequenceTracker* removal_tracker =
1266       collection_.GetRemovalTrackerForTesting(
1267           FrameSequenceTrackerType::kTouchScroll);
1268   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1269             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1270   GenerateSequence("b(2)s(2)e(2,0)P(1)");
1271   // Now the |removal_tracker| should have been destroyed.
1272   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1273
1274   std::string metric =
1275       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1276   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1277 }
1278
1279 // The second impl-frame has no damage.
1280 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame18) {
1281   base::HistogramTester histogram_tester;
1282   // Ensure we have enough data to report.
1283   ImplThroughput().frames_expected = 100u;
1284   ImplThroughput().frames_produced = 100u;
1285
1286   GenerateSequence("b(1)");
1287   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1288   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1289   FrameSequenceTracker* removal_tracker =
1290       collection_.GetRemovalTrackerForTesting(
1291           FrameSequenceTrackerType::kTouchScroll);
1292   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1293             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1294   GenerateSequence("s(1)e(1,0)b(2)n(2)e(2,0)P(1)");
1295   // Now the |removal_tracker| should have been destroyed.
1296   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1297
1298   std::string metric =
1299       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1300   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1301 }
1302
1303 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame19) {
1304   base::HistogramTester histogram_tester;
1305   // Ensure we have enough data to report.
1306   ImplThroughput().frames_expected = 100u;
1307   ImplThroughput().frames_produced = 100u;
1308
1309   GenerateSequence("b(1)s(1)");
1310   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1311   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1312   FrameSequenceTracker* removal_tracker =
1313       collection_.GetRemovalTrackerForTesting(
1314           FrameSequenceTrackerType::kTouchScroll);
1315   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1316             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1317   GenerateSequence("e(1,0)b(2)n(2)e(2,0)P(1)");
1318   // Now the |removal_tracker| should have been destroyed.
1319   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1320
1321   std::string metric =
1322       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1323   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1324 }
1325
1326 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame20) {
1327   base::HistogramTester histogram_tester;
1328   // Ensure we have enough data to report.
1329   ImplThroughput().frames_expected = 100u;
1330   ImplThroughput().frames_produced = 100u;
1331
1332   GenerateSequence("b(1)s(1)e(1,0)");
1333   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1334   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1335   FrameSequenceTracker* removal_tracker =
1336       collection_.GetRemovalTrackerForTesting(
1337           FrameSequenceTrackerType::kTouchScroll);
1338   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1339             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1340   GenerateSequence("b(2)n(2)e(2,0)P(1)");
1341   // Now the |removal_tracker| should have been destroyed.
1342   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1343
1344   std::string metric =
1345       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1346   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1347 }
1348
1349 // Following cases test that no frame needs to be presented, basically:
1350 // b(1)n(1)e(1,0), and StopSequence can happen anytime after b(1).
1351 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame21) {
1352   base::HistogramTester histogram_tester;
1353   // Ensure we have enough data to report.
1354   ImplThroughput().frames_expected = 100u;
1355   ImplThroughput().frames_produced = 100u;
1356
1357   GenerateSequence("b(1)");
1358   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1359   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1360   FrameSequenceTracker* removal_tracker =
1361       collection_.GetRemovalTrackerForTesting(
1362           FrameSequenceTrackerType::kTouchScroll);
1363   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1364             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1365   GenerateSequence("n(1)e(1,0)");
1366   // Ensure that this tracker is actually removed from the |removal_trackers_|
1367   // before the test terminates.
1368   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1369
1370   // If the tracker is terminated successfully, we should see this UMA.
1371   std::string metric =
1372       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1373   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1374 }
1375
1376 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame22) {
1377   base::HistogramTester histogram_tester;
1378   // Ensure we have enough data to report.
1379   ImplThroughput().frames_expected = 100u;
1380   ImplThroughput().frames_produced = 100u;
1381
1382   GenerateSequence("b(1)n(1)");
1383   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1384   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1385   FrameSequenceTracker* removal_tracker =
1386       collection_.GetRemovalTrackerForTesting(
1387           FrameSequenceTrackerType::kTouchScroll);
1388   EXPECT_EQ(GetTerminationStatus(removal_tracker),
1389             FrameSequenceTracker::TerminationStatus::kScheduledForTermination);
1390   GenerateSequence("e(1,0)");
1391   // Ensure that this tracker is actually removed from the |removal_trackers_|
1392   // before the test terminates.
1393   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1394
1395   // If the tracker is terminated successfully, we should see this UMA.
1396   std::string metric =
1397       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1398   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1399 }
1400
1401 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame23) {
1402   base::HistogramTester histogram_tester;
1403   // Ensure we have enough data to report.
1404   ImplThroughput().frames_expected = 100u;
1405   ImplThroughput().frames_produced = 100u;
1406
1407   GenerateSequence("b(1)n(1)e(1,0)");
1408   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1409   // Ensure that this tracker is actually removed from the |removal_trackers_|
1410   // before the test terminates.
1411   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1412
1413   // If the tracker is terminated successfully, we should see this UMA.
1414   std::string metric =
1415       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1416   EXPECT_EQ(histogram_tester.GetBucketCount(metric, 0), 1);
1417 }
1418
1419 // This test ensure that the tracker would terminate at e.
1420 TEST_F(FrameSequenceTrackerTest, TrackLastImplFrame24) {
1421   GenerateSequence("b(1)s(1)P(1)");
1422   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1423   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1424   GenerateSequence("e(1,0)");
1425   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1426 }
1427
1428 TEST_F(FrameSequenceTrackerTest, IgnoredFrameTokensRemovedAtPresentation1) {
1429   GenerateSequence("b(5)s(1)e(5,0)P(1)");
1430   auto args = CreateBeginFrameArgs(/*source_id=*/1u, 1u);
1431   // Ack to an impl frame that doesn't exist in this tracker.
1432   collection_.NotifySubmitFrame(2, /*has_missing_content=*/false,
1433                                 viz::BeginFrameAck(args, true), args);
1434   EXPECT_EQ(IgnoredFrameTokens().size(), 1u);
1435   GenerateSequence("P(3)");
1436   // Any token that is < 3 should have been removed.
1437   EXPECT_EQ(IgnoredFrameTokens().size(), 0u);
1438 }
1439
1440 // Test the case where the frame tokens wraps around the 32-bit max value.
1441 TEST_F(FrameSequenceTrackerTest, IgnoredFrameTokensRemovedAtPresentation2) {
1442   GenerateSequence("b(5)");
1443   auto args = CreateBeginFrameArgs(1u, 1u);
1444   // Ack to an impl frame that doesn't exist in this tracker.
1445   collection_.NotifySubmitFrame(UINT32_MAX, /*has_missing_content=*/false,
1446                                 viz::BeginFrameAck(args, true), args);
1447   EXPECT_EQ(IgnoredFrameTokens().size(), 1u);
1448
1449   args = CreateBeginFrameArgs(1u, 5u);
1450   collection_.NotifySubmitFrame(1, false, viz::BeginFrameAck(args, true), args);
1451   GenerateSequence("e(5,0)P(1)");
1452   EXPECT_TRUE(IgnoredFrameTokens().empty());
1453 }
1454
1455 TEST_F(FrameSequenceTrackerTest, TerminationWithNullPresentationTimeStamp) {
1456   GenerateSequence("b(1)s(1)");
1457   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1458   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1459   // Even if the presentation timestamp is null, as long as this presentation
1460   // is acking the last impl frame, we consider that impl frame completed and
1461   // so the tracker is ready for termination.
1462   collection_.NotifyFramePresented(
1463       1, {base::TimeTicks(), viz::BeginFrameArgs::DefaultInterval(), 0});
1464   GenerateSequence("e(1,0)");
1465   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1466 }
1467
1468 // Test that a tracker is terminated after 3 submitted frames, remove this
1469 // once crbug.com/1072482 is fixed.
1470 TEST_F(FrameSequenceTrackerTest, TerminationAfterThreeSubmissions1) {
1471   GenerateSequence("b(1)s(1)e(1,0)");
1472   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1473   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1474   GenerateSequence("b(2)s(2)e(2,0)b(3)s(3)e(3,0)b(4)s(4)e(4,0)b(5)s(5)e(5,0)");
1475   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1476 }
1477
1478 TEST_F(FrameSequenceTrackerTest, TerminationAfterThreeSubmissions2) {
1479   GenerateSequence("b(1)");
1480   auto args = CreateBeginFrameArgs(1u, 1u);
1481   // Ack to an impl frame that doesn't exist in this tracker.
1482   collection_.NotifySubmitFrame(UINT32_MAX, /*has_missing_content=*/false,
1483                                 viz::BeginFrameAck(args, true), args);
1484   GenerateSequence("e(1,0)");
1485   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1486   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1487   GenerateSequence("b(2)s(1)e(2,0)b(3)s(2)e(3,0)b(4)s(3)e(4,0)");
1488   EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
1489 }
1490
1491 TEST_F(FrameSequenceTrackerTest, TerminationAfterThreeSubmissions3) {
1492   GenerateSequence(
1493       "b(1)s(1)e(1,0)P(1)b(2)s(2)e(2,0)P(2)b(3)s(3)e(3,0)P(3)b(4)");
1494   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1495   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1496   GenerateSequence("s(4)");
1497   EXPECT_EQ(NumberOfRemovalTrackers(), 1u);
1498 }
1499
1500 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage1) {
1501   const char sequence[] =
1502       "b(1)B(0,1)n(1)e(1,0)b(2)E(1)B(1,2)n(2)e(2,1)b(3)E(2)B(2,3)n(3)e(3,2)";
1503   GenerateSequence(sequence);
1504   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
1505   // At E(2), B(0,1) is treated no damage.
1506   EXPECT_EQ(MainThroughput().frames_expected, 2u);
1507 }
1508
1509 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage2) {
1510   const char sequence[] =
1511       "b(1)B(0,1)n(1)e(1,0)b(2)E(1)B(1,2)n(2)e(2,1)b(3)n(3)e(3,1)b(4)n(4)e(4,1)"
1512       "b(8)E(2)"
1513       "B(8,8)n(8)e(8,2)";
1514   GenerateSequence(sequence);
1515   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
1516   // At E(2), B(0,1) is treated as no damage.
1517   EXPECT_EQ(MainThroughput().frames_expected, 7u);
1518 }
1519
1520 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage3) {
1521   const char sequence[] =
1522       "b(34)B(0,34)n(34)e(34,0)b(35)n(35)e(35,0)b(36)E(34)n(36)e(36,34)b(39)s("
1523       "1)e(39,34)";
1524   GenerateSequence(sequence);
1525   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1526   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1527 }
1528
1529 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage4) {
1530   const char sequence[] =
1531       "b(9)B(0,9)n(9)Re(9,0)E(9)b(11)B(0,11)n(11)e(11,9)b(12)E(11)B(11,12)s(1)"
1532       "S(11)e(12,11)b(13)E(12)s(2)S(12)";
1533   GenerateSequence(sequence);
1534   EXPECT_EQ(ImplThroughput().frames_expected, 2u);
1535   EXPECT_EQ(MainThroughput().frames_expected, 2u);
1536 }
1537
1538 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage5) {
1539   const char sequence[] =
1540       "b(1)B(0,1)E(1)s(1)S(1)e(1,0)b(2)n(2)e(2,0)b(3)B(1,3)n(3)e(3,0)E(3)b(4)B("
1541       "3,4)n("
1542       "4)e(4,3)E(4)";
1543   GenerateSequence(sequence);
1544   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1545   // At E(4), we treat B(1,3) as if it had no damage.
1546   EXPECT_EQ(MainThroughput().frames_expected, 3u);
1547 }
1548
1549 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage6) {
1550   const char sequence[] =
1551       "b(1)B(0,1)E(1)s(1)S(1)e(1,1)b(2)B(1,2)E(2)n(2)N(2,2)e(2,2)b(3)B(0,3)E(3)"
1552       "n(3)"
1553       "N(3,3)e(3,3)";
1554   GenerateSequence(sequence);
1555   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1556   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1557 }
1558
1559 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage7) {
1560   const char sequence[] =
1561       "b(8)B(0,8)n(8)e(8,0)b(9)E(8)B(8,9)E(9)s(1)S(8)e(9,9)b(10)s(2)S(9)e(10,"
1562       "9)";
1563   GenerateSequence(sequence);
1564   EXPECT_EQ(ImplThroughput().frames_expected, 2u);
1565   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1566 }
1567
1568 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage8) {
1569   const char sequence[] =
1570       "b(18)B(0,18)E(18)n(18)N(18,18)Re(18,18)b(20)B(0,20)N(20,20)n(20)N(0,20)"
1571       "e("
1572       "20,18)b(21)B(0,21)E(21)s(1)S(21)e(21,21)";
1573   GenerateSequence(sequence);
1574   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1575   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1576 }
1577
1578 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage9) {
1579   const char sequence[] =
1580       "b(78)n(78)Re(78,0)Rb(82)B(0,82)E(82)n(82)N(82,82)Re(82,82)b(86)B(0,86)E("
1581       "86)n("
1582       "86)e(86,86)b(87)s(1)S(86)e(87,86)";
1583   GenerateSequence(sequence);
1584   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1585   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1586 }
1587
1588 TEST_F(FrameSequenceTrackerTest, OffScreenMainDamage10) {
1589   const char sequence[] =
1590       "b(2)B(0,2)E(2)n(2)N(2,2)e(2,2)b(3)B(0,3)E(3)n(3)N(3,3)e(3,3)b(4)B(0,4)E("
1591       "4)n("
1592       "4)N(4,4)e(4,4)b(5)B(0,5)E(5)n(5)N(5,5)e(5,5)b(6)B(0,6)n(6)e(6,5)E(6)Rb("
1593       "8)B(0,"
1594       "8)E(8)n(8)N(8,8)e(8,8)";
1595   GenerateSequence(sequence);
1596   EXPECT_EQ(ImplThroughput().frames_expected, 0u);
1597   EXPECT_EQ(MainThroughput().frames_expected, 0u);
1598 }
1599
1600 // A presentation with a frame token that is > the main frame token submitted.
1601 TEST_F(FrameSequenceTrackerTest, MainThreadPresentWithNonMatchedToken) {
1602   const char sequence[] = "b(1)B(0,1)E(1)s(1)S(1)e(1,0)b(2)s(2)S(1)e(2,1)P(2)";
1603   GenerateSequence(sequence);
1604   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1605   EXPECT_EQ(MainThroughput().frames_produced, 1u);
1606 }
1607
1608 TEST_F(FrameSequenceTrackerTest, CoalescedMainThreadPresent) {
1609   const char sequence[] =
1610       "b(1)B(0,1)E(1)s(1)S(1)e(1,1)b(2)B(1,2)E(2)s(2)S(2)e(2,2)P(2)";
1611   GenerateSequence(sequence);
1612   EXPECT_EQ(MainThroughput().frames_expected, 2u);
1613   EXPECT_EQ(MainThroughput().frames_produced, 1u);
1614 }
1615
1616 TEST_F(FrameSequenceTrackerTest, MainThreadPresentWithNullTimeStamp) {
1617   const char sequence[] = "b(1)B(0,1)E(1)s(1)S(1)e(1,1)";
1618   GenerateSequence(sequence);
1619   collection_.NotifyFramePresented(
1620       1, {base::TimeTicks(), viz::BeginFrameArgs::DefaultInterval(),
1621           gfx::PresentationFeedback::kFailure});
1622   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1623   // No presentation, no main frame produced.
1624   EXPECT_EQ(MainThroughput().frames_produced, 0u);
1625   GenerateSequence("b(2)s(2)S(1)e(2,0)P(2)");
1626   EXPECT_EQ(MainThroughput().frames_expected, 1u);
1627   // The main frame update is caught up here.
1628   EXPECT_EQ(MainThroughput().frames_produced, 1u);
1629 }
1630
1631 TEST_F(FrameSequenceTrackerTest, TrackerTypeEncoding) {
1632   // The test begins with a kTouchScroll tracker
1633   EXPECT_EQ(NumberOfTrackers(), 1u);
1634   ActiveFrameSequenceTrackers active_encoded =
1635       collection_.FrameSequenceTrackerActiveTypes();
1636   EXPECT_EQ(active_encoded, 16);  // 1 << 4
1637 }
1638
1639 TEST_F(FrameSequenceTrackerTest, CustomTrackers) {
1640   CustomTrackerResults results;
1641   collection_.set_custom_tracker_results_added_callback(
1642       base::BindLambdaForTesting([&](const CustomTrackerResults& reported) {
1643         for (const auto& pair : reported)
1644           results[pair.first] = pair.second;
1645       }));
1646
1647   // Start custom tracker 1.
1648   collection_.StartCustomSequence(1);
1649   EXPECT_EQ(1u, NumberOfCustomTrackers());
1650
1651   // No reports.
1652   uint32_t frame_token = 1u;
1653   collection_.NotifyFramePresented(frame_token, {});
1654   EXPECT_EQ(0u, results.size());
1655
1656   // Start custom tracker 2 and 3 in addition to 1.
1657   collection_.StartCustomSequence(2);
1658   collection_.StartCustomSequence(3);
1659   EXPECT_EQ(3u, NumberOfCustomTrackers());
1660
1661   // All custom trackers are running. No reports.
1662   collection_.NotifyFramePresented(frame_token, {});
1663   EXPECT_EQ(0u, results.size());
1664
1665   // Tracker 2 is stopped and scheduled to terminate.
1666   collection_.StopCustomSequence(2);
1667   EXPECT_EQ(2u, NumberOfCustomTrackers());
1668
1669   // Tracker 2 has zero expected frames.
1670   collection_.NotifyFramePresented(frame_token, {});
1671   EXPECT_EQ(1u, results.size());
1672   EXPECT_EQ(0u, results[2].frames_expected);
1673
1674   // Simple sequence of one frame.
1675   const char sequence[] = "b(1)B(0,1)s(1)S(1)e(1,0)P(1)";
1676   GenerateSequence(sequence);
1677
1678   // Stop all custom trackers.
1679   collection_.StopCustomSequence(1);
1680   collection_.StopCustomSequence(3);
1681   EXPECT_EQ(0u, NumberOfCustomTrackers());
1682
1683   // Tracker 1 and 3 and should report.
1684   collection_.NotifyFramePresented(frame_token, {});
1685   EXPECT_EQ(3u, results.size());
1686   EXPECT_EQ(1u, results[1].frames_produced);
1687   EXPECT_EQ(1u, results[1].frames_expected);
1688   EXPECT_EQ(0u, results[2].frames_produced);
1689   EXPECT_EQ(0u, results[2].frames_expected);
1690   EXPECT_EQ(1u, results[3].frames_produced);
1691   EXPECT_EQ(1u, results[3].frames_expected);
1692 }
1693
1694 TEST_F(FrameSequenceTrackerTest, MergeTrackers) {
1695   // Generate two sequences of scrolls: first with only 1 frame, and then with
1696   // 99 frames. Verify that the two scrolls are merged to report a single
1697   // metric.
1698   base::HistogramTester histogram_tester;
1699   const char first_sequence[] = "b(1)s(1)e(1,0)P(1)";
1700   GenerateSequence(first_sequence);
1701   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1702   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
1703   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1704
1705   const char metric[] =
1706       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1707   histogram_tester.ExpectTotalCount(metric, 0u);
1708   EXPECT_FALSE(TrackerExists(FrameSequenceTrackerType::kTouchScroll));
1709
1710   CreateNewTracker();
1711   const char second_sequence[] = "b(2)s(2)e(2,0)P(2)b(100)s(3)e(100,0)P(3)";
1712   GenerateSequence(second_sequence);
1713   EXPECT_EQ(ImplThroughput().frames_expected, 99u);
1714   EXPECT_EQ(ImplThroughput().frames_produced, 2u);
1715   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1716   EXPECT_FALSE(TrackerExists(FrameSequenceTrackerType::kTouchScroll));
1717   histogram_tester.ExpectTotalCount(metric, 1u);
1718   EXPECT_THAT(histogram_tester.GetAllSamples(metric),
1719               testing::ElementsAre(base::Bucket(97, 1)));
1720 }
1721
1722 TEST_F(FrameSequenceTrackerTest, MergeTrackersPresentAfterStopSequence) {
1723   // Generate two sequences of scrolls: first with only 1 frame, and then with
1724   // 99 frames. Verify that the two scrolls are merged to report a single
1725   // metric. For the second sequence, the last frame is presented after the
1726   // sequence ends.
1727   base::HistogramTester histogram_tester;
1728   const char first_sequence[] = "b(1)s(1)e(1,0)P(1)";
1729   GenerateSequence(first_sequence);
1730   EXPECT_EQ(ImplThroughput().frames_expected, 1u);
1731   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
1732   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1733
1734   const char metric[] =
1735       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1736   histogram_tester.ExpectTotalCount(metric, 0u);
1737   EXPECT_FALSE(TrackerExists(FrameSequenceTrackerType::kTouchScroll));
1738
1739   CreateNewTracker();
1740   const char second_sequence[] = "b(2)s(2)e(2,0)P(2)b(100)s(3)e(100,0)";
1741   GenerateSequence(second_sequence);
1742   EXPECT_EQ(ImplThroughput().frames_expected, 99u);
1743   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
1744   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1745   GenerateSequence("P(3)");
1746   histogram_tester.ExpectTotalCount(metric, 1u);
1747   EXPECT_THAT(histogram_tester.GetAllSamples(metric),
1748               testing::ElementsAre(base::Bucket(97, 1)));
1749 }
1750
1751 TEST_F(FrameSequenceTrackerTest, MergeTrackersScrollOnSameThread) {
1752   // Do a short scroll on the compositor thread, then do another short scroll on
1753   // the compositor thread. Make sure these are merged.
1754   base::HistogramTester histogram_tester;
1755   const char first_sequence[] = "b(1)s(1)e(1,0)P(1)b(80)s(2)e(80,0)P(2)";
1756   GenerateSequence(first_sequence);
1757   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1758
1759   CreateNewTracker(FrameInfo::SmoothEffectDrivingThread::kCompositor);
1760   const char second_sequence[] = "b(81)s(3)e(81,0)P(3)b(101)s(4)e(101,0)P(4)";
1761   GenerateSequence(second_sequence);
1762   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1763
1764   const char comp_metric[] =
1765       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1766   const char main_metric[] =
1767       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll";
1768   histogram_tester.ExpectTotalCount(comp_metric, 1u);
1769   histogram_tester.ExpectTotalCount(main_metric, 0u);
1770 }
1771
1772 TEST_F(FrameSequenceTrackerTest, MergeTrackersScrollOnDifferentThreads) {
1773   // Do a short scroll on the compositor thread, then do another short scroll on
1774   // the main-thread. Make sure these are not merged.
1775   base::HistogramTester histogram_tester;
1776   const char compscroll_sequence[] = "b(1)s(1)e(1,0)P(1)b(80)s(2)e(80,0)P(2)";
1777   GenerateSequence(compscroll_sequence);
1778   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1779
1780   CreateNewTracker(FrameInfo::SmoothEffectDrivingThread::kMain);
1781   const char mainscroll_sequence[] =
1782       "b(81)s(3)e(81,0)P(3)b(101)s(4)e(101,0)P(4)";
1783   GenerateSequence(mainscroll_sequence);
1784   collection_.StopSequence(FrameSequenceTrackerType::kTouchScroll);
1785
1786   const char comp_metric[] =
1787       "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.TouchScroll";
1788   const char main_metric[] =
1789       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll";
1790   histogram_tester.ExpectTotalCount(comp_metric, 0u);
1791   histogram_tester.ExpectTotalCount(main_metric, 0u);
1792 }
1793
1794 }  // namespace cc