blob: 68e4c585da3ab27e9c56aeb54c3b6f4edd9ab6de [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
Alec Mourie4034bb2019-11-19 12:45:54 -0800306TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
307 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
308
309 using namespace std::chrono_literals;
310
311 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
312 .count(),
313 std::make_shared<FenceTime>(
314 std::chrono::duration_cast<
315 std::chrono::nanoseconds>(3ms)
316 .count()));
317
318 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
319 .count(),
320 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
321 .count());
322
323 // First verify that flushing RenderEngine durations did not occur yet.
324 SFTimeStatsGlobalProto preFlushProto;
325 ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
326 ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
327
328 // Push a dummy present fence to trigger flushing the RenderEngine timings.
329 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
330 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
331 std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
332
333 // Now we can verify that RenderEngine durations were flushed now.
334 SFTimeStatsGlobalProto postFlushProto;
335 ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
336
337 ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
338 const SFTimeStatsHistogramBucketProto& histogramProto =
339 postFlushProto.render_engine_timing().Get(0);
340 EXPECT_EQ(2, histogramProto.frame_count());
341 EXPECT_EQ(2, histogramProto.time_millis());
342}
343
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800344TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
345 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
346
347 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
348 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
349
350 SFTimeStatsGlobalProto globalProto;
351 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
352
353 ASSERT_EQ(1, globalProto.stats_size());
354 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
355 ASSERT_TRUE(layerProto.has_layer_name());
356 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
357 ASSERT_TRUE(layerProto.has_total_frames());
358 EXPECT_EQ(1, layerProto.total_frames());
359 ASSERT_EQ(6, layerProto.deltas_size());
360 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
361 ASSERT_EQ(1, deltaProto.histograms_size());
362 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
363 EXPECT_EQ(1, histogramProto.frame_count());
364 if ("post2acquire" == deltaProto.delta_name()) {
365 EXPECT_EQ(1, histogramProto.time_millis());
366 } else if ("post2present" == deltaProto.delta_name()) {
367 EXPECT_EQ(4, histogramProto.time_millis());
368 } else if ("acquire2present" == deltaProto.delta_name()) {
369 EXPECT_EQ(3, histogramProto.time_millis());
370 } else if ("latch2present" == deltaProto.delta_name()) {
371 EXPECT_EQ(2, histogramProto.time_millis());
372 } else if ("desired2present" == deltaProto.delta_name()) {
373 EXPECT_EQ(1, histogramProto.time_millis());
374 } else if ("present2present" == deltaProto.delta_name()) {
375 EXPECT_EQ(1, histogramProto.time_millis());
376 } else {
377 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
378 }
379 }
380}
381
382TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
383 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
384
385 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
386 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
387
388 SFTimeStatsGlobalProto globalProto;
389 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
390
391 ASSERT_EQ(0, globalProto.stats_size());
392}
393
394TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
395 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
396
397 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
398 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
399 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
400 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
401
402 SFTimeStatsGlobalProto globalProto;
403 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
404
405 EXPECT_EQ(2, globalProto.stats_size());
406}
407
408TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
409 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
410
411 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
412 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
413
414 SFTimeStatsGlobalProto globalProto;
415 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
416
417 ASSERT_EQ(1, globalProto.stats_size());
418 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
419 ASSERT_TRUE(layerProto.has_layer_name());
420 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
421 ASSERT_TRUE(layerProto.has_total_frames());
422 EXPECT_EQ(1, layerProto.total_frames());
423 ASSERT_EQ(6, layerProto.deltas_size());
424 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
425 ASSERT_EQ(1, deltaProto.histograms_size());
426 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
427 EXPECT_EQ(1, histogramProto.frame_count());
428 if ("post2acquire" == deltaProto.delta_name()) {
429 EXPECT_EQ(0, histogramProto.time_millis());
430 } else if ("post2present" == deltaProto.delta_name()) {
431 EXPECT_EQ(2, histogramProto.time_millis());
432 } else if ("acquire2present" == deltaProto.delta_name()) {
433 EXPECT_EQ(2, histogramProto.time_millis());
434 } else if ("latch2present" == deltaProto.delta_name()) {
435 EXPECT_EQ(2, histogramProto.time_millis());
436 } else if ("desired2present" == deltaProto.delta_name()) {
437 EXPECT_EQ(1, histogramProto.time_millis());
438 } else if ("present2present" == deltaProto.delta_name()) {
439 EXPECT_EQ(1, histogramProto.time_millis());
440 } else {
441 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
442 }
443 }
444}
445
Alec Mourifb571ea2019-01-24 18:42:10 -0800446TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
447 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
448
449 uint32_t fpsOne = 30;
450 uint32_t fpsTwo = 90;
451 uint64_t millisOne = 5000;
452 uint64_t millisTwo = 7000;
453
454 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
455 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
456
457 SFTimeStatsGlobalProto globalProto;
458 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
459
460 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
461 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
462 expectedConfigOne->set_fps(fpsOne);
463 expectedBucketOne.set_duration_millis(millisOne);
464
465 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
466 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
467 expectedConfigTwo->set_fps(fpsTwo);
468 expectedBucketTwo.set_duration_millis(millisTwo);
469
470 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
471
472 std::unordered_set<uint32_t> seen_fps;
473 for (const auto& bucket : globalProto.display_config_stats()) {
474 seen_fps.emplace(bucket.config().fps());
475 if (fpsOne == bucket.config().fps()) {
476 EXPECT_EQ(millisOne, bucket.duration_millis());
477 } else if (fpsTwo == bucket.config().fps()) {
478 EXPECT_EQ(millisTwo, bucket.duration_millis());
479 } else {
480 FAIL() << "Unknown fps: " << bucket.config().fps();
481 }
482 }
483 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
484}
485
486TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
487 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
488
489 uint32_t fps = 30;
490 uint64_t millisOne = 5000;
491 uint64_t millisTwo = 7000;
492
493 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
494 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
495
496 SFTimeStatsGlobalProto globalProto;
497 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
498 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
499 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
500 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
501}
502
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800503TEST_F(TimeStatsTest, canRemoveTimeRecord) {
504 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
505
506 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
507 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
508 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
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, canRecoverFromIncompleteTimeRecordError) {
521 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
522
523 uint64_t frameNumber = 1;
524 nsecs_t ts = 1000000;
525 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
Alec Mourifb571ea2019-01-24 18:42:10 -0800526 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800527 frameNumber++;
528 ts += 1000000;
529 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
530 }
531
532 SFTimeStatsGlobalProto globalProto;
533 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
534
535 ASSERT_EQ(1, globalProto.stats_size());
536 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
537 ASSERT_TRUE(layerProto.has_total_frames());
538 EXPECT_EQ(1, layerProto.total_frames());
539}
540
541TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
542 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
543
544 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
545 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
546 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
547 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
548
549 SFTimeStatsGlobalProto globalProto;
550 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
551
552 ASSERT_EQ(1, globalProto.stats_size());
553 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
554 ASSERT_TRUE(layerProto.has_total_frames());
555 EXPECT_EQ(1, layerProto.total_frames());
556}
557
558TEST_F(TimeStatsTest, canClearTimeStats) {
559 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
560
561 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
562 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
563 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
564 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
565 ASSERT_NO_FATAL_FAILURE(
566 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
567 ASSERT_NO_FATAL_FAILURE(
568 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
569 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
570 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
571
572 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
573
574 SFTimeStatsGlobalProto globalProto;
575 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
576
577 EXPECT_EQ(0, globalProto.total_frames());
578 EXPECT_EQ(0, globalProto.missed_frames());
579 EXPECT_EQ(0, globalProto.client_composition_frames());
580 EXPECT_EQ(0, globalProto.present_to_present_size());
581 EXPECT_EQ(0, globalProto.stats_size());
582}
583
584TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
585 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
586
587 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
588 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
589 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
590 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
591 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
592
593 SFTimeStatsGlobalProto globalProto;
594 ASSERT_TRUE(
595 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
596
597 ASSERT_EQ(1, globalProto.stats_size());
598 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
599 ASSERT_TRUE(layerProto.has_layer_name());
600 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
601 ASSERT_TRUE(layerProto.has_total_frames());
602 EXPECT_EQ(2, layerProto.total_frames());
603}
604
605TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
606 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
607
608 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
609 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
610
611 SFTimeStatsGlobalProto globalProto;
612 ASSERT_TRUE(globalProto.ParseFromString(
613 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
614
615 ASSERT_EQ(0, globalProto.stats_size());
616}
617
618TEST_F(TimeStatsTest, canSurviveMonkey) {
Lloyd Pique067fe1e2018-12-06 19:44:13 -0800619 if (g_noSlowTests) {
620 GTEST_SKIP();
621 }
622
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800623 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
624
625 for (size_t i = 0; i < 10000000; ++i) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800626 const int32_t layerId = genRandomInt32(-1, 10);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800627 const int32_t frameNumber = genRandomInt32(1, 10);
628 switch (genRandomInt32(0, 100)) {
629 case 0:
630 ALOGV("removeTimeRecord");
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800631 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800632 continue;
633 case 1:
634 ALOGV("onDestroy");
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800635 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800636 continue;
637 }
638 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
639 const int32_t ts = genRandomInt32(1, 1000000000);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800640 ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
641 setTimeStamp(type, layerId, frameNumber, ts);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800642 }
643}
644
645} // namespace
646} // namespace android