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 #undef LOG_TAG
18 #define LOG_TAG "LibSurfaceFlingerUnittests"
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <log/log.h>
24 #include <utils/String16.h>
25 #include <utils/Vector.h>
26
27 #include <random>
28 #include <unordered_set>
29
30 #include "TimeStats/TimeStats.h"
31
32 #include "libsurfaceflinger_unittest_main.h"
33
34 using namespace android::surfaceflinger;
35 using namespace google::protobuf;
36
37 namespace android {
38 namespace {
39
40 using testing::Contains;
41 using testing::SizeIs;
42 using testing::UnorderedElementsAre;
43
44 // clang-format off
45 #define FMT_PROTO true
46 #define FMT_STRING false
47 #define LAYER_ID_0 0
48 #define LAYER_ID_1 1
49 #define LAYER_ID_INVALID -1
50 #define NUM_LAYERS 1
51 #define NUM_LAYERS_INVALID "INVALID"
52
53 enum InputCommand : int32_t {
54 ENABLE = 0,
55 DISABLE = 1,
56 CLEAR = 2,
57 DUMP_ALL = 3,
58 DUMP_MAXLAYERS_1 = 4,
59 DUMP_MAXLAYERS_INVALID = 5,
60 INPUT_COMMAND_BEGIN = ENABLE,
61 INPUT_COMMAND_END = DUMP_MAXLAYERS_INVALID,
62 INPUT_COMMAND_RANGE = INPUT_COMMAND_END - INPUT_COMMAND_BEGIN + 1,
63 };
64
65 enum TimeStamp : int32_t {
66 POST = 0,
67 ACQUIRE = 1,
68 ACQUIRE_FENCE = 2,
69 LATCH = 3,
70 DESIRED = 4,
71 PRESENT = 5,
72 PRESENT_FENCE = 6,
73 TIME_STAMP_BEGIN = POST,
74 TIME_STAMP_END = PRESENT,
75 TIME_STAMP_RANGE = TIME_STAMP_END - TIME_STAMP_BEGIN + 1,
76 };
77
78 static const TimeStamp NORMAL_SEQUENCE[] = {
79 TimeStamp::POST,
80 TimeStamp::ACQUIRE,
81 TimeStamp::LATCH,
82 TimeStamp::DESIRED,
83 TimeStamp::PRESENT,
84 };
85
86 static const TimeStamp NORMAL_SEQUENCE_2[] = {
87 TimeStamp::POST,
88 TimeStamp::ACQUIRE_FENCE,
89 TimeStamp::LATCH,
90 TimeStamp::DESIRED,
91 TimeStamp::PRESENT_FENCE,
92 };
93
94 static const TimeStamp UNORDERED_SEQUENCE[] = {
95 TimeStamp::ACQUIRE,
96 TimeStamp::LATCH,
97 TimeStamp::POST,
98 TimeStamp::DESIRED,
99 TimeStamp::PRESENT,
100 };
101
102 static const TimeStamp INCOMPLETE_SEQUENCE[] = {
103 TimeStamp::POST,
104 };
105 // clang-format on
106
107 class TimeStatsTest : public testing::Test {
108 public:
TimeStatsTest()109 TimeStatsTest() {
110 const ::testing::TestInfo* const test_info =
111 ::testing::UnitTest::GetInstance()->current_test_info();
112 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
113 }
114
~TimeStatsTest()115 ~TimeStatsTest() {
116 const ::testing::TestInfo* const test_info =
117 ::testing::UnitTest::GetInstance()->current_test_info();
118 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
119 }
120
121 std::string inputCommand(InputCommand cmd, bool useProto);
122
123 void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
124
125 int32_t genRandomInt32(int32_t begin, int32_t end);
126
127 template <size_t N>
insertTimeRecord(const TimeStamp (& sequence)[N],int32_t id,uint64_t frameNumber,nsecs_t ts)128 void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber,
129 nsecs_t ts) {
130 for (size_t i = 0; i < N; i++, ts += 1000000) {
131 setTimeStamp(sequence[i], id, frameNumber, ts);
132 }
133 }
134
135 std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
136 std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
137 };
138
inputCommand(InputCommand cmd,bool useProto)139 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
140 std::string result;
141 Vector<String16> args;
142
143 switch (cmd) {
144 case InputCommand::ENABLE:
145 args.push_back(String16("-enable"));
146 break;
147 case InputCommand::DISABLE:
148 args.push_back(String16("-disable"));
149 break;
150 case InputCommand::CLEAR:
151 args.push_back(String16("-clear"));
152 break;
153 case InputCommand::DUMP_ALL:
154 args.push_back(String16("-dump"));
155 break;
156 case InputCommand::DUMP_MAXLAYERS_1:
157 args.push_back(String16("-dump"));
158 args.push_back(String16("-maxlayers"));
159 args.push_back(String16(std::to_string(NUM_LAYERS).c_str()));
160 break;
161 case InputCommand::DUMP_MAXLAYERS_INVALID:
162 args.push_back(String16("-dump"));
163 args.push_back(String16("-maxlayers"));
164 args.push_back(String16(NUM_LAYERS_INVALID));
165 break;
166 default:
167 ALOGD("Invalid control command");
168 }
169
170 EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, result));
171 return result;
172 }
173
genLayerName(int32_t layerID)174 static std::string genLayerName(int32_t layerID) {
175 return (layerID < 0 ? "invalid.dummy" : "com.dummy#") + std::to_string(layerID);
176 }
177
setTimeStamp(TimeStamp type,int32_t id,uint64_t frameNumber,nsecs_t ts)178 void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
179 switch (type) {
180 case TimeStamp::POST:
181 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), ts));
182 break;
183 case TimeStamp::ACQUIRE:
184 ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts));
185 break;
186 case TimeStamp::ACQUIRE_FENCE:
187 ASSERT_NO_FATAL_FAILURE(
188 mTimeStats->setAcquireFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
189 break;
190 case TimeStamp::LATCH:
191 ASSERT_NO_FATAL_FAILURE(mTimeStats->setLatchTime(id, frameNumber, ts));
192 break;
193 case TimeStamp::DESIRED:
194 ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
195 break;
196 case TimeStamp::PRESENT:
197 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
198 break;
199 case TimeStamp::PRESENT_FENCE:
200 ASSERT_NO_FATAL_FAILURE(
201 mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
202 break;
203 default:
204 ALOGD("Invalid timestamp type");
205 }
206 }
207
genRandomInt32(int32_t begin,int32_t end)208 int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) {
209 std::uniform_int_distribution<int32_t> distr(begin, end);
210 return distr(mRandomEngine);
211 }
212
TEST_F(TimeStatsTest,canEnableAndDisableTimeStats)213 TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
214 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
215 ASSERT_TRUE(mTimeStats->isEnabled());
216
217 EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
218 ASSERT_FALSE(mTimeStats->isEnabled());
219 }
220
TEST_F(TimeStatsTest,canIncreaseGlobalStats)221 TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
222 constexpr size_t TOTAL_FRAMES = 5;
223 constexpr size_t MISSED_FRAMES = 4;
224 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
225
226 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
227
228 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
229 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
230 }
231 for (size_t i = 0; i < MISSED_FRAMES; i++) {
232 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
233 }
234 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
235 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
236 }
237
238 SFTimeStatsGlobalProto globalProto;
239 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
240
241 ASSERT_TRUE(globalProto.has_total_frames());
242 EXPECT_EQ(TOTAL_FRAMES, globalProto.total_frames());
243 ASSERT_TRUE(globalProto.has_missed_frames());
244 EXPECT_EQ(MISSED_FRAMES, globalProto.missed_frames());
245 ASSERT_TRUE(globalProto.has_client_composition_frames());
246 EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
247 }
248
TEST_F(TimeStatsTest,canInsertGlobalPresentToPresent)249 TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
250 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
251
252 ASSERT_NO_FATAL_FAILURE(
253 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
254 ASSERT_NO_FATAL_FAILURE(
255 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
256
257 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
258 ASSERT_NO_FATAL_FAILURE(
259 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
260 ASSERT_NO_FATAL_FAILURE(
261 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
262
263 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
264 ASSERT_NO_FATAL_FAILURE(
265 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
266 ASSERT_NO_FATAL_FAILURE(
267 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(8000000)));
268
269 SFTimeStatsGlobalProto globalProto;
270 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
271
272 ASSERT_EQ(1, globalProto.present_to_present_size());
273 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.present_to_present().Get(0);
274 EXPECT_EQ(1, histogramProto.frame_count());
275 EXPECT_EQ(2, histogramProto.time_millis());
276 }
277
TEST_F(TimeStatsTest,canInsertOneLayerTimeStats)278 TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
279 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
280
281 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
282 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
283
284 SFTimeStatsGlobalProto globalProto;
285 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
286
287 ASSERT_EQ(1, globalProto.stats_size());
288 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
289 ASSERT_TRUE(layerProto.has_layer_name());
290 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
291 ASSERT_TRUE(layerProto.has_total_frames());
292 EXPECT_EQ(1, layerProto.total_frames());
293 ASSERT_EQ(6, layerProto.deltas_size());
294 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
295 ASSERT_EQ(1, deltaProto.histograms_size());
296 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
297 EXPECT_EQ(1, histogramProto.frame_count());
298 if ("post2acquire" == deltaProto.delta_name()) {
299 EXPECT_EQ(1, histogramProto.time_millis());
300 } else if ("post2present" == deltaProto.delta_name()) {
301 EXPECT_EQ(4, histogramProto.time_millis());
302 } else if ("acquire2present" == deltaProto.delta_name()) {
303 EXPECT_EQ(3, histogramProto.time_millis());
304 } else if ("latch2present" == deltaProto.delta_name()) {
305 EXPECT_EQ(2, histogramProto.time_millis());
306 } else if ("desired2present" == deltaProto.delta_name()) {
307 EXPECT_EQ(1, histogramProto.time_millis());
308 } else if ("present2present" == deltaProto.delta_name()) {
309 EXPECT_EQ(1, histogramProto.time_millis());
310 } else {
311 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
312 }
313 }
314 }
315
TEST_F(TimeStatsTest,canNotInsertInvalidLayerNameTimeStats)316 TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
317 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
318
319 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
320 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
321
322 SFTimeStatsGlobalProto globalProto;
323 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
324
325 ASSERT_EQ(0, globalProto.stats_size());
326 }
327
TEST_F(TimeStatsTest,canInsertMultipleLayersTimeStats)328 TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
329 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
330
331 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
332 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
333 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
334 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
335
336 SFTimeStatsGlobalProto globalProto;
337 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
338
339 EXPECT_EQ(2, globalProto.stats_size());
340 }
341
TEST_F(TimeStatsTest,canInsertUnorderedLayerTimeStats)342 TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
343 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
344
345 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
346 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
347
348 SFTimeStatsGlobalProto globalProto;
349 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
350
351 ASSERT_EQ(1, globalProto.stats_size());
352 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
353 ASSERT_TRUE(layerProto.has_layer_name());
354 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
355 ASSERT_TRUE(layerProto.has_total_frames());
356 EXPECT_EQ(1, layerProto.total_frames());
357 ASSERT_EQ(6, layerProto.deltas_size());
358 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
359 ASSERT_EQ(1, deltaProto.histograms_size());
360 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
361 EXPECT_EQ(1, histogramProto.frame_count());
362 if ("post2acquire" == deltaProto.delta_name()) {
363 EXPECT_EQ(0, histogramProto.time_millis());
364 } else if ("post2present" == deltaProto.delta_name()) {
365 EXPECT_EQ(2, histogramProto.time_millis());
366 } else if ("acquire2present" == deltaProto.delta_name()) {
367 EXPECT_EQ(2, histogramProto.time_millis());
368 } else if ("latch2present" == deltaProto.delta_name()) {
369 EXPECT_EQ(2, histogramProto.time_millis());
370 } else if ("desired2present" == deltaProto.delta_name()) {
371 EXPECT_EQ(1, histogramProto.time_millis());
372 } else if ("present2present" == deltaProto.delta_name()) {
373 EXPECT_EQ(1, histogramProto.time_millis());
374 } else {
375 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
376 }
377 }
378 }
379
TEST_F(TimeStatsTest,recordRefreshRateNewConfigs)380 TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
381 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
382
383 uint32_t fpsOne = 30;
384 uint32_t fpsTwo = 90;
385 uint64_t millisOne = 5000;
386 uint64_t millisTwo = 7000;
387
388 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
389 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
390
391 SFTimeStatsGlobalProto globalProto;
392 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
393
394 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
395 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
396 expectedConfigOne->set_fps(fpsOne);
397 expectedBucketOne.set_duration_millis(millisOne);
398
399 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
400 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
401 expectedConfigTwo->set_fps(fpsTwo);
402 expectedBucketTwo.set_duration_millis(millisTwo);
403
404 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
405
406 std::unordered_set<uint32_t> seen_fps;
407 for (const auto& bucket : globalProto.display_config_stats()) {
408 seen_fps.emplace(bucket.config().fps());
409 if (fpsOne == bucket.config().fps()) {
410 EXPECT_EQ(millisOne, bucket.duration_millis());
411 } else if (fpsTwo == bucket.config().fps()) {
412 EXPECT_EQ(millisTwo, bucket.duration_millis());
413 } else {
414 FAIL() << "Unknown fps: " << bucket.config().fps();
415 }
416 }
417 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
418 }
419
TEST_F(TimeStatsTest,recordRefreshRateUpdatesConfig)420 TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
421 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
422
423 uint32_t fps = 30;
424 uint64_t millisOne = 5000;
425 uint64_t millisTwo = 7000;
426
427 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
428 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
429
430 SFTimeStatsGlobalProto globalProto;
431 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
432 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
433 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
434 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
435 }
436
TEST_F(TimeStatsTest,canRemoveTimeRecord)437 TEST_F(TimeStatsTest, canRemoveTimeRecord) {
438 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
439
440 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
441 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
442 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
443 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
444
445 SFTimeStatsGlobalProto globalProto;
446 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
447
448 ASSERT_EQ(1, globalProto.stats_size());
449 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
450 ASSERT_TRUE(layerProto.has_total_frames());
451 EXPECT_EQ(1, layerProto.total_frames());
452 }
453
TEST_F(TimeStatsTest,canRecoverFromIncompleteTimeRecordError)454 TEST_F(TimeStatsTest, canRecoverFromIncompleteTimeRecordError) {
455 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
456
457 uint64_t frameNumber = 1;
458 nsecs_t ts = 1000000;
459 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
460 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
461 frameNumber++;
462 ts += 1000000;
463 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
464 }
465
466 SFTimeStatsGlobalProto globalProto;
467 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
468
469 ASSERT_EQ(1, globalProto.stats_size());
470 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
471 ASSERT_TRUE(layerProto.has_total_frames());
472 EXPECT_EQ(1, layerProto.total_frames());
473 }
474
TEST_F(TimeStatsTest,layerTimeStatsOnDestroy)475 TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
476 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
477
478 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
479 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
480 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
481 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
482
483 SFTimeStatsGlobalProto globalProto;
484 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
485
486 ASSERT_EQ(1, globalProto.stats_size());
487 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
488 ASSERT_TRUE(layerProto.has_total_frames());
489 EXPECT_EQ(1, layerProto.total_frames());
490 }
491
TEST_F(TimeStatsTest,canClearTimeStats)492 TEST_F(TimeStatsTest, canClearTimeStats) {
493 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
494
495 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
496 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
497 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
498 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
499 ASSERT_NO_FATAL_FAILURE(
500 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
501 ASSERT_NO_FATAL_FAILURE(
502 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
503 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
504 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
505
506 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
507
508 SFTimeStatsGlobalProto globalProto;
509 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
510
511 EXPECT_EQ(0, globalProto.total_frames());
512 EXPECT_EQ(0, globalProto.missed_frames());
513 EXPECT_EQ(0, globalProto.client_composition_frames());
514 EXPECT_EQ(0, globalProto.present_to_present_size());
515 EXPECT_EQ(0, globalProto.stats_size());
516 }
517
TEST_F(TimeStatsTest,canDumpWithMaxLayers)518 TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
519 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
520
521 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
522 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
523 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
524 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
525 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
526
527 SFTimeStatsGlobalProto globalProto;
528 ASSERT_TRUE(
529 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
530
531 ASSERT_EQ(1, globalProto.stats_size());
532 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
533 ASSERT_TRUE(layerProto.has_layer_name());
534 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
535 ASSERT_TRUE(layerProto.has_total_frames());
536 EXPECT_EQ(2, layerProto.total_frames());
537 }
538
TEST_F(TimeStatsTest,canDumpWithInvalidMaxLayers)539 TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
540 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
541
542 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
543 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
544
545 SFTimeStatsGlobalProto globalProto;
546 ASSERT_TRUE(globalProto.ParseFromString(
547 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
548
549 ASSERT_EQ(0, globalProto.stats_size());
550 }
551
TEST_F(TimeStatsTest,canSurviveMonkey)552 TEST_F(TimeStatsTest, canSurviveMonkey) {
553 if (g_noSlowTests) {
554 GTEST_SKIP();
555 }
556
557 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
558
559 for (size_t i = 0; i < 10000000; ++i) {
560 const int32_t layerID = genRandomInt32(-1, 10);
561 const int32_t frameNumber = genRandomInt32(1, 10);
562 switch (genRandomInt32(0, 100)) {
563 case 0:
564 ALOGV("removeTimeRecord");
565 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerID, frameNumber));
566 continue;
567 case 1:
568 ALOGV("onDestroy");
569 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerID));
570 continue;
571 }
572 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
573 const int32_t ts = genRandomInt32(1, 1000000000);
574 ALOGV("type[%d], layerID[%d], frameNumber[%d], ts[%d]", type, layerID, frameNumber, ts);
575 setTimeStamp(type, layerID, frameNumber, ts);
576 }
577 }
578
579 } // namespace
580 } // namespace android
581