blob: ec27201bcae5140fba87e7cacb7f3474c3eead78 [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 Mourid5065452019-12-07 18:18:48 -080039using testing::_;
Alec Mourifb571ea2019-01-24 18:42:10 -080040using testing::Contains;
Alec Mourid5065452019-12-07 18:18:48 -080041using testing::InSequence;
Alec Mourifb571ea2019-01-24 18:42:10 -080042using testing::SizeIs;
43using testing::UnorderedElementsAre;
44
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080045// clang-format off
46#define FMT_PROTO true
47#define FMT_STRING false
48#define LAYER_ID_0 0
49#define LAYER_ID_1 1
50#define LAYER_ID_INVALID -1
51#define NUM_LAYERS 1
52#define NUM_LAYERS_INVALID "INVALID"
53
54enum InputCommand : int32_t {
55 ENABLE = 0,
56 DISABLE = 1,
57 CLEAR = 2,
58 DUMP_ALL = 3,
59 DUMP_MAXLAYERS_1 = 4,
60 DUMP_MAXLAYERS_INVALID = 5,
61 INPUT_COMMAND_BEGIN = ENABLE,
62 INPUT_COMMAND_END = DUMP_MAXLAYERS_INVALID,
63 INPUT_COMMAND_RANGE = INPUT_COMMAND_END - INPUT_COMMAND_BEGIN + 1,
64};
65
66enum TimeStamp : int32_t {
67 POST = 0,
68 ACQUIRE = 1,
69 ACQUIRE_FENCE = 2,
70 LATCH = 3,
71 DESIRED = 4,
72 PRESENT = 5,
73 PRESENT_FENCE = 6,
74 TIME_STAMP_BEGIN = POST,
75 TIME_STAMP_END = PRESENT,
76 TIME_STAMP_RANGE = TIME_STAMP_END - TIME_STAMP_BEGIN + 1,
77};
78
79static const TimeStamp NORMAL_SEQUENCE[] = {
80 TimeStamp::POST,
81 TimeStamp::ACQUIRE,
82 TimeStamp::LATCH,
83 TimeStamp::DESIRED,
84 TimeStamp::PRESENT,
85};
86
87static const TimeStamp NORMAL_SEQUENCE_2[] = {
88 TimeStamp::POST,
89 TimeStamp::ACQUIRE_FENCE,
90 TimeStamp::LATCH,
91 TimeStamp::DESIRED,
92 TimeStamp::PRESENT_FENCE,
93};
94
95static const TimeStamp UNORDERED_SEQUENCE[] = {
96 TimeStamp::ACQUIRE,
97 TimeStamp::LATCH,
98 TimeStamp::POST,
99 TimeStamp::DESIRED,
100 TimeStamp::PRESENT,
101};
102
103static const TimeStamp INCOMPLETE_SEQUENCE[] = {
104 TimeStamp::POST,
105};
106// clang-format on
107
108class TimeStatsTest : public testing::Test {
109public:
110 TimeStatsTest() {
111 const ::testing::TestInfo* const test_info =
112 ::testing::UnitTest::GetInstance()->current_test_info();
113 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
114 }
115
116 ~TimeStatsTest() {
117 const ::testing::TestInfo* const test_info =
118 ::testing::UnitTest::GetInstance()->current_test_info();
119 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
120 }
121
122 std::string inputCommand(InputCommand cmd, bool useProto);
123
124 void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
125
126 int32_t genRandomInt32(int32_t begin, int32_t end);
127
128 template <size_t N>
129 void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber,
130 nsecs_t ts) {
131 for (size_t i = 0; i < N; i++, ts += 1000000) {
132 setTimeStamp(sequence[i], id, frameNumber, ts);
133 }
134 }
135
136 std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
Alec Mourid5065452019-12-07 18:18:48 -0800137
138 class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
139 public:
140 FakeStatsEventDelegate() = default;
141 ~FakeStatsEventDelegate() override = default;
142
143 struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
144 return mEvent;
145 }
146 void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
147 pull_atom_metadata*, void* cookie) override {
148 mAtomTag = atom_tag;
149 mCallback = callback;
150 mCookie = cookie;
151 }
152
153 bool checkStatsService() override { return true; }
154
155 bool makePullAtomCallback(int32_t atom_tag, const void* cookie) {
156 return (*mCallback)(atom_tag, nullptr, cookie);
157 }
158
159 MOCK_METHOD2(statsEventSetAtomId, void(struct stats_event*, int32_t));
160 MOCK_METHOD2(statsEventWriteInt64, void(struct stats_event*, int64_t));
161 MOCK_METHOD1(statsEventBuild, void(struct stats_event*));
162
163 struct stats_event* mEvent = stats_event_obtain();
164 int32_t mAtomTag = 0;
165 stats_pull_atom_callback_t mCallback = nullptr;
166 void* mCookie = nullptr;
167 };
168
169 FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
170 std::unique_ptr<TimeStats> mTimeStats =
171 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800172};
173
174std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
Yiwei Zhang5434a782018-12-05 18:06:32 -0800175 std::string result;
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800176 Vector<String16> args;
177
178 switch (cmd) {
179 case InputCommand::ENABLE:
180 args.push_back(String16("-enable"));
181 break;
182 case InputCommand::DISABLE:
183 args.push_back(String16("-disable"));
184 break;
185 case InputCommand::CLEAR:
186 args.push_back(String16("-clear"));
187 break;
188 case InputCommand::DUMP_ALL:
189 args.push_back(String16("-dump"));
190 break;
191 case InputCommand::DUMP_MAXLAYERS_1:
192 args.push_back(String16("-dump"));
193 args.push_back(String16("-maxlayers"));
194 args.push_back(String16(std::to_string(NUM_LAYERS).c_str()));
195 break;
196 case InputCommand::DUMP_MAXLAYERS_INVALID:
197 args.push_back(String16("-dump"));
198 args.push_back(String16("-maxlayers"));
199 args.push_back(String16(NUM_LAYERS_INVALID));
200 break;
201 default:
202 ALOGD("Invalid control command");
203 }
204
Dominik Laskowskic2867142019-01-21 11:33:38 -0800205 EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, result));
Yiwei Zhang5434a782018-12-05 18:06:32 -0800206 return result;
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800207}
208
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800209static std::string genLayerName(int32_t layerId) {
210 return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.dummy#") + std::to_string(layerId);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800211}
212
213void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
214 switch (type) {
215 case TimeStamp::POST:
216 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), ts));
217 break;
218 case TimeStamp::ACQUIRE:
219 ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts));
220 break;
221 case TimeStamp::ACQUIRE_FENCE:
222 ASSERT_NO_FATAL_FAILURE(
223 mTimeStats->setAcquireFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
224 break;
225 case TimeStamp::LATCH:
226 ASSERT_NO_FATAL_FAILURE(mTimeStats->setLatchTime(id, frameNumber, ts));
227 break;
228 case TimeStamp::DESIRED:
229 ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
230 break;
231 case TimeStamp::PRESENT:
232 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
233 break;
234 case TimeStamp::PRESENT_FENCE:
235 ASSERT_NO_FATAL_FAILURE(
236 mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
237 break;
238 default:
239 ALOGD("Invalid timestamp type");
240 }
241}
242
243int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) {
244 std::uniform_int_distribution<int32_t> distr(begin, end);
245 return distr(mRandomEngine);
246}
247
Alec Mourib3885ad2019-09-06 17:08:55 -0700248TEST_F(TimeStatsTest, enabledByDefault) {
249 ASSERT_TRUE(mTimeStats->isEnabled());
250}
251
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800252TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
253 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
254 ASSERT_TRUE(mTimeStats->isEnabled());
255
256 EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
257 ASSERT_FALSE(mTimeStats->isEnabled());
258}
259
260TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
261 constexpr size_t TOTAL_FRAMES = 5;
262 constexpr size_t MISSED_FRAMES = 4;
263 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
264
265 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
266
267 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
268 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
269 }
270 for (size_t i = 0; i < MISSED_FRAMES; i++) {
271 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
272 }
273 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
274 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
275 }
276
277 SFTimeStatsGlobalProto globalProto;
278 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
279
280 ASSERT_TRUE(globalProto.has_total_frames());
281 EXPECT_EQ(TOTAL_FRAMES, globalProto.total_frames());
282 ASSERT_TRUE(globalProto.has_missed_frames());
283 EXPECT_EQ(MISSED_FRAMES, globalProto.missed_frames());
284 ASSERT_TRUE(globalProto.has_client_composition_frames());
285 EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
286}
287
288TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
289 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
290
291 ASSERT_NO_FATAL_FAILURE(
292 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
293 ASSERT_NO_FATAL_FAILURE(
294 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
295
296 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
297 ASSERT_NO_FATAL_FAILURE(
298 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
299 ASSERT_NO_FATAL_FAILURE(
300 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
301
302 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
303 ASSERT_NO_FATAL_FAILURE(
304 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
305 ASSERT_NO_FATAL_FAILURE(
306 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(8000000)));
307
308 SFTimeStatsGlobalProto globalProto;
309 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
310
311 ASSERT_EQ(1, globalProto.present_to_present_size());
312 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.present_to_present().Get(0);
313 EXPECT_EQ(1, histogramProto.frame_count());
314 EXPECT_EQ(2, histogramProto.time_millis());
315}
316
Alec Mouri9519bf12019-11-15 16:54:44 -0800317TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
318 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
319
320 using namespace std::chrono_literals;
321
322 mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
323 mTimeStats
324 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
325 std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
326 .count());
327 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
328 mTimeStats
329 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
330 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
331 .count());
332
333 SFTimeStatsGlobalProto globalProto;
334 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
335
336 ASSERT_EQ(1, globalProto.frame_duration_size());
337 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
338 EXPECT_EQ(1, histogramProto.frame_count());
339 EXPECT_EQ(3, histogramProto.time_millis());
340}
341
Alec Mourie4034bb2019-11-19 12:45:54 -0800342TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
343 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
344
345 using namespace std::chrono_literals;
346
347 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
348 .count(),
349 std::make_shared<FenceTime>(
350 std::chrono::duration_cast<
351 std::chrono::nanoseconds>(3ms)
352 .count()));
353
354 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
355 .count(),
356 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
357 .count());
358
359 // First verify that flushing RenderEngine durations did not occur yet.
360 SFTimeStatsGlobalProto preFlushProto;
361 ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
362 ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
363
364 // Push a dummy present fence to trigger flushing the RenderEngine timings.
365 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
366 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
367 std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
368
369 // Now we can verify that RenderEngine durations were flushed now.
370 SFTimeStatsGlobalProto postFlushProto;
371 ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
372
373 ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
374 const SFTimeStatsHistogramBucketProto& histogramProto =
375 postFlushProto.render_engine_timing().Get(0);
376 EXPECT_EQ(2, histogramProto.frame_count());
377 EXPECT_EQ(2, histogramProto.time_millis());
378}
379
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800380TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
381 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
382
383 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
384 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
385
386 SFTimeStatsGlobalProto globalProto;
387 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
388
389 ASSERT_EQ(1, globalProto.stats_size());
390 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
391 ASSERT_TRUE(layerProto.has_layer_name());
392 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
393 ASSERT_TRUE(layerProto.has_total_frames());
394 EXPECT_EQ(1, layerProto.total_frames());
395 ASSERT_EQ(6, layerProto.deltas_size());
396 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
397 ASSERT_EQ(1, deltaProto.histograms_size());
398 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
399 EXPECT_EQ(1, histogramProto.frame_count());
400 if ("post2acquire" == deltaProto.delta_name()) {
401 EXPECT_EQ(1, histogramProto.time_millis());
402 } else if ("post2present" == deltaProto.delta_name()) {
403 EXPECT_EQ(4, histogramProto.time_millis());
404 } else if ("acquire2present" == deltaProto.delta_name()) {
405 EXPECT_EQ(3, histogramProto.time_millis());
406 } else if ("latch2present" == deltaProto.delta_name()) {
407 EXPECT_EQ(2, histogramProto.time_millis());
408 } else if ("desired2present" == deltaProto.delta_name()) {
409 EXPECT_EQ(1, histogramProto.time_millis());
410 } else if ("present2present" == deltaProto.delta_name()) {
411 EXPECT_EQ(1, histogramProto.time_millis());
412 } else {
413 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
414 }
415 }
416}
417
418TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
419 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
420
421 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
422 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
423
424 SFTimeStatsGlobalProto globalProto;
425 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
426
427 ASSERT_EQ(0, globalProto.stats_size());
428}
429
430TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
431 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
432
433 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
434 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
435 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
436 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
437
438 SFTimeStatsGlobalProto globalProto;
439 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
440
441 EXPECT_EQ(2, globalProto.stats_size());
442}
443
444TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
445 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
446
447 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
448 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
449
450 SFTimeStatsGlobalProto globalProto;
451 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
452
453 ASSERT_EQ(1, globalProto.stats_size());
454 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
455 ASSERT_TRUE(layerProto.has_layer_name());
456 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
457 ASSERT_TRUE(layerProto.has_total_frames());
458 EXPECT_EQ(1, layerProto.total_frames());
459 ASSERT_EQ(6, layerProto.deltas_size());
460 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
461 ASSERT_EQ(1, deltaProto.histograms_size());
462 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
463 EXPECT_EQ(1, histogramProto.frame_count());
464 if ("post2acquire" == deltaProto.delta_name()) {
465 EXPECT_EQ(0, histogramProto.time_millis());
466 } else if ("post2present" == deltaProto.delta_name()) {
467 EXPECT_EQ(2, histogramProto.time_millis());
468 } else if ("acquire2present" == deltaProto.delta_name()) {
469 EXPECT_EQ(2, histogramProto.time_millis());
470 } else if ("latch2present" == deltaProto.delta_name()) {
471 EXPECT_EQ(2, histogramProto.time_millis());
472 } else if ("desired2present" == deltaProto.delta_name()) {
473 EXPECT_EQ(1, histogramProto.time_millis());
474 } else if ("present2present" == deltaProto.delta_name()) {
475 EXPECT_EQ(1, histogramProto.time_millis());
476 } else {
477 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
478 }
479 }
480}
481
Alec Mourifb571ea2019-01-24 18:42:10 -0800482TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
483 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
484
485 uint32_t fpsOne = 30;
486 uint32_t fpsTwo = 90;
487 uint64_t millisOne = 5000;
488 uint64_t millisTwo = 7000;
489
490 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
491 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
492
493 SFTimeStatsGlobalProto globalProto;
494 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
495
496 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
497 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
498 expectedConfigOne->set_fps(fpsOne);
499 expectedBucketOne.set_duration_millis(millisOne);
500
501 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
502 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
503 expectedConfigTwo->set_fps(fpsTwo);
504 expectedBucketTwo.set_duration_millis(millisTwo);
505
506 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
507
508 std::unordered_set<uint32_t> seen_fps;
509 for (const auto& bucket : globalProto.display_config_stats()) {
510 seen_fps.emplace(bucket.config().fps());
511 if (fpsOne == bucket.config().fps()) {
512 EXPECT_EQ(millisOne, bucket.duration_millis());
513 } else if (fpsTwo == bucket.config().fps()) {
514 EXPECT_EQ(millisTwo, bucket.duration_millis());
515 } else {
516 FAIL() << "Unknown fps: " << bucket.config().fps();
517 }
518 }
519 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
520}
521
522TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
523 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
524
525 uint32_t fps = 30;
526 uint64_t millisOne = 5000;
527 uint64_t millisTwo = 7000;
528
529 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
530 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
531
532 SFTimeStatsGlobalProto globalProto;
533 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
534 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
535 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
536 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
537}
538
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800539TEST_F(TimeStatsTest, canRemoveTimeRecord) {
540 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
541
542 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
543 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
544 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
545 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
546
547 SFTimeStatsGlobalProto globalProto;
548 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
549
550 ASSERT_EQ(1, globalProto.stats_size());
551 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
552 ASSERT_TRUE(layerProto.has_total_frames());
553 EXPECT_EQ(1, layerProto.total_frames());
554}
555
556TEST_F(TimeStatsTest, canRecoverFromIncompleteTimeRecordError) {
557 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
558
559 uint64_t frameNumber = 1;
560 nsecs_t ts = 1000000;
561 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
Alec Mourifb571ea2019-01-24 18:42:10 -0800562 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800563 frameNumber++;
564 ts += 1000000;
565 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
566 }
567
568 SFTimeStatsGlobalProto globalProto;
569 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
570
571 ASSERT_EQ(1, globalProto.stats_size());
572 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
573 ASSERT_TRUE(layerProto.has_total_frames());
574 EXPECT_EQ(1, layerProto.total_frames());
575}
576
577TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
578 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
579
580 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
581 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
582 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
583 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
584
585 SFTimeStatsGlobalProto globalProto;
586 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
587
588 ASSERT_EQ(1, globalProto.stats_size());
589 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
590 ASSERT_TRUE(layerProto.has_total_frames());
591 EXPECT_EQ(1, layerProto.total_frames());
592}
593
594TEST_F(TimeStatsTest, canClearTimeStats) {
595 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
596
597 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
598 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
599 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
600 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
Alec Mouri31ac64a2020-01-09 09:26:22 -0800601
602 using namespace std::chrono_literals;
603 mTimeStats
604 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
605 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
606 .count());
607 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
608 .count(),
609 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
610 .count());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800611 ASSERT_NO_FATAL_FAILURE(
612 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
613 ASSERT_NO_FATAL_FAILURE(
614 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
615 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
616 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
617
618 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
619
620 SFTimeStatsGlobalProto globalProto;
621 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
622
623 EXPECT_EQ(0, globalProto.total_frames());
624 EXPECT_EQ(0, globalProto.missed_frames());
625 EXPECT_EQ(0, globalProto.client_composition_frames());
626 EXPECT_EQ(0, globalProto.present_to_present_size());
Alec Mouri31ac64a2020-01-09 09:26:22 -0800627 EXPECT_EQ(0, globalProto.frame_duration_size());
628 EXPECT_EQ(0, globalProto.render_engine_timing_size());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800629 EXPECT_EQ(0, globalProto.stats_size());
630}
631
632TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
633 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
634
635 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
636 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
637 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
638 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
639 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
640
641 SFTimeStatsGlobalProto globalProto;
642 ASSERT_TRUE(
643 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
644
645 ASSERT_EQ(1, globalProto.stats_size());
646 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
647 ASSERT_TRUE(layerProto.has_layer_name());
648 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
649 ASSERT_TRUE(layerProto.has_total_frames());
650 EXPECT_EQ(2, layerProto.total_frames());
651}
652
653TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
654 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
655
656 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
657 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
658
659 SFTimeStatsGlobalProto globalProto;
660 ASSERT_TRUE(globalProto.ParseFromString(
661 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
662
663 ASSERT_EQ(0, globalProto.stats_size());
664}
665
Alec Mourid5065452019-12-07 18:18:48 -0800666TEST_F(TimeStatsTest, globalStatsCallback_disabledBeforeBoot) {
667 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
668
669 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
670 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
671 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
672
673 // Callback should not be registered after flushing global stats
674 EXPECT_EQ(nullptr, mDelegate->mCallback);
675}
676
677TEST_F(TimeStatsTest, globalStatsCallback_worksAfterBoot) {
678 constexpr size_t TOTAL_FRAMES = 5;
679 constexpr size_t MISSED_FRAMES = 4;
680 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
681
682 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
683 mTimeStats->onBootFinished();
684
685 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
686 mTimeStats->incrementTotalFrames();
687 }
688 for (size_t i = 0; i < MISSED_FRAMES; i++) {
689 mTimeStats->incrementMissedFrames();
690 }
691 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
692 mTimeStats->incrementClientCompositionFrames();
693 }
694
695 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
696 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
697 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
698
699 EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, mDelegate->mAtomTag);
700 EXPECT_NE(nullptr, mDelegate->mCallback);
701 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
702
703 {
704 InSequence seq;
705 EXPECT_CALL(*mDelegate,
706 statsEventSetAtomId(mDelegate->mEvent,
707 android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
708 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
709 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
710 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
711 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
712 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
713 EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
714 }
715 mDelegate->makePullAtomCallback(mDelegate->mAtomTag, mDelegate->mCookie);
716
717 SFTimeStatsGlobalProto globalProto;
718 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
719
720 EXPECT_EQ(0, globalProto.total_frames());
721 EXPECT_EQ(0, globalProto.missed_frames());
722 EXPECT_EQ(0, globalProto.client_composition_frames());
723 EXPECT_EQ(0, globalProto.present_to_present_size());
724}
725
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800726TEST_F(TimeStatsTest, canSurviveMonkey) {
Lloyd Pique067fe1e2018-12-06 19:44:13 -0800727 if (g_noSlowTests) {
728 GTEST_SKIP();
729 }
730
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800731 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
732
733 for (size_t i = 0; i < 10000000; ++i) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800734 const int32_t layerId = genRandomInt32(-1, 10);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800735 const int32_t frameNumber = genRandomInt32(1, 10);
736 switch (genRandomInt32(0, 100)) {
737 case 0:
738 ALOGV("removeTimeRecord");
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800739 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800740 continue;
741 case 1:
742 ALOGV("onDestroy");
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800743 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800744 continue;
745 }
746 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
747 const int32_t ts = genRandomInt32(1, 1000000000);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800748 ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
749 setTimeStamp(type, layerId, frameNumber, ts);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800750 }
751}
752
753} // namespace
754} // namespace android