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