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