1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 #pragma clang diagnostic ignored "-Wextra"
21
22 #undef LOG_TAG
23 #define LOG_TAG "LibSurfaceFlingerUnittests"
24
25 #include <TimeStats/TimeStats.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include <log/log.h>
29 #include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
30 #include <utils/String16.h>
31 #include <utils/Vector.h>
32
33 #include <chrono>
34 #include <random>
35 #include <unordered_set>
36
37 #include "libsurfaceflinger_unittest_main.h"
38
39 using namespace android::surfaceflinger;
40 using namespace google::protobuf;
41 using namespace std::chrono_literals;
42
43 namespace android {
44 namespace {
45
46 using testing::_;
47 using testing::AnyNumber;
48 using testing::Contains;
49 using testing::HasSubstr;
50 using testing::InSequence;
51 using testing::Not;
52 using testing::SizeIs;
53 using testing::StrEq;
54 using testing::UnorderedElementsAre;
55
56 using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
57 using SurfaceflingerStatsLayerInfo = android::surfaceflinger::SurfaceflingerStatsLayerInfo;
58 using SurfaceflingerStatsLayerInfoWrapper =
59 android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper;
60
61 // clang-format off
62 #define FMT_PROTO true
63 #define FMT_STRING false
64 #define LAYER_ID_0 0
65 #define LAYER_ID_1 1
66 #define UID_0 123
67 #define REFRESH_RATE_0 61
68 #define RENDER_RATE_0 31
69 #define REFRESH_RATE_BUCKET_0 60
70 #define RENDER_RATE_BUCKET_0 30
71 #define LAYER_ID_INVALID -1
72 #define NUM_LAYERS 1
73 #define NUM_LAYERS_INVALID "INVALID"
74
75 const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
76 const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
77 static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported;
78
79 enum InputCommand : int32_t {
80 ENABLE = 0,
81 DISABLE = 1,
82 CLEAR = 2,
83 DUMP_ALL = 3,
84 DUMP_MAXLAYERS_1 = 4,
85 DUMP_MAXLAYERS_INVALID = 5,
86 INPUT_COMMAND_BEGIN = ENABLE,
87 INPUT_COMMAND_END = DUMP_MAXLAYERS_INVALID,
88 INPUT_COMMAND_RANGE = INPUT_COMMAND_END - INPUT_COMMAND_BEGIN + 1,
89 };
90
91 enum TimeStamp : int32_t {
92 POST = 0,
93 ACQUIRE = 1,
94 ACQUIRE_FENCE = 2,
95 LATCH = 3,
96 DESIRED = 4,
97 PRESENT = 5,
98 PRESENT_FENCE = 6,
99 TIME_STAMP_BEGIN = POST,
100 TIME_STAMP_END = PRESENT,
101 TIME_STAMP_RANGE = TIME_STAMP_END - TIME_STAMP_BEGIN + 1,
102 };
103
104 static const TimeStamp NORMAL_SEQUENCE[] = {
105 TimeStamp::POST,
106 TimeStamp::ACQUIRE,
107 TimeStamp::LATCH,
108 TimeStamp::DESIRED,
109 TimeStamp::PRESENT,
110 };
111
112 static const TimeStamp NORMAL_SEQUENCE_2[] = {
113 TimeStamp::POST,
114 TimeStamp::ACQUIRE_FENCE,
115 TimeStamp::LATCH,
116 TimeStamp::DESIRED,
117 TimeStamp::PRESENT_FENCE,
118 };
119
120 static const TimeStamp UNORDERED_SEQUENCE[] = {
121 TimeStamp::ACQUIRE,
122 TimeStamp::LATCH,
123 TimeStamp::POST,
124 TimeStamp::DESIRED,
125 TimeStamp::PRESENT,
126 };
127
128 static const TimeStamp INCOMPLETE_SEQUENCE[] = {
129 TimeStamp::POST,
130 };
131 // clang-format on
132
133 class TimeStatsTest : public testing::Test {
134 public:
TimeStatsTest()135 TimeStatsTest() {
136 const ::testing::TestInfo* const test_info =
137 ::testing::UnitTest::GetInstance()->current_test_info();
138 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
139 }
140
~TimeStatsTest()141 ~TimeStatsTest() {
142 const ::testing::TestInfo* const test_info =
143 ::testing::UnitTest::GetInstance()->current_test_info();
144 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
145 }
146
147 std::string inputCommand(InputCommand cmd, bool useProto);
148
149 void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts,
150 TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode);
151
152 int32_t genRandomInt32(int32_t begin, int32_t end);
153
154 template <size_t N>
insertTimeRecord(const TimeStamp (& sequence)[N],int32_t id,uint64_t frameNumber,nsecs_t ts,TimeStats::SetFrameRateVote frameRateVote={},int32_t gameMode=kGameMode)155 void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber,
156 nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {},
157 int32_t gameMode = kGameMode) {
158 for (size_t i = 0; i < N; i++, ts += 1000000) {
159 setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote, gameMode);
160 }
161 }
162
163 std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
164 std::unique_ptr<TimeStats> mTimeStats =
165 std::make_unique<impl::TimeStats>(std::nullopt, std::nullopt);
166 };
167
inputCommand(InputCommand cmd,bool useProto)168 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
169 std::string result;
170 Vector<String16> args;
171
172 switch (cmd) {
173 case InputCommand::ENABLE:
174 args.push_back(String16("-enable"));
175 break;
176 case InputCommand::DISABLE:
177 args.push_back(String16("-disable"));
178 break;
179 case InputCommand::CLEAR:
180 args.push_back(String16("-clear"));
181 break;
182 case InputCommand::DUMP_ALL:
183 args.push_back(String16("-dump"));
184 break;
185 case InputCommand::DUMP_MAXLAYERS_1:
186 args.push_back(String16("-dump"));
187 args.push_back(String16("-maxlayers"));
188 args.push_back(String16(std::to_string(NUM_LAYERS).c_str()));
189 break;
190 case InputCommand::DUMP_MAXLAYERS_INVALID:
191 args.push_back(String16("-dump"));
192 args.push_back(String16("-maxlayers"));
193 args.push_back(String16(NUM_LAYERS_INVALID));
194 break;
195 default:
196 ALOGD("Invalid control command");
197 }
198
199 EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, result));
200 return result;
201 }
202
genLayerName(int32_t layerId)203 static std::string genLayerName(int32_t layerId) {
204 return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.example.fake#") + std::to_string(layerId);
205 }
206
setTimeStamp(TimeStamp type,int32_t id,uint64_t frameNumber,nsecs_t ts,TimeStats::SetFrameRateVote frameRateVote,int32_t gameMode)207 void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts,
208 TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode) {
209 switch (type) {
210 case TimeStamp::POST:
211 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id),
212 UID_0, ts, gameMode));
213 break;
214 case TimeStamp::ACQUIRE:
215 ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts));
216 break;
217 case TimeStamp::ACQUIRE_FENCE:
218 ASSERT_NO_FATAL_FAILURE(
219 mTimeStats->setAcquireFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
220 break;
221 case TimeStamp::LATCH:
222 ASSERT_NO_FATAL_FAILURE(mTimeStats->setLatchTime(id, frameNumber, ts));
223 break;
224 case TimeStamp::DESIRED:
225 ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
226 break;
227 case TimeStamp::PRESENT:
228 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0,
229 kRenderRate0, frameRateVote,
230 gameMode));
231 break;
232 case TimeStamp::PRESENT_FENCE:
233 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber,
234 std::make_shared<FenceTime>(ts),
235 kRefreshRate0, kRenderRate0,
236 frameRateVote, gameMode));
237 break;
238 default:
239 ALOGD("Invalid timestamp type");
240 }
241 }
242
genRandomInt32(int32_t begin,int32_t end)243 int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) {
244 std::uniform_int_distribution<int32_t> distr(begin, end);
245 return distr(mRandomEngine);
246 }
247
TEST_F(TimeStatsTest,disabledByDefault)248 TEST_F(TimeStatsTest, disabledByDefault) {
249 ASSERT_FALSE(mTimeStats->isEnabled());
250 }
251
TEST_F(TimeStatsTest,canEnableAndDisableTimeStats)252 TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
253 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
254 ASSERT_TRUE(mTimeStats->isEnabled());
255
256 EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
257 ASSERT_FALSE(mTimeStats->isEnabled());
258 }
259
TEST_F(TimeStatsTest,canIncreaseGlobalStats)260 TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
261 constexpr size_t TOTAL_FRAMES = 5;
262 constexpr size_t MISSED_FRAMES = 4;
263 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
264
265 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
266
267 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
268 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
269 }
270 for (size_t i = 0; i < MISSED_FRAMES; i++) {
271 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
272 }
273 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
274 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
275 }
276
277 SFTimeStatsGlobalProto globalProto;
278 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
279
280 ASSERT_TRUE(globalProto.has_total_frames());
281 EXPECT_EQ(TOTAL_FRAMES, globalProto.total_frames());
282 ASSERT_TRUE(globalProto.has_missed_frames());
283 EXPECT_EQ(MISSED_FRAMES, globalProto.missed_frames());
284 ASSERT_TRUE(globalProto.has_client_composition_frames());
285 EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
286 }
287
TEST_F(TimeStatsTest,canIncreaseLateAcquireFrames)288 TEST_F(TimeStatsTest, canIncreaseLateAcquireFrames) {
289 // this stat is not in the proto so verify by checking the string dump
290 constexpr size_t LATE_ACQUIRE_FRAMES = 2;
291
292 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
293
294 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
295 for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
296 mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
297 }
298 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
299
300 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
301 const std::string expectedResult = "lateAcquireFrames = " + std::to_string(LATE_ACQUIRE_FRAMES);
302 EXPECT_THAT(result, HasSubstr(expectedResult));
303 }
304
TEST_F(TimeStatsTest,canIncreaseBadDesiredPresent)305 TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) {
306 // this stat is not in the proto so verify by checking the string dump
307 constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 2;
308
309 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
310
311 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
312 for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
313 mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
314 }
315 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
316
317 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
318 const std::string expectedResult =
319 "badDesiredPresentFrames = " + std::to_string(BAD_DESIRED_PRESENT_FRAMES);
320 EXPECT_THAT(result, HasSubstr(expectedResult));
321 }
322
TEST_F(TimeStatsTest,canIncreaseJankyFramesForLayer)323 TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
324 // this stat is not in the proto so verify by checking the string dump
325 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
326
327 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
328 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
329 kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2,
330 3});
331 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
332 kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2,
333 3});
334 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
335 kGameMode, JankType::DisplayHAL, 1, 2, 3});
336 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
337 kGameMode, JankType::AppDeadlineMissed, 1, 2, 3});
338 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
339 kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3});
340 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
341 kGameMode, JankType::PredictionError, 1, 2, 3});
342 mTimeStats->incrementJankyFrames(
343 {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode,
344 JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3});
345 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
346 kGameMode, JankType::None, 1, 2, 3});
347
348 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
349 std::string expectedResult =
350 "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps";
351 EXPECT_THAT(result, HasSubstr(expectedResult));
352 expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps";
353 EXPECT_THAT(result, HasSubstr(expectedResult));
354 expectedResult = "totalTimelineFrames = " + std::to_string(8);
355 EXPECT_THAT(result, HasSubstr(expectedResult));
356 expectedResult = "jankyFrames = " + std::to_string(7);
357 EXPECT_THAT(result, HasSubstr(expectedResult));
358 expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
359 EXPECT_THAT(result, HasSubstr(expectedResult));
360 expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
361 EXPECT_THAT(result, HasSubstr(expectedResult));
362 expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
363 EXPECT_THAT(result, HasSubstr(expectedResult));
364 expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
365 EXPECT_THAT(result, HasSubstr(expectedResult));
366 expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
367 EXPECT_THAT(result, HasSubstr(expectedResult));
368 expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
369 EXPECT_THAT(result, HasSubstr(expectedResult));
370 expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
371 EXPECT_THAT(result, HasSubstr(expectedResult));
372 }
373
TEST_F(TimeStatsTest,canCaptureSetFrameRateVote)374 TEST_F(TimeStatsTest, canCaptureSetFrameRateVote) {
375 // this stat is not in the proto so verify by checking the string dump
376 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
377
378 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
379
380 const auto frameRate60 = TimeStats::SetFrameRateVote{
381 .frameRate = 60.0f,
382 .frameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility::Default,
383 .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::ShouldBeSeamless,
384 };
385 const auto frameRate90 = TimeStats::SetFrameRateVote{
386 .frameRate = 90.0f,
387 .frameRateCompatibility =
388 TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple,
389 .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired,
390 };
391 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60);
392 std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
393 std::string expectedResult = "frameRate = 60.00";
394 EXPECT_THAT(result, HasSubstr(expectedResult));
395 expectedResult = "frameRateCompatibility = Default";
396 EXPECT_THAT(result, HasSubstr(expectedResult));
397 expectedResult = "seamlessness = ShouldBeSeamless";
398 EXPECT_THAT(result, HasSubstr(expectedResult));
399
400 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, frameRate90);
401 result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING);
402 expectedResult = "frameRate = 90.00";
403 EXPECT_THAT(result, HasSubstr(expectedResult));
404 expectedResult = "frameRateCompatibility = ExactOrMultiple";
405 EXPECT_THAT(result, HasSubstr(expectedResult));
406 expectedResult = "seamlessness = NotRequired";
407 EXPECT_THAT(result, HasSubstr(expectedResult));
408
409 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 4, 4000000, frameRate60);
410 result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING);
411 expectedResult = "frameRate = 60.00";
412 EXPECT_THAT(result, HasSubstr(expectedResult));
413 expectedResult = "frameRateCompatibility = Default";
414 EXPECT_THAT(result, HasSubstr(expectedResult));
415 expectedResult = "seamlessness = ShouldBeSeamless";
416 EXPECT_THAT(result, HasSubstr(expectedResult));
417 }
418
TEST_F(TimeStatsTest,canCaptureSetFrameRateVoteAfterZeroForLayer)419 TEST_F(TimeStatsTest, canCaptureSetFrameRateVoteAfterZeroForLayer) {
420 // this stat is not in the proto so verify by checking the string dump
421 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
422
423 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
424
425 const auto frameRate90 = TimeStats::SetFrameRateVote{
426 .frameRate = 90.0f,
427 .frameRateCompatibility =
428 TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple,
429 .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired,
430 };
431 const auto frameRateDefault = TimeStats::SetFrameRateVote{
432 .frameRate = 0.0f,
433 .frameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility::Default,
434 .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::ShouldBeSeamless,
435 };
436 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate90);
437 std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
438 std::string expectedResult = "frameRate = 90.00";
439 EXPECT_THAT(result, HasSubstr(expectedResult));
440 expectedResult = "frameRateCompatibility = ExactOrMultiple";
441 EXPECT_THAT(result, HasSubstr(expectedResult));
442 expectedResult = "seamlessness = NotRequired";
443 EXPECT_THAT(result, HasSubstr(expectedResult));
444
445 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, frameRateDefault);
446 result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING);
447 expectedResult = "frameRate = 90.00";
448 EXPECT_THAT(result, HasSubstr(expectedResult));
449 expectedResult = "frameRateCompatibility = ExactOrMultiple";
450 EXPECT_THAT(result, HasSubstr(expectedResult));
451 expectedResult = "seamlessness = NotRequired";
452 EXPECT_THAT(result, HasSubstr(expectedResult));
453
454 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 4, 4000000, frameRateDefault);
455 result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING);
456 expectedResult = "frameRate = 90.00";
457 EXPECT_THAT(result, HasSubstr(expectedResult));
458 expectedResult = "frameRateCompatibility = ExactOrMultiple";
459 EXPECT_THAT(result, HasSubstr(expectedResult));
460 expectedResult = "seamlessness = NotRequired";
461 EXPECT_THAT(result, HasSubstr(expectedResult));
462 }
463
TEST_F(TimeStatsTest,canIncreaseClientCompositionReusedFrames)464 TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
465 // this stat is not in the proto so verify by checking the string dump
466 constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
467
468 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
469 for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
470 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
471 }
472
473 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
474 const std::string expectedResult =
475 "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
476 EXPECT_THAT(result, HasSubstr(expectedResult));
477 }
478
TEST_F(TimeStatsTest,canIncreaseRefreshRateSwitches)479 TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
480 // this stat is not in the proto so verify by checking the string dump
481 constexpr size_t REFRESH_RATE_SWITCHES = 2;
482
483 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
484 for (size_t i = 0; i < REFRESH_RATE_SWITCHES; i++) {
485 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
486 }
487
488 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
489 const std::string expectedResult =
490 "refreshRateSwitches = " + std::to_string(REFRESH_RATE_SWITCHES);
491 EXPECT_THAT(result, HasSubstr(expectedResult));
492 }
493
TEST_F(TimeStatsTest,canIncreaseCompositionStrategyChanges)494 TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
495 // this stat is not in the proto so verify by checking the string dump
496 constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
497
498 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
499 for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
500 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
501 }
502
503 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
504 const std::string expectedResult =
505 "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
506 EXPECT_THAT(result, HasSubstr(expectedResult));
507 }
508
TEST_F(TimeStatsTest,canAverageFrameDuration)509 TEST_F(TimeStatsTest, canAverageFrameDuration) {
510 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
511 mTimeStats->setPowerMode(PowerMode::ON);
512 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
513 std::chrono::nanoseconds(6ms).count());
514 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
515 std::chrono::nanoseconds(16ms).count());
516
517 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
518 EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
519 }
520
TEST_F(TimeStatsTest,canAverageRenderEngineTimings)521 TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
522 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
523 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
524 std::make_shared<FenceTime>(
525 std::chrono::duration_cast<
526 std::chrono::nanoseconds>(3ms)
527 .count()));
528
529 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
530 std::chrono::nanoseconds(8ms).count());
531
532 // Push a fake present fence to trigger flushing the RenderEngine timings.
533 mTimeStats->setPowerMode(PowerMode::ON);
534 mTimeStats->setPresentFenceGlobal(
535 std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
536
537 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
538 EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
539 }
540
TEST_F(TimeStatsTest,canInsertGlobalPresentToPresent)541 TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
542 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
543
544 ASSERT_NO_FATAL_FAILURE(
545 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
546 ASSERT_NO_FATAL_FAILURE(
547 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
548
549 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
550 ASSERT_NO_FATAL_FAILURE(
551 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
552 ASSERT_NO_FATAL_FAILURE(
553 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
554
555 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::OFF));
556 ASSERT_NO_FATAL_FAILURE(
557 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
558 ASSERT_NO_FATAL_FAILURE(
559 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(8000000)));
560
561 SFTimeStatsGlobalProto globalProto;
562 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
563
564 ASSERT_EQ(1, globalProto.present_to_present_size());
565 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.present_to_present().Get(0);
566 EXPECT_EQ(1, histogramProto.frame_count());
567 EXPECT_EQ(2, histogramProto.time_millis());
568 }
569
TEST_F(TimeStatsTest,canInsertGlobalFrameDuration)570 TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
571 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
572
573 mTimeStats->setPowerMode(PowerMode::OFF);
574 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
575 std::chrono::nanoseconds(5ms).count());
576 mTimeStats->setPowerMode(PowerMode::ON);
577 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
578 std::chrono::nanoseconds(6ms).count());
579
580 SFTimeStatsGlobalProto globalProto;
581 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
582
583 ASSERT_EQ(1, globalProto.frame_duration_size());
584 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
585 EXPECT_EQ(1, histogramProto.frame_count());
586 EXPECT_EQ(3, histogramProto.time_millis());
587 }
588
TEST_F(TimeStatsTest,canInsertGlobalRenderEngineTiming)589 TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
590 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
591
592 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
593 std::make_shared<FenceTime>(
594 std::chrono::duration_cast<
595 std::chrono::nanoseconds>(3ms)
596 .count()));
597
598 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
599 std::chrono::nanoseconds(6ms).count());
600
601 // First verify that flushing RenderEngine durations did not occur yet.
602 SFTimeStatsGlobalProto preFlushProto;
603 ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
604 ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
605
606 // Push a fake present fence to trigger flushing the RenderEngine timings.
607 mTimeStats->setPowerMode(PowerMode::ON);
608 mTimeStats->setPresentFenceGlobal(
609 std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
610
611 // Now we can verify that RenderEngine durations were flushed now.
612 SFTimeStatsGlobalProto postFlushProto;
613 ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
614
615 ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
616 const SFTimeStatsHistogramBucketProto& histogramProto =
617 postFlushProto.render_engine_timing().Get(0);
618 EXPECT_EQ(2, histogramProto.frame_count());
619 EXPECT_EQ(2, histogramProto.time_millis());
620 }
621
TEST_F(TimeStatsTest,canInsertOneLayerTimeStats)622 TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
623 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
624
625 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
626 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
627
628 SFTimeStatsGlobalProto globalProto;
629 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
630
631 ASSERT_EQ(1, globalProto.stats_size());
632 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
633 ASSERT_TRUE(layerProto.has_layer_name());
634 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
635 ASSERT_TRUE(layerProto.has_total_frames());
636 EXPECT_EQ(1, layerProto.total_frames());
637 ASSERT_EQ(6, layerProto.deltas_size());
638 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
639 ASSERT_EQ(1, deltaProto.histograms_size());
640 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
641 EXPECT_EQ(1, histogramProto.frame_count());
642 if ("post2acquire" == deltaProto.delta_name()) {
643 EXPECT_EQ(1, histogramProto.time_millis());
644 } else if ("post2present" == deltaProto.delta_name()) {
645 EXPECT_EQ(4, histogramProto.time_millis());
646 } else if ("acquire2present" == deltaProto.delta_name()) {
647 EXPECT_EQ(3, histogramProto.time_millis());
648 } else if ("latch2present" == deltaProto.delta_name()) {
649 EXPECT_EQ(2, histogramProto.time_millis());
650 } else if ("desired2present" == deltaProto.delta_name()) {
651 EXPECT_EQ(1, histogramProto.time_millis());
652 } else if ("present2present" == deltaProto.delta_name()) {
653 EXPECT_EQ(1, histogramProto.time_millis());
654 } else {
655 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
656 }
657 }
658 }
659
TEST_F(TimeStatsTest,canNotInsertInvalidLayerNameTimeStats)660 TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
661 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
662
663 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
664 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
665
666 SFTimeStatsGlobalProto globalProto;
667 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
668
669 ASSERT_EQ(0, globalProto.stats_size());
670 }
671
TEST_F(TimeStatsTest,canInsertMultipleLayersTimeStats)672 TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
673 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
674
675 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
676 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
677 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
678 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
679
680 SFTimeStatsGlobalProto globalProto;
681 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
682
683 EXPECT_EQ(2, globalProto.stats_size());
684 }
685
TEST_F(TimeStatsTest,canInsertUnorderedLayerTimeStats)686 TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
687 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
688
689 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
690 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
691
692 SFTimeStatsGlobalProto globalProto;
693 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
694
695 ASSERT_EQ(1, globalProto.stats_size());
696 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
697 ASSERT_TRUE(layerProto.has_layer_name());
698 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
699 ASSERT_TRUE(layerProto.has_total_frames());
700 EXPECT_EQ(1, layerProto.total_frames());
701 ASSERT_EQ(6, layerProto.deltas_size());
702 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
703 ASSERT_EQ(1, deltaProto.histograms_size());
704 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
705 EXPECT_EQ(1, histogramProto.frame_count());
706 if ("post2acquire" == deltaProto.delta_name()) {
707 EXPECT_EQ(0, histogramProto.time_millis());
708 } else if ("post2present" == deltaProto.delta_name()) {
709 EXPECT_EQ(2, histogramProto.time_millis());
710 } else if ("acquire2present" == deltaProto.delta_name()) {
711 EXPECT_EQ(2, histogramProto.time_millis());
712 } else if ("latch2present" == deltaProto.delta_name()) {
713 EXPECT_EQ(2, histogramProto.time_millis());
714 } else if ("desired2present" == deltaProto.delta_name()) {
715 EXPECT_EQ(1, histogramProto.time_millis());
716 } else if ("present2present" == deltaProto.delta_name()) {
717 EXPECT_EQ(1, histogramProto.time_millis());
718 } else {
719 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
720 }
721 }
722 }
723
TEST_F(TimeStatsTest,recordRefreshRateNewConfigs)724 TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
725 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
726
727 uint32_t fpsOne = 30;
728 uint32_t fpsTwo = 90;
729 uint64_t millisOne = 5000;
730 uint64_t millisTwo = 7000;
731
732 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
733 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
734
735 SFTimeStatsGlobalProto globalProto;
736 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
737
738 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
739 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
740 expectedConfigOne->set_fps(fpsOne);
741 expectedBucketOne.set_duration_millis(millisOne);
742
743 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
744 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
745 expectedConfigTwo->set_fps(fpsTwo);
746 expectedBucketTwo.set_duration_millis(millisTwo);
747
748 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
749
750 std::unordered_set<uint32_t> seen_fps;
751 for (const auto& bucket : globalProto.display_config_stats()) {
752 seen_fps.emplace(bucket.config().fps());
753 if (fpsOne == bucket.config().fps()) {
754 EXPECT_EQ(millisOne, bucket.duration_millis());
755 } else if (fpsTwo == bucket.config().fps()) {
756 EXPECT_EQ(millisTwo, bucket.duration_millis());
757 } else {
758 FAIL() << "Unknown fps: " << bucket.config().fps();
759 }
760 }
761 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
762 }
763
TEST_F(TimeStatsTest,recordRefreshRateUpdatesConfig)764 TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
765 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
766
767 uint32_t fps = 30;
768 uint64_t millisOne = 5000;
769 uint64_t millisTwo = 7000;
770
771 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
772 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
773
774 SFTimeStatsGlobalProto globalProto;
775 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
776 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
777 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
778 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
779 }
780
TEST_F(TimeStatsTest,canRemoveTimeRecord)781 TEST_F(TimeStatsTest, canRemoveTimeRecord) {
782 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
783
784 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
785 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
786 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
787 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
788
789 SFTimeStatsGlobalProto globalProto;
790 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
791
792 ASSERT_EQ(1, globalProto.stats_size());
793 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
794 ASSERT_TRUE(layerProto.has_total_frames());
795 EXPECT_EQ(1, layerProto.total_frames());
796 }
797
TEST_F(TimeStatsTest,canRecoverFromIncompleteTimeRecordError)798 TEST_F(TimeStatsTest, canRecoverFromIncompleteTimeRecordError) {
799 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
800
801 uint64_t frameNumber = 1;
802 nsecs_t ts = 1000000;
803 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
804 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
805 frameNumber++;
806 ts += 1000000;
807 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
808 }
809
810 SFTimeStatsGlobalProto globalProto;
811 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
812
813 ASSERT_EQ(1, globalProto.stats_size());
814 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
815 ASSERT_TRUE(layerProto.has_total_frames());
816 EXPECT_EQ(1, layerProto.total_frames());
817 }
818
TEST_F(TimeStatsTest,layerTimeStatsOnDestroy)819 TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
820 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
821
822 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
823 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
824 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
825 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
826
827 SFTimeStatsGlobalProto globalProto;
828 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
829
830 ASSERT_EQ(1, globalProto.stats_size());
831 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
832 ASSERT_TRUE(layerProto.has_total_frames());
833 EXPECT_EQ(1, layerProto.total_frames());
834 }
835
TEST_F(TimeStatsTest,canClearTimeStats)836 TEST_F(TimeStatsTest, canClearTimeStats) {
837 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
838
839 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
840 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
841 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
842 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
843
844 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
845 std::chrono::nanoseconds(6ms).count());
846 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
847 std::chrono::nanoseconds(6ms).count());
848 ASSERT_NO_FATAL_FAILURE(
849 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
850 ASSERT_NO_FATAL_FAILURE(
851 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
852 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
853 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
854
855 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
856
857 SFTimeStatsGlobalProto globalProto;
858 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
859
860 EXPECT_EQ(0, globalProto.total_frames());
861 EXPECT_EQ(0, globalProto.missed_frames());
862 EXPECT_EQ(0, globalProto.client_composition_frames());
863 EXPECT_EQ(0, globalProto.present_to_present_size());
864 EXPECT_EQ(0, globalProto.frame_duration_size());
865 EXPECT_EQ(0, globalProto.render_engine_timing_size());
866 EXPECT_EQ(0, globalProto.stats_size());
867 }
868
TEST_F(TimeStatsTest,canClearDumpOnlyTimeStats)869 TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
870 // These stats are not in the proto so verify by checking the string dump.
871 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
872 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
873 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
874 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
875 mTimeStats->setPowerMode(PowerMode::ON);
876 mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
877 std::chrono::nanoseconds(5ms).count());
878 mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
879 std::chrono::nanoseconds(6ms).count());
880 mTimeStats->setPresentFenceGlobal(
881 std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
882
883 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
884 kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2,
885 3});
886 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
887 kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2,
888 3});
889 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
890 kGameMode, JankType::DisplayHAL, 1, 2, 3});
891 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
892 kGameMode, JankType::AppDeadlineMissed, 1, 2, 3});
893 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
894 kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3});
895 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
896 kGameMode, JankType::PredictionError, 1, 2, 3});
897 mTimeStats->incrementJankyFrames(
898 {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode,
899 JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3});
900 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
901 kGameMode, JankType::None, 1, 2, 3});
902
903 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
904
905 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
906 EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
907 EXPECT_THAT(result, HasSubstr("refreshRateSwitches = 0"));
908 EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
909 EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
910 EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
911 std::string expectedResult = "totalTimelineFrames = ";
912 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
913 expectedResult = "jankyFrames = ";
914 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
915 expectedResult = "sfLongCpuJankyFrames = ";
916 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
917 expectedResult = "sfLongGpuJankyFrames = ";
918 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
919 expectedResult = "sfUnattributedJankyFrames = ";
920 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
921 expectedResult = "appUnattributedJankyFrames = ";
922 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
923 expectedResult = "sfSchedulingJankyFrames = ";
924 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
925 expectedResult = "sfPredictionErrorJankyFrames = ";
926 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
927 expectedResult = "appBufferStuffingJankyFrames = ";
928 EXPECT_THAT(result, Not(HasSubstr(expectedResult)));
929 }
930
TEST_F(TimeStatsTest,canDumpWithMaxLayers)931 TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
932 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
933
934 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
935 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
936 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
937 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
938 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
939
940 SFTimeStatsGlobalProto globalProto;
941 ASSERT_TRUE(
942 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
943
944 ASSERT_EQ(1, globalProto.stats_size());
945 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
946 ASSERT_TRUE(layerProto.has_layer_name());
947 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
948 ASSERT_TRUE(layerProto.has_total_frames());
949 EXPECT_EQ(2, layerProto.total_frames());
950 }
951
TEST_F(TimeStatsTest,canDumpWithInvalidMaxLayers)952 TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
953 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
954
955 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
956 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
957
958 SFTimeStatsGlobalProto globalProto;
959 ASSERT_TRUE(globalProto.ParseFromString(
960 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
961
962 ASSERT_EQ(0, globalProto.stats_size());
963 }
964
TEST_F(TimeStatsTest,noInfInAverageFPS)965 TEST_F(TimeStatsTest, noInfInAverageFPS) {
966 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
967 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
968 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 1000000);
969
970 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
971 EXPECT_THAT(result, HasSubstr("averageFPS = 0.000"));
972 }
973
974 namespace {
buildExpectedHistogram(const std::vector<int32_t> & times,const std::vector<int32_t> & frameCounts)975 FrameTimingHistogram buildExpectedHistogram(const std::vector<int32_t>& times,
976 const std::vector<int32_t>& frameCounts) {
977 FrameTimingHistogram histogram;
978 for (int i = 0; i < times.size(); i++) {
979 ALOGE("Writing time: %d", times[i]);
980 histogram.add_time_millis_buckets(times[i]);
981 ALOGE("Writing count: %d", frameCounts[i]);
982 histogram.add_frame_counts((int64_t)frameCounts[i]);
983 }
984 return histogram;
985 }
986 } // namespace
987
988 MATCHER_P(HistogramEq, expected, "") {
989 *result_listener << "Histograms are not equal! \n";
990
991 if (arg.time_millis_buckets_size() != expected.time_millis_buckets_size()) {
992 *result_listener << "Time millis bucket are different sizes. Expected: "
993 << expected.time_millis_buckets_size() << ". Actual "
994 << arg.time_millis_buckets_size();
995 return false;
996 }
997 if (arg.frame_counts_size() != expected.frame_counts_size()) {
998 *result_listener << "Frame counts are different sizes. Expected: "
999 << expected.frame_counts_size() << ". Actual " << arg.frame_counts_size();
1000 return false;
1001 }
1002
1003 for (int i = 0; i < expected.time_millis_buckets_size(); i++) {
1004 if (arg.time_millis_buckets(i) != expected.time_millis_buckets(i)) {
1005 *result_listener << "time_millis_bucket[" << i
1006 << "] is different. Expected: " << expected.time_millis_buckets(i)
1007 << ". Actual: " << arg.time_millis_buckets(i);
1008 return false;
1009 }
1010 if (arg.frame_counts(i) != expected.frame_counts(i)) {
1011 *result_listener << "frame_counts[" << i
1012 << "] is different. Expected: " << expected.frame_counts(i)
1013 << ". Actual: " << arg.frame_counts(i);
1014 return false;
1015 }
1016 }
1017 return true;
1018 }
1019
TEST_F(TimeStatsTest,globalStatsCallback)1020 TEST_F(TimeStatsTest, globalStatsCallback) {
1021 constexpr size_t TOTAL_FRAMES = 5;
1022 constexpr size_t MISSED_FRAMES = 4;
1023 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
1024 constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
1025 constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000;
1026 constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000;
1027 constexpr nsecs_t APP_DEADLINE_DELTA = 3'000'000;
1028
1029 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1030
1031 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
1032 mTimeStats->incrementTotalFrames();
1033 }
1034 for (size_t i = 0; i < MISSED_FRAMES; i++) {
1035 mTimeStats->incrementMissedFrames();
1036 }
1037 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
1038 mTimeStats->incrementClientCompositionFrames();
1039 }
1040
1041 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1042
1043 mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
1044 mTimeStats->setPowerMode(PowerMode::ON);
1045 mTimeStats->recordFrameDuration(1000000, 3000000);
1046 mTimeStats->recordRenderEngineDuration(2000000, 4000000);
1047 mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
1048
1049 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
1050 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
1051
1052 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1053 kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed,
1054 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1055 APP_DEADLINE_DELTA});
1056 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1057 kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed,
1058 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1059 APP_DEADLINE_DELTA});
1060 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1061 kGameMode, JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA,
1062 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
1063 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1064 kGameMode, JankType::AppDeadlineMissed,
1065 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1066 APP_DEADLINE_DELTA});
1067 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1068 kGameMode, JankType::SurfaceFlingerScheduling,
1069 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1070 APP_DEADLINE_DELTA});
1071 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1072 kGameMode, JankType::PredictionError, DISPLAY_DEADLINE_DELTA,
1073 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
1074 mTimeStats->incrementJankyFrames(
1075 {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode,
1076 JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA,
1077 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
1078 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1079 kGameMode, JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA,
1080 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
1081 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1082 kGameMode, JankType::None, DISPLAY_DEADLINE_DELTA,
1083 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
1084
1085 std::string pulledData;
1086 EXPECT_TRUE(mTimeStats->onPullAtom(10062 /*SURFACEFLINGER_STATS_GLOBAL_INFO*/, &pulledData));
1087
1088 android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList;
1089 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1090 ASSERT_EQ(atomList.atom_size(), 1);
1091 const android::surfaceflinger::SurfaceflingerStatsGlobalInfo& atom = atomList.atom(0);
1092
1093 EXPECT_EQ(atom.total_frames(), TOTAL_FRAMES);
1094 EXPECT_EQ(atom.missed_frames(), MISSED_FRAMES);
1095 EXPECT_EQ(atom.client_composition_frames(), CLIENT_COMPOSITION_FRAMES);
1096 // Display on millis is not checked.
1097 EXPECT_EQ(atom.animation_millis(), 2);
1098 EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS);
1099 EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1})));
1100 EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1})));
1101 EXPECT_EQ(atom.total_timeline_frames(), 9);
1102 EXPECT_EQ(atom.total_janky_frames(), 7);
1103 EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1);
1104 EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1);
1105 EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1);
1106 EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2);
1107 EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1);
1108 EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1);
1109 EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 2);
1110 EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
1111 EXPECT_THAT(atom.sf_deadline_misses(), HistogramEq(buildExpectedHistogram({1}, {7})));
1112 EXPECT_THAT(atom.sf_prediction_errors(), HistogramEq(buildExpectedHistogram({2}, {7})));
1113 EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0);
1114
1115 SFTimeStatsGlobalProto globalProto;
1116 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
1117
1118 EXPECT_EQ(0, globalProto.total_frames());
1119 EXPECT_EQ(0, globalProto.missed_frames());
1120 EXPECT_EQ(0, globalProto.client_composition_frames());
1121 EXPECT_EQ(0, globalProto.present_to_present_size());
1122
1123 // also check dump-only stats: expect that global stats are indeed dropped but there should
1124 // still be stats for the layer
1125 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
1126 std::string expectedResult = "totalTimelineFrames = " + std::to_string(0);
1127 EXPECT_THAT(result, HasSubstr(expectedResult));
1128 expectedResult = "totalTimelineFrames = " + std::to_string(9);
1129 EXPECT_THAT(result, HasSubstr(expectedResult));
1130 expectedResult = "jankyFrames = " + std::to_string(0);
1131 EXPECT_THAT(result, HasSubstr(expectedResult));
1132 expectedResult = "jankyFrames = " + std::to_string(7);
1133 EXPECT_THAT(result, HasSubstr(expectedResult));
1134 expectedResult = "sfLongCpuJankyFrames = " + std::to_string(0);
1135 EXPECT_THAT(result, HasSubstr(expectedResult));
1136 expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
1137 EXPECT_THAT(result, HasSubstr(expectedResult));
1138 expectedResult = "sfLongGpuJankyFrames = " + std::to_string(0);
1139 EXPECT_THAT(result, HasSubstr(expectedResult));
1140 expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
1141 EXPECT_THAT(result, HasSubstr(expectedResult));
1142 expectedResult = "sfUnattributedJankyFrames = " + std::to_string(0);
1143 EXPECT_THAT(result, HasSubstr(expectedResult));
1144 expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
1145 EXPECT_THAT(result, HasSubstr(expectedResult));
1146 expectedResult = "appUnattributedJankyFrames = " + std::to_string(0);
1147 EXPECT_THAT(result, HasSubstr(expectedResult));
1148 expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
1149 EXPECT_THAT(result, HasSubstr(expectedResult));
1150 expectedResult = "sfSchedulingJankyFrames = " + std::to_string(0);
1151 EXPECT_THAT(result, HasSubstr(expectedResult));
1152 expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
1153 EXPECT_THAT(result, HasSubstr(expectedResult));
1154 expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(0);
1155 EXPECT_THAT(result, HasSubstr(expectedResult));
1156 expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
1157 EXPECT_THAT(result, HasSubstr(expectedResult));
1158 expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0);
1159 EXPECT_THAT(result, HasSubstr(expectedResult));
1160 expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(2);
1161 EXPECT_THAT(result, HasSubstr(expectedResult));
1162 }
1163
TEST_F(TimeStatsTest,layerStatsCallback_pullsAllAndClears)1164 TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
1165 constexpr size_t LATE_ACQUIRE_FRAMES = 2;
1166 constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
1167 constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000;
1168 constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000;
1169 constexpr nsecs_t APP_DEADLINE_DELTA_2MS = 2'000'000;
1170 constexpr nsecs_t APP_DEADLINE_DELTA_3MS = 3'000'000;
1171 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1172
1173 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {},
1174 TimeStatsHelper::GameModeStandard);
1175 for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
1176 mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
1177 }
1178 for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
1179 mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
1180 }
1181 const auto frameRate60 = TimeStats::SetFrameRateVote{
1182 .frameRate = 60.0f,
1183 .frameRateCompatibility =
1184 TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple,
1185 .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired,
1186 };
1187 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60,
1188 TimeStatsHelper::GameModeStandard);
1189
1190 mTimeStats->incrementJankyFrames(
1191 {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1192 TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerCpuDeadlineMissed,
1193 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
1194 mTimeStats->incrementJankyFrames(
1195 {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1196 TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerGpuDeadlineMissed,
1197 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
1198 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1199 TimeStatsHelper::GameModeStandard, JankType::DisplayHAL,
1200 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1201 APP_DEADLINE_DELTA_3MS});
1202 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1203 TimeStatsHelper::GameModeStandard,
1204 JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA,
1205 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
1206 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1207 TimeStatsHelper::GameModeStandard,
1208 JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA,
1209 DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS});
1210 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1211 TimeStatsHelper::GameModeStandard, JankType::PredictionError,
1212 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1213 APP_DEADLINE_DELTA_2MS});
1214 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1215 TimeStatsHelper::GameModeStandard,
1216 JankType::AppDeadlineMissed | JankType::BufferStuffing,
1217 DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS,
1218 APP_DEADLINE_DELTA_2MS});
1219 mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
1220 TimeStatsHelper::GameModeStandard, JankType::None,
1221 DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
1222 APP_DEADLINE_DELTA_3MS});
1223
1224 std::string pulledData;
1225 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1226
1227 SurfaceflingerStatsLayerInfoWrapper atomList;
1228 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1229 ASSERT_EQ(atomList.atom_size(), 1);
1230 const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
1231
1232 EXPECT_EQ(atom.layer_name(), genLayerName(LAYER_ID_0));
1233 EXPECT_EQ(atom.total_frames(), 1);
1234 EXPECT_EQ(atom.dropped_frames(), 0);
1235 EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1236 EXPECT_THAT(atom.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1})));
1237 EXPECT_THAT(atom.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1})));
1238 EXPECT_THAT(atom.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1})));
1239 EXPECT_THAT(atom.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1240 EXPECT_THAT(atom.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1})));
1241 EXPECT_EQ(atom.late_acquire_frames(), LATE_ACQUIRE_FRAMES);
1242 EXPECT_EQ(atom.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES);
1243 EXPECT_EQ(atom.uid(), UID_0);
1244 EXPECT_EQ(atom.total_timeline_frames(), 8);
1245 EXPECT_EQ(atom.total_janky_frames(), 7);
1246 EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1);
1247 EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1);
1248 EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1);
1249 EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2);
1250 EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1);
1251 EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1);
1252 EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 1);
1253 EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
1254 EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0);
1255 EXPECT_THAT(atom.set_frame_rate_vote().frame_rate(), testing::FloatEq(frameRate60.frameRate));
1256 EXPECT_EQ((int)atom.set_frame_rate_vote().frame_rate_compatibility(),
1257 (int)frameRate60.frameRateCompatibility);
1258 EXPECT_EQ((int)atom.set_frame_rate_vote().seamlessness(), (int)frameRate60.seamlessness);
1259 EXPECT_THAT(atom.app_deadline_misses(), HistogramEq(buildExpectedHistogram({3, 2}, {4, 3})));
1260 EXPECT_EQ(atom.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD);
1261
1262 SFTimeStatsGlobalProto globalProto;
1263 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
1264
1265 EXPECT_EQ(0, globalProto.stats_size());
1266
1267 // also check dump-only stats: expect that layer stats are indeed dropped but there should still
1268 // be global stats
1269 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
1270 std::string expectedResult = "totalTimelineFrames = " + std::to_string(8);
1271 EXPECT_THAT(result, HasSubstr(expectedResult));
1272 expectedResult = "jankyFrames = " + std::to_string(7);
1273 EXPECT_THAT(result, HasSubstr(expectedResult));
1274 expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
1275 EXPECT_THAT(result, HasSubstr(expectedResult));
1276 expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
1277 EXPECT_THAT(result, HasSubstr(expectedResult));
1278 expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
1279 EXPECT_THAT(result, HasSubstr(expectedResult));
1280 expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
1281 EXPECT_THAT(result, HasSubstr(expectedResult));
1282 expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
1283 EXPECT_THAT(result, HasSubstr(expectedResult));
1284 expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
1285 EXPECT_THAT(result, HasSubstr(expectedResult));
1286 expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
1287 EXPECT_THAT(result, HasSubstr(expectedResult));
1288
1289 std::string expectedMissing = "uid = " + std::to_string(UID_0);
1290 EXPECT_THAT(result, Not(HasSubstr(expectedMissing)));
1291 }
1292
TEST_F(TimeStatsTest,layerStatsCallback_multipleGameModes)1293 TEST_F(TimeStatsTest, layerStatsCallback_multipleGameModes) {
1294 constexpr size_t LATE_ACQUIRE_FRAMES = 2;
1295 constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
1296 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1297
1298 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {},
1299 TimeStatsHelper::GameModeStandard);
1300 for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
1301 mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
1302 }
1303 for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
1304 mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
1305 }
1306 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {},
1307 TimeStatsHelper::GameModeStandard);
1308
1309 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {},
1310 TimeStatsHelper::GameModePerformance);
1311
1312 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, TimeStatsHelper::GameModeBattery);
1313 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, TimeStatsHelper::GameModeBattery);
1314
1315 std::string pulledData;
1316 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1317
1318 SurfaceflingerStatsLayerInfoWrapper atomList;
1319 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1320 // The first time record is never uploaded to stats.
1321 ASSERT_EQ(atomList.atom_size(), 3);
1322 // Layers are ordered based on the hash in LayerStatsKey. For this test, the order happens to
1323 // be: 0 - Battery 1 - Performance 2 - Standard
1324 const SurfaceflingerStatsLayerInfo& atom0 = atomList.atom(0);
1325
1326 EXPECT_EQ(atom0.layer_name(), genLayerName(LAYER_ID_0));
1327 EXPECT_EQ(atom0.total_frames(), 2);
1328 EXPECT_EQ(atom0.dropped_frames(), 0);
1329 EXPECT_THAT(atom0.present_to_present(), HistogramEq(buildExpectedHistogram({0, 1}, {1, 1})));
1330 EXPECT_THAT(atom0.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {2})));
1331 EXPECT_THAT(atom0.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {2})));
1332 EXPECT_THAT(atom0.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {2})));
1333 EXPECT_THAT(atom0.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {2})));
1334 EXPECT_THAT(atom0.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {2})));
1335 EXPECT_EQ(atom0.late_acquire_frames(), 0);
1336 EXPECT_EQ(atom0.bad_desired_present_frames(), 0);
1337 EXPECT_EQ(atom0.uid(), UID_0);
1338 EXPECT_EQ(atom0.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
1339 EXPECT_EQ(atom0.render_rate_bucket(), RENDER_RATE_BUCKET_0);
1340 EXPECT_EQ(atom0.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY);
1341
1342 const SurfaceflingerStatsLayerInfo& atom1 = atomList.atom(1);
1343
1344 EXPECT_EQ(atom1.layer_name(), genLayerName(LAYER_ID_0));
1345 EXPECT_EQ(atom1.total_frames(), 1);
1346 EXPECT_EQ(atom1.dropped_frames(), 0);
1347 EXPECT_THAT(atom1.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1348 EXPECT_THAT(atom1.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1})));
1349 EXPECT_THAT(atom1.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1})));
1350 EXPECT_THAT(atom1.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1})));
1351 EXPECT_THAT(atom1.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1352 EXPECT_THAT(atom1.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1})));
1353 EXPECT_EQ(atom1.late_acquire_frames(), 0);
1354 EXPECT_EQ(atom1.bad_desired_present_frames(), 0);
1355 EXPECT_EQ(atom1.uid(), UID_0);
1356 EXPECT_EQ(atom1.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
1357 EXPECT_EQ(atom1.render_rate_bucket(), RENDER_RATE_BUCKET_0);
1358 EXPECT_EQ(atom1.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE);
1359
1360 const SurfaceflingerStatsLayerInfo& atom2 = atomList.atom(2);
1361
1362 EXPECT_EQ(atom2.layer_name(), genLayerName(LAYER_ID_0));
1363 EXPECT_EQ(atom2.total_frames(), 1);
1364 EXPECT_EQ(atom2.dropped_frames(), 0);
1365 EXPECT_THAT(atom2.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1366 EXPECT_THAT(atom2.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1})));
1367 EXPECT_THAT(atom2.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1})));
1368 EXPECT_THAT(atom2.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1})));
1369 EXPECT_THAT(atom2.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1})));
1370 EXPECT_THAT(atom2.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1})));
1371 EXPECT_EQ(atom2.late_acquire_frames(), LATE_ACQUIRE_FRAMES);
1372 EXPECT_EQ(atom2.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES);
1373 EXPECT_EQ(atom2.uid(), UID_0);
1374 EXPECT_EQ(atom2.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0);
1375 EXPECT_EQ(atom2.render_rate_bucket(), RENDER_RATE_BUCKET_0);
1376 EXPECT_EQ(atom2.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD);
1377 }
1378
TEST_F(TimeStatsTest,layerStatsCallback_pullsMultipleLayers)1379 TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
1380 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1381
1382 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1383 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
1384 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
1385 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
1386
1387 std::string pulledData;
1388 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1389
1390 SurfaceflingerStatsLayerInfoWrapper atomList;
1391 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1392 ASSERT_EQ(atomList.atom_size(), 2);
1393 std::vector<std::string> actualLayerNames = {atomList.atom(0).layer_name(),
1394 atomList.atom(1).layer_name()};
1395 EXPECT_THAT(actualLayerNames,
1396 UnorderedElementsAre(genLayerName(LAYER_ID_0), genLayerName(LAYER_ID_1)));
1397 }
1398
TEST_F(TimeStatsTest,layerStatsCallback_pullsMultipleBuckets)1399 TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
1400 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1401
1402 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1403 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
1404 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
1405 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
1406
1407 // Now make sure that TimeStats flushes global stats to set the callback.
1408 mTimeStats->setPowerMode(PowerMode::ON);
1409 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
1410 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
1411
1412 std::string pulledData;
1413 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1414
1415 SurfaceflingerStatsLayerInfoWrapper atomList;
1416 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1417 ASSERT_EQ(atomList.atom_size(), 1);
1418 const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
1419 EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1, 2}, {2, 1})));
1420 }
1421
TEST_F(TimeStatsTest,layerStatsCallback_limitsHistogramBuckets)1422 TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
1423 mTimeStats = std::make_unique<impl::TimeStats>(std::nullopt, 1);
1424 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1425
1426 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1427 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
1428 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
1429 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
1430
1431 std::string pulledData;
1432 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1433
1434 SurfaceflingerStatsLayerInfoWrapper atomList;
1435 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1436 ASSERT_EQ(atomList.atom_size(), 1);
1437 const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
1438 EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {2})));
1439 }
1440
TEST_F(TimeStatsTest,layerStatsCallback_limitsLayers)1441 TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
1442 mTimeStats = std::make_unique<impl::TimeStats>(1, std::nullopt);
1443 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1444
1445 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1446 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
1447 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
1448 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
1449 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
1450
1451 std::string pulledData;
1452 EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
1453
1454 SurfaceflingerStatsLayerInfoWrapper atomList;
1455 ASSERT_TRUE(atomList.ParseFromString(pulledData));
1456 ASSERT_EQ(atomList.atom_size(), 1);
1457 EXPECT_EQ(atomList.atom(0).layer_name(), genLayerName(LAYER_ID_1));
1458 }
1459
TEST_F(TimeStatsTest,canSurviveMonkey)1460 TEST_F(TimeStatsTest, canSurviveMonkey) {
1461 if (g_noSlowTests) {
1462 GTEST_SKIP();
1463 }
1464
1465 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1466
1467 for (size_t i = 0; i < 10000000; ++i) {
1468 const int32_t layerId = genRandomInt32(-1, 10);
1469 const int32_t frameNumber = genRandomInt32(1, 10);
1470 switch (genRandomInt32(0, 100)) {
1471 case 0:
1472 ALOGV("removeTimeRecord");
1473 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
1474 continue;
1475 case 1:
1476 ALOGV("onDestroy");
1477 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
1478 continue;
1479 }
1480 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
1481 const int32_t ts = genRandomInt32(1, 1000000000);
1482 ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
1483 setTimeStamp(type, layerId, frameNumber, ts, {}, kGameMode);
1484 }
1485 }
1486
TEST_F(TimeStatsTest,refreshRateIsClampedToNearestBucket)1487 TEST_F(TimeStatsTest, refreshRateIsClampedToNearestBucket) {
1488 // this stat is not in the proto so verify by checking the string dump
1489 const auto verifyRefreshRateBucket = [&](Fps fps, int32_t bucket) {
1490 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
1491 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1492
1493 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1494 mTimeStats->incrementJankyFrames({fps, std::nullopt, UID_0, genLayerName(LAYER_ID_0),
1495 kGameMode, JankType::None, 0, 0, 0});
1496 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
1497 std::string expectedResult = "displayRefreshRate = " + std::to_string(bucket) + " fps";
1498 EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps;
1499 };
1500
1501 verifyRefreshRateBucket(Fps(91.f), 90);
1502 verifyRefreshRateBucket(Fps(89.f), 90);
1503
1504 verifyRefreshRateBucket(Fps(61.f), 60);
1505 verifyRefreshRateBucket(Fps(59.f), 60);
1506
1507 verifyRefreshRateBucket(Fps(31.f), 30);
1508 verifyRefreshRateBucket(Fps(29.f), 30);
1509 }
1510
1511 } // namespace
1512 } // namespace android
1513
1514 // TODO(b/129481165): remove the #pragma below and fix conversion issues
1515 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
1516