[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / frame_sorter_unittest.cc
1 // Copyright 2020 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_sorter.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "cc/metrics/frame_info.h"
14 #include "cc/test/fake_frame_info.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace cc {
18
19 // Test class for FrameSorter
20 class FrameSorterTest : public testing::Test {
21  public:
22   FrameSorterTest()
23       : frame_sorter_(base::BindRepeating(&FrameSorterTest::FlushFrame,
24                                           base::Unretained(this))) {
25     IncreaseSourceId();
26   }
27   ~FrameSorterTest() override = default;
28
29   const viz::BeginFrameArgs GetNextFrameArgs() {
30     uint64_t sequence_number = next_frame_sequence_number_++;
31     return viz::BeginFrameArgs::Create(
32         BEGINFRAME_FROM_HERE, next_frame_source_id_, sequence_number,
33         last_begin_frame_time_,
34         last_begin_frame_time_ + viz::BeginFrameArgs::DefaultInterval(),
35         viz::BeginFrameArgs::DefaultInterval(), viz::BeginFrameArgs::NORMAL);
36   }
37
38   void IncreaseSourceId() {
39     next_frame_source_id_++;
40     current_frame_id_ = -1;
41     args_.clear();
42     next_frame_sequence_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
43   }
44
45   // Simulates a sequence of queries
46   // Possible queries:
47   // "S{frame_number}": Start frame.
48   // "D{frame_number}": End frame as dropped.
49   // "P{frame_number}": End frame as none-dropped (presented).
50   // "E{frame_number}": Frame expects twp acks.
51   // "I": Increase source_id (simulating a crash).
52   // "R": Reset the frame sorter.
53   // Method expects the start of frames to be in order starting with 1.
54   void SimulateQueries(std::vector<std::string> queries) {
55     // Keeps track of how many times a frame is terminated.
56     std::map<int, int> end_counters;
57
58     for (auto& query : queries) {
59       int id;
60       base::StringToInt(query.substr(1), &id);
61       if (id > current_frame_id_) {
62         current_frame_id_++;
63         args_.push_back(GetNextFrameArgs());
64       }
65       switch (query[0]) {
66         case 'S':
67           frame_sorter_.AddNewFrame(args_[id]);
68           break;
69         case 'D': {
70           ++end_counters[id];
71           FrameInfo info =
72               CreateFakeFrameInfo(FrameInfo::FrameFinalState::kDropped);
73           if (end_counters[id] == 1) {
74             // For the first response to the frame, mark it as not including
75             // update from the main-thread.
76             info.main_thread_response = FrameInfo::MainThreadResponse::kMissing;
77           } else {
78             DCHECK_EQ(2, end_counters[id]);
79             info.main_thread_response =
80                 FrameInfo::MainThreadResponse::kIncluded;
81           }
82           frame_sorter_.AddFrameResult(args_[id], info);
83           break;
84         }
85         case 'P': {
86           ++end_counters[id];
87           FrameInfo info =
88               CreateFakeFrameInfo(FrameInfo::FrameFinalState::kPresentedAll);
89           if (end_counters[id] == 1) {
90             // For the first response to the frame, mark it as not including
91             // update from the main-thread.
92             info.main_thread_response = FrameInfo::MainThreadResponse::kMissing;
93           } else {
94             DCHECK_EQ(2, end_counters[id]);
95             info.main_thread_response =
96                 FrameInfo::MainThreadResponse::kIncluded;
97           }
98           frame_sorter_.AddFrameResult(args_[id], info);
99           break;
100         }
101         case 'I':
102           IncreaseSourceId();
103           break;
104         case 'R':
105           frame_sorter_.Reset();
106           break;
107       }
108     }
109   }
110
111   void ValidateResults(
112       std::vector<std::pair<uint64_t, bool>> expected_results) {
113     EXPECT_EQ(sorted_frames_.size(), expected_results.size());
114     int result_index = 0;
115     for (auto result : expected_results) {
116       auto& sorted_frame = sorted_frames_[result_index];
117       EXPECT_EQ(sorted_frame.first.frame_id.sequence_number, result.first + 1);
118       EXPECT_EQ(sorted_frame.second, result.second);
119       result_index++;
120     }
121   }
122
123  private:
124   void FlushFrame(const viz::BeginFrameArgs& args, const FrameInfo& frame) {
125     sorted_frames_.emplace_back(args, frame.IsDroppedAffectingSmoothness());
126   }
127
128   FrameSorter frame_sorter_;
129   std::vector<std::pair<const viz::BeginFrameArgs, bool>> sorted_frames_;
130   base::TimeTicks last_begin_frame_time_ = base::TimeTicks::Now();
131   uint64_t next_frame_source_id_ = 0;
132   uint64_t next_frame_sequence_number_ =
133       viz::BeginFrameArgs::kStartingFrameNumber;
134   std::vector<const viz::BeginFrameArgs> args_ = {};
135   int current_frame_id_ = -1;
136 };
137
138 TEST_F(FrameSorterTest, TestSortingFrames) {
139   // Frame end in order of F0, F2, F1, F3, but they should be flushed in the
140   // order they began (eg. F0, F1, F2, F3).
141   std::vector<std::string> queries = {"S0", "S1", "P0", "S2",
142                                       "P2", "S3", "P1", "D3"};
143   std::vector<std::pair<uint64_t, bool>> expected_results = {
144       {0, false}, {1, false}, {2, false}, {3, true}};
145
146   SimulateQueries(queries);
147   ValidateResults(expected_results);
148 }
149
150 TEST_F(FrameSorterTest, ResetInMiddleOfAcks) {
151   // Reset occur in between the start and ack of F1 & F3, so except these two
152   // all other frames should be flushed in order in the sorted_frames_.
153   std::vector<std::string> queries = {"S0", "S1", "P0", "S2", "P2", "S3",
154                                       "R",  "S4", "P1", "D4", "D3"};
155   std::vector<std::pair<uint64_t, bool>> expected_results = {
156       {0, false}, {2, false}, {4, true}};
157
158   SimulateQueries(queries);
159   ValidateResults(expected_results);
160 }
161
162 TEST_F(FrameSorterTest, ExpectingMultipleAcks) {
163   // F1 has multiple acks and the final ack is received at the end. Which makes
164   // other frames to wait in pending tree before being flushed, all in order.
165   // Also in any of the duplicated acks report a dropped frame, the overall
166   // status for that frame should be dropped.
167   std::vector<std::string> queries = {"S0", "S1", "P0", "S1", "S2", "P2",
168                                       "S3", "S4", "P1", "D3", "D4", "D1"};
169   std::vector<std::pair<uint64_t, bool>> expected_results = {
170       {0, false}, {1, true}, {2, false}, {3, true}, {4, true}};
171
172   SimulateQueries(queries);
173   ValidateResults(expected_results);
174 }
175
176 TEST_F(FrameSorterTest, ExpectingMultipleAcksWithReset) {
177   // Combination of last two tests. Reset occurs in middle of start and ack of
178   // F1 and F3. Also F1 expects two acks, which both are received after reset.
179   std::vector<std::string> queries = {"S0", "S1", "P0", "S1", "S2", "P2", "S3",
180                                       "R",  "S4", "P1", "D1", "D4", "D3"};
181   std::vector<std::pair<uint64_t, bool>> expected_results = {
182       {0, false}, {2, false}, {4, true}};
183
184   SimulateQueries(queries);
185   ValidateResults(expected_results);
186 }
187
188 TEST_F(FrameSorterTest, ExpectingMultipleAcksWithReset2) {
189   // Reset occurs in middle of the two starts of F0.
190   // This is to test if F1 will be flushed properly while being in between the
191   // two acks of F0, which should be ignored as a result of reset.
192   std::vector<std::string> queries = {"S0", "R", "S0", "P0", "S1", "D0", "D1"};
193   std::vector<std::pair<uint64_t, bool>> expected_results = {{1, true}};
194
195   SimulateQueries(queries);
196   ValidateResults(expected_results);
197 }
198
199 TEST_F(FrameSorterTest, ExpectingMultipleAcksWithSourceIdIncrease) {
200   // Reset and increase in source_id occurs in middle start and ack of F1.
201   // This is to simulate a navigation. So the initial F0 has source_id of 0
202   // while the F0 after reset has source_id of 1, and because of that the
203   // start and ack for F0 after the reset is not ignored (The ignore is only
204   // needed when frame has the same source_id and sequence_number).
205   std::vector<std::string> queries = {"S0", "S0", "S1", "S1", "I",  "R",
206                                       "S0", "S0", "P0", "S1", "P1", "D0"};
207   std::vector<std::pair<uint64_t, bool>> expected_results = {{0, true},
208                                                              {1, false}};
209
210   SimulateQueries(queries);
211   ValidateResults(expected_results);
212 }
213
214 }  // namespace cc