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