blob: 50446262873a9a392eae08cf680d3a622b0aaaa8 [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 Mouri37384342020-01-02 17:23:37 -080025#include <android/util/ProtoOutputStream.h>
Alec Mourifb571ea2019-01-24 18:42:10 -080026#include <gmock/gmock.h>
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080027#include <gtest/gtest.h>
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080028#include <log/log.h>
29#include <utils/String16.h>
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080030#include <utils/Vector.h>
31
Alec Mouri9519bf12019-11-15 16:54:44 -080032#include <chrono>
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080033#include <random>
Alec Mourifb571ea2019-01-24 18:42:10 -080034#include <unordered_set>
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080035
Lloyd Pique067fe1e2018-12-06 19:44:13 -080036#include "libsurfaceflinger_unittest_main.h"
37
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080038using namespace android::surfaceflinger;
39using namespace google::protobuf;
40
41namespace android {
42namespace {
43
Alec Mouri8e2f31b2020-01-16 22:04:35 +000044using testing::_;
Alec Mouri37384342020-01-02 17:23:37 -080045using testing::AnyNumber;
Alec Mourifb571ea2019-01-24 18:42:10 -080046using testing::Contains;
Alec Mouri8e2f31b2020-01-16 22:04:35 +000047using testing::InSequence;
Alec Mourifb571ea2019-01-24 18:42:10 -080048using testing::SizeIs;
Alec Mouri37384342020-01-02 17:23:37 -080049using testing::StrEq;
Alec Mourifb571ea2019-01-24 18:42:10 -080050using testing::UnorderedElementsAre;
51
Yiwei Zhang16faa5d2018-11-13 18:12:59 -080052// clang-format off
53#define FMT_PROTO true
54#define FMT_STRING false
55#define LAYER_ID_0 0
56#define LAYER_ID_1 1
57#define LAYER_ID_INVALID -1
58#define NUM_LAYERS 1
59#define NUM_LAYERS_INVALID "INVALID"
60
61enum InputCommand : int32_t {
62 ENABLE = 0,
63 DISABLE = 1,
64 CLEAR = 2,
65 DUMP_ALL = 3,
66 DUMP_MAXLAYERS_1 = 4,
67 DUMP_MAXLAYERS_INVALID = 5,
68 INPUT_COMMAND_BEGIN = ENABLE,
69 INPUT_COMMAND_END = DUMP_MAXLAYERS_INVALID,
70 INPUT_COMMAND_RANGE = INPUT_COMMAND_END - INPUT_COMMAND_BEGIN + 1,
71};
72
73enum TimeStamp : int32_t {
74 POST = 0,
75 ACQUIRE = 1,
76 ACQUIRE_FENCE = 2,
77 LATCH = 3,
78 DESIRED = 4,
79 PRESENT = 5,
80 PRESENT_FENCE = 6,
81 TIME_STAMP_BEGIN = POST,
82 TIME_STAMP_END = PRESENT,
83 TIME_STAMP_RANGE = TIME_STAMP_END - TIME_STAMP_BEGIN + 1,
84};
85
86static const TimeStamp NORMAL_SEQUENCE[] = {
87 TimeStamp::POST,
88 TimeStamp::ACQUIRE,
89 TimeStamp::LATCH,
90 TimeStamp::DESIRED,
91 TimeStamp::PRESENT,
92};
93
94static const TimeStamp NORMAL_SEQUENCE_2[] = {
95 TimeStamp::POST,
96 TimeStamp::ACQUIRE_FENCE,
97 TimeStamp::LATCH,
98 TimeStamp::DESIRED,
99 TimeStamp::PRESENT_FENCE,
100};
101
102static const TimeStamp UNORDERED_SEQUENCE[] = {
103 TimeStamp::ACQUIRE,
104 TimeStamp::LATCH,
105 TimeStamp::POST,
106 TimeStamp::DESIRED,
107 TimeStamp::PRESENT,
108};
109
110static const TimeStamp INCOMPLETE_SEQUENCE[] = {
111 TimeStamp::POST,
112};
113// clang-format on
114
115class TimeStatsTest : public testing::Test {
116public:
117 TimeStatsTest() {
118 const ::testing::TestInfo* const test_info =
119 ::testing::UnitTest::GetInstance()->current_test_info();
120 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
121 }
122
123 ~TimeStatsTest() {
124 const ::testing::TestInfo* const test_info =
125 ::testing::UnitTest::GetInstance()->current_test_info();
126 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
127 }
128
129 std::string inputCommand(InputCommand cmd, bool useProto);
130
131 void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
132
133 int32_t genRandomInt32(int32_t begin, int32_t end);
134
135 template <size_t N>
136 void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber,
137 nsecs_t ts) {
138 for (size_t i = 0; i < N; i++, ts += 1000000) {
139 setTimeStamp(sequence[i], id, frameNumber, ts);
140 }
141 }
142
143 std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000144
145 class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
146 public:
147 FakeStatsEventDelegate() = default;
148 ~FakeStatsEventDelegate() override = default;
149
150 struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
151 return mEvent;
152 }
153 void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
154 pull_atom_metadata*, void* cookie) override {
Alec Mouri37384342020-01-02 17:23:37 -0800155 mAtomTags.push_back(atom_tag);
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000156 mCallback = callback;
157 mCookie = cookie;
158 }
159
160 status_pull_atom_return_t makePullAtomCallback(int32_t atom_tag, void* cookie) {
161 return (*mCallback)(atom_tag, nullptr, cookie);
162 }
163
164 MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t));
165 MOCK_METHOD2(statsEventSetAtomId, void(struct stats_event*, uint32_t));
166 MOCK_METHOD2(statsEventWriteInt64, void(struct stats_event*, int64_t));
Alec Mouri37384342020-01-02 17:23:37 -0800167 MOCK_METHOD2(statsEventWriteString8, void(struct stats_event*, const char*));
168 MOCK_METHOD3(statsEventWriteByteArray, void(struct stats_event*, const uint8_t*, size_t));
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000169 MOCK_METHOD1(statsEventBuild, void(struct stats_event*));
170
171 struct stats_event* mEvent = stats_event_obtain();
Alec Mouri37384342020-01-02 17:23:37 -0800172 std::vector<int32_t> mAtomTags;
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000173 stats_pull_atom_callback_t mCallback = nullptr;
174 void* mCookie = nullptr;
175 };
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000176 FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
177 std::unique_ptr<TimeStats> mTimeStats =
Alec Mouri37384342020-01-02 17:23:37 -0800178 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
179 std::nullopt, std::nullopt);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800180};
181
182std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
Yiwei Zhang5434a782018-12-05 18:06:32 -0800183 std::string result;
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800184 Vector<String16> args;
185
186 switch (cmd) {
187 case InputCommand::ENABLE:
188 args.push_back(String16("-enable"));
189 break;
190 case InputCommand::DISABLE:
191 args.push_back(String16("-disable"));
192 break;
193 case InputCommand::CLEAR:
194 args.push_back(String16("-clear"));
195 break;
196 case InputCommand::DUMP_ALL:
197 args.push_back(String16("-dump"));
198 break;
199 case InputCommand::DUMP_MAXLAYERS_1:
200 args.push_back(String16("-dump"));
201 args.push_back(String16("-maxlayers"));
202 args.push_back(String16(std::to_string(NUM_LAYERS).c_str()));
203 break;
204 case InputCommand::DUMP_MAXLAYERS_INVALID:
205 args.push_back(String16("-dump"));
206 args.push_back(String16("-maxlayers"));
207 args.push_back(String16(NUM_LAYERS_INVALID));
208 break;
209 default:
210 ALOGD("Invalid control command");
211 }
212
Dominik Laskowskic2867142019-01-21 11:33:38 -0800213 EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, result));
Yiwei Zhang5434a782018-12-05 18:06:32 -0800214 return result;
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800215}
216
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800217static std::string genLayerName(int32_t layerId) {
218 return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.dummy#") + std::to_string(layerId);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800219}
220
221void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
222 switch (type) {
223 case TimeStamp::POST:
224 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), ts));
225 break;
226 case TimeStamp::ACQUIRE:
227 ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts));
228 break;
229 case TimeStamp::ACQUIRE_FENCE:
230 ASSERT_NO_FATAL_FAILURE(
231 mTimeStats->setAcquireFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
232 break;
233 case TimeStamp::LATCH:
234 ASSERT_NO_FATAL_FAILURE(mTimeStats->setLatchTime(id, frameNumber, ts));
235 break;
236 case TimeStamp::DESIRED:
237 ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
238 break;
239 case TimeStamp::PRESENT:
240 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
241 break;
242 case TimeStamp::PRESENT_FENCE:
243 ASSERT_NO_FATAL_FAILURE(
244 mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
245 break;
246 default:
247 ALOGD("Invalid timestamp type");
248 }
249}
250
251int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) {
252 std::uniform_int_distribution<int32_t> distr(begin, end);
253 return distr(mRandomEngine);
254}
255
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000256TEST_F(TimeStatsTest, disabledByDefault) {
257 ASSERT_FALSE(mTimeStats->isEnabled());
258}
259
260TEST_F(TimeStatsTest, enabledAfterBoot) {
261 mTimeStats->onBootFinished();
Alec Mourib3885ad2019-09-06 17:08:55 -0700262 ASSERT_TRUE(mTimeStats->isEnabled());
263}
264
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800265TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
266 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
267 ASSERT_TRUE(mTimeStats->isEnabled());
Alec Mouri37384342020-01-02 17:23:37 -0800268 EXPECT_THAT(mDelegate->mAtomTags,
269 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
270 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800271
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000272 EXPECT_CALL(*mDelegate,
273 unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
Alec Mouri37384342020-01-02 17:23:37 -0800274 EXPECT_CALL(*mDelegate,
275 unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800276 EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
277 ASSERT_FALSE(mTimeStats->isEnabled());
278}
279
280TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
281 constexpr size_t TOTAL_FRAMES = 5;
282 constexpr size_t MISSED_FRAMES = 4;
283 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
284
285 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
286
287 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
288 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
289 }
290 for (size_t i = 0; i < MISSED_FRAMES; i++) {
291 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
292 }
293 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
294 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
295 }
296
297 SFTimeStatsGlobalProto globalProto;
298 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
299
300 ASSERT_TRUE(globalProto.has_total_frames());
301 EXPECT_EQ(TOTAL_FRAMES, globalProto.total_frames());
302 ASSERT_TRUE(globalProto.has_missed_frames());
303 EXPECT_EQ(MISSED_FRAMES, globalProto.missed_frames());
304 ASSERT_TRUE(globalProto.has_client_composition_frames());
305 EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
306}
307
308TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
309 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
310
311 ASSERT_NO_FATAL_FAILURE(
312 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
313 ASSERT_NO_FATAL_FAILURE(
314 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
315
316 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
317 ASSERT_NO_FATAL_FAILURE(
318 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
319 ASSERT_NO_FATAL_FAILURE(
320 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
321
322 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
323 ASSERT_NO_FATAL_FAILURE(
324 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
325 ASSERT_NO_FATAL_FAILURE(
326 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(8000000)));
327
328 SFTimeStatsGlobalProto globalProto;
329 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
330
331 ASSERT_EQ(1, globalProto.present_to_present_size());
332 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.present_to_present().Get(0);
333 EXPECT_EQ(1, histogramProto.frame_count());
334 EXPECT_EQ(2, histogramProto.time_millis());
335}
336
Alec Mouri9519bf12019-11-15 16:54:44 -0800337TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
338 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
339
340 using namespace std::chrono_literals;
341
342 mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
343 mTimeStats
344 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
345 std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
346 .count());
347 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
348 mTimeStats
349 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
350 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
351 .count());
352
353 SFTimeStatsGlobalProto globalProto;
354 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
355
356 ASSERT_EQ(1, globalProto.frame_duration_size());
357 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
358 EXPECT_EQ(1, histogramProto.frame_count());
359 EXPECT_EQ(3, histogramProto.time_millis());
360}
361
Alec Mourie4034bb2019-11-19 12:45:54 -0800362TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
363 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
364
365 using namespace std::chrono_literals;
366
367 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
368 .count(),
369 std::make_shared<FenceTime>(
370 std::chrono::duration_cast<
371 std::chrono::nanoseconds>(3ms)
372 .count()));
373
374 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
375 .count(),
376 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
377 .count());
378
379 // First verify that flushing RenderEngine durations did not occur yet.
380 SFTimeStatsGlobalProto preFlushProto;
381 ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
382 ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
383
384 // Push a dummy present fence to trigger flushing the RenderEngine timings.
385 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
386 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
387 std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
388
389 // Now we can verify that RenderEngine durations were flushed now.
390 SFTimeStatsGlobalProto postFlushProto;
391 ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
392
393 ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
394 const SFTimeStatsHistogramBucketProto& histogramProto =
395 postFlushProto.render_engine_timing().Get(0);
396 EXPECT_EQ(2, histogramProto.frame_count());
397 EXPECT_EQ(2, histogramProto.time_millis());
398}
399
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800400TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
401 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
402
403 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
404 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
405
406 SFTimeStatsGlobalProto globalProto;
407 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
408
409 ASSERT_EQ(1, globalProto.stats_size());
410 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
411 ASSERT_TRUE(layerProto.has_layer_name());
412 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
413 ASSERT_TRUE(layerProto.has_total_frames());
414 EXPECT_EQ(1, layerProto.total_frames());
415 ASSERT_EQ(6, layerProto.deltas_size());
416 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
417 ASSERT_EQ(1, deltaProto.histograms_size());
418 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
419 EXPECT_EQ(1, histogramProto.frame_count());
420 if ("post2acquire" == deltaProto.delta_name()) {
421 EXPECT_EQ(1, histogramProto.time_millis());
422 } else if ("post2present" == deltaProto.delta_name()) {
423 EXPECT_EQ(4, histogramProto.time_millis());
424 } else if ("acquire2present" == deltaProto.delta_name()) {
425 EXPECT_EQ(3, histogramProto.time_millis());
426 } else if ("latch2present" == deltaProto.delta_name()) {
427 EXPECT_EQ(2, histogramProto.time_millis());
428 } else if ("desired2present" == deltaProto.delta_name()) {
429 EXPECT_EQ(1, histogramProto.time_millis());
430 } else if ("present2present" == deltaProto.delta_name()) {
431 EXPECT_EQ(1, histogramProto.time_millis());
432 } else {
433 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
434 }
435 }
436}
437
438TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
439 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
440
441 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
442 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
443
444 SFTimeStatsGlobalProto globalProto;
445 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
446
447 ASSERT_EQ(0, globalProto.stats_size());
448}
449
450TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
451 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
452
453 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
454 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
455 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
456 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
457
458 SFTimeStatsGlobalProto globalProto;
459 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
460
461 EXPECT_EQ(2, globalProto.stats_size());
462}
463
464TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
465 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
466
467 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
468 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
469
470 SFTimeStatsGlobalProto globalProto;
471 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
472
473 ASSERT_EQ(1, globalProto.stats_size());
474 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
475 ASSERT_TRUE(layerProto.has_layer_name());
476 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
477 ASSERT_TRUE(layerProto.has_total_frames());
478 EXPECT_EQ(1, layerProto.total_frames());
479 ASSERT_EQ(6, layerProto.deltas_size());
480 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
481 ASSERT_EQ(1, deltaProto.histograms_size());
482 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
483 EXPECT_EQ(1, histogramProto.frame_count());
484 if ("post2acquire" == deltaProto.delta_name()) {
485 EXPECT_EQ(0, histogramProto.time_millis());
486 } else if ("post2present" == deltaProto.delta_name()) {
487 EXPECT_EQ(2, histogramProto.time_millis());
488 } else if ("acquire2present" == deltaProto.delta_name()) {
489 EXPECT_EQ(2, histogramProto.time_millis());
490 } else if ("latch2present" == deltaProto.delta_name()) {
491 EXPECT_EQ(2, histogramProto.time_millis());
492 } else if ("desired2present" == deltaProto.delta_name()) {
493 EXPECT_EQ(1, histogramProto.time_millis());
494 } else if ("present2present" == deltaProto.delta_name()) {
495 EXPECT_EQ(1, histogramProto.time_millis());
496 } else {
497 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
498 }
499 }
500}
501
Alec Mourifb571ea2019-01-24 18:42:10 -0800502TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
503 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
504
505 uint32_t fpsOne = 30;
506 uint32_t fpsTwo = 90;
507 uint64_t millisOne = 5000;
508 uint64_t millisTwo = 7000;
509
510 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
511 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
512
513 SFTimeStatsGlobalProto globalProto;
514 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
515
516 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
517 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
518 expectedConfigOne->set_fps(fpsOne);
519 expectedBucketOne.set_duration_millis(millisOne);
520
521 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
522 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
523 expectedConfigTwo->set_fps(fpsTwo);
524 expectedBucketTwo.set_duration_millis(millisTwo);
525
526 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
527
528 std::unordered_set<uint32_t> seen_fps;
529 for (const auto& bucket : globalProto.display_config_stats()) {
530 seen_fps.emplace(bucket.config().fps());
531 if (fpsOne == bucket.config().fps()) {
532 EXPECT_EQ(millisOne, bucket.duration_millis());
533 } else if (fpsTwo == bucket.config().fps()) {
534 EXPECT_EQ(millisTwo, bucket.duration_millis());
535 } else {
536 FAIL() << "Unknown fps: " << bucket.config().fps();
537 }
538 }
539 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
540}
541
542TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
543 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
544
545 uint32_t fps = 30;
546 uint64_t millisOne = 5000;
547 uint64_t millisTwo = 7000;
548
549 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
550 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
551
552 SFTimeStatsGlobalProto globalProto;
553 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
554 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
555 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
556 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
557}
558
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800559TEST_F(TimeStatsTest, canRemoveTimeRecord) {
560 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
561
562 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
563 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
564 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
565 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
566
567 SFTimeStatsGlobalProto globalProto;
568 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
569
570 ASSERT_EQ(1, globalProto.stats_size());
571 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
572 ASSERT_TRUE(layerProto.has_total_frames());
573 EXPECT_EQ(1, layerProto.total_frames());
574}
575
576TEST_F(TimeStatsTest, canRecoverFromIncompleteTimeRecordError) {
577 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
578
579 uint64_t frameNumber = 1;
580 nsecs_t ts = 1000000;
581 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
Alec Mourifb571ea2019-01-24 18:42:10 -0800582 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800583 frameNumber++;
584 ts += 1000000;
585 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
586 }
587
588 SFTimeStatsGlobalProto globalProto;
589 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
590
591 ASSERT_EQ(1, globalProto.stats_size());
592 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
593 ASSERT_TRUE(layerProto.has_total_frames());
594 EXPECT_EQ(1, layerProto.total_frames());
595}
596
597TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
598 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
599
600 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
601 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
602 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
603 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
604
605 SFTimeStatsGlobalProto globalProto;
606 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
607
608 ASSERT_EQ(1, globalProto.stats_size());
609 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
610 ASSERT_TRUE(layerProto.has_total_frames());
611 EXPECT_EQ(1, layerProto.total_frames());
612}
613
614TEST_F(TimeStatsTest, canClearTimeStats) {
615 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
616
617 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
618 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
619 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
620 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
Alec Mouri31ac64a2020-01-09 09:26:22 -0800621
622 using namespace std::chrono_literals;
623 mTimeStats
624 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
625 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
626 .count());
627 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
628 .count(),
629 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
630 .count());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800631 ASSERT_NO_FATAL_FAILURE(
632 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
633 ASSERT_NO_FATAL_FAILURE(
634 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
635 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
636 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
637
638 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
639
640 SFTimeStatsGlobalProto globalProto;
641 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
642
643 EXPECT_EQ(0, globalProto.total_frames());
644 EXPECT_EQ(0, globalProto.missed_frames());
645 EXPECT_EQ(0, globalProto.client_composition_frames());
646 EXPECT_EQ(0, globalProto.present_to_present_size());
Alec Mouri31ac64a2020-01-09 09:26:22 -0800647 EXPECT_EQ(0, globalProto.frame_duration_size());
648 EXPECT_EQ(0, globalProto.render_engine_timing_size());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800649 EXPECT_EQ(0, globalProto.stats_size());
650}
651
652TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
653 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
654
655 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
656 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
657 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
658 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
659 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
660
661 SFTimeStatsGlobalProto globalProto;
662 ASSERT_TRUE(
663 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
664
665 ASSERT_EQ(1, globalProto.stats_size());
666 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
667 ASSERT_TRUE(layerProto.has_layer_name());
668 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
669 ASSERT_TRUE(layerProto.has_total_frames());
670 EXPECT_EQ(2, layerProto.total_frames());
671}
672
673TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
674 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
675
676 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
677 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
678
679 SFTimeStatsGlobalProto globalProto;
680 ASSERT_TRUE(globalProto.ParseFromString(
681 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
682
683 ASSERT_EQ(0, globalProto.stats_size());
684}
685
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000686TEST_F(TimeStatsTest, globalStatsCallback) {
687 constexpr size_t TOTAL_FRAMES = 5;
688 constexpr size_t MISSED_FRAMES = 4;
689 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
690
691 mTimeStats->onBootFinished();
692 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
693
694 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
695 mTimeStats->incrementTotalFrames();
696 }
697 for (size_t i = 0; i < MISSED_FRAMES; i++) {
698 mTimeStats->incrementMissedFrames();
699 }
700 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
701 mTimeStats->incrementClientCompositionFrames();
702 }
703
704 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
705 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
706 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
707
Alec Mouri37384342020-01-02 17:23:37 -0800708 EXPECT_THAT(mDelegate->mAtomTags,
709 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
710 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000711 EXPECT_NE(nullptr, mDelegate->mCallback);
712 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
713
714 {
715 InSequence seq;
716 EXPECT_CALL(*mDelegate,
717 statsEventSetAtomId(mDelegate->mEvent,
718 android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
719 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
720 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
721 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
722 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
723 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
724 EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
725 }
726 EXPECT_EQ(STATS_PULL_SUCCESS,
Alec Mouri37384342020-01-02 17:23:37 -0800727 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
728 mDelegate->mCookie));
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000729
730 SFTimeStatsGlobalProto globalProto;
731 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
732
733 EXPECT_EQ(0, globalProto.total_frames());
734 EXPECT_EQ(0, globalProto.missed_frames());
735 EXPECT_EQ(0, globalProto.client_composition_frames());
736 EXPECT_EQ(0, globalProto.present_to_present_size());
737}
738
Alec Mouri37384342020-01-02 17:23:37 -0800739namespace {
740std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
741 const std::vector<int32_t>& frameCounts) {
742 util::ProtoOutputStream proto;
743 for (int i = 0; i < times.size(); i++) {
744 ALOGE("Writing time: %d", times[i]);
745 proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
746 (int32_t)times[i]);
747 ALOGE("Writing count: %d", frameCounts[i]);
748 proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
749 (int64_t)frameCounts[i]);
750 }
751 std::string byteString;
752 proto.serializeToString(&byteString);
753 return byteString;
754}
755
756std::string dumpByteStringHex(const std::string& str) {
757 std::stringstream ss;
758 ss << std::hex;
759 for (const char& c : str) {
760 ss << (int)c << " ";
761 }
762
763 return ss.str();
764}
765
766} // namespace
767
768MATCHER_P2(BytesEq, bytes, size, "") {
769 std::string expected;
770 expected.append((const char*)bytes, size);
771 std::string actual;
772 actual.append((const char*)arg, size);
773
774 *result_listener << "Bytes are not equal! \n";
775 *result_listener << "size: " << size << "\n";
776 *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
777 *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
778
779 return expected == actual;
780}
781
782TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) {
783 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
784
785 mTimeStats->onBootFinished();
786
787 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
788 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
789
790 EXPECT_THAT(mDelegate->mAtomTags,
791 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
792 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
793 EXPECT_NE(nullptr, mDelegate->mCallback);
794 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
795
796 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
797 std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
798 std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
799 std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
800 std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
801 std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
802 {
803 InSequence seq;
804 EXPECT_CALL(*mDelegate,
805 statsEventSetAtomId(mDelegate->mEvent,
806 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
807 EXPECT_CALL(*mDelegate,
808 statsEventWriteString8(mDelegate->mEvent,
809 StrEq(genLayerName(LAYER_ID_0).c_str())));
810 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
811 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
812 EXPECT_CALL(*mDelegate,
813 statsEventWriteByteArray(mDelegate->mEvent,
814 BytesEq((const uint8_t*)
815 expectedPresentToPresent.c_str(),
816 expectedPresentToPresent.size()),
817 expectedPresentToPresent.size()));
818 EXPECT_CALL(*mDelegate,
819 statsEventWriteByteArray(mDelegate->mEvent,
820 BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
821 expectedPostToPresent.size()),
822 expectedPostToPresent.size()));
823 EXPECT_CALL(*mDelegate,
824 statsEventWriteByteArray(mDelegate->mEvent,
825 BytesEq((const uint8_t*)
826 expectedAcquireToPresent.c_str(),
827 expectedAcquireToPresent.size()),
828 expectedAcquireToPresent.size()));
829 EXPECT_CALL(*mDelegate,
830 statsEventWriteByteArray(mDelegate->mEvent,
831 BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
832 expectedLatchToPresent.size()),
833 expectedLatchToPresent.size()));
834 EXPECT_CALL(*mDelegate,
835 statsEventWriteByteArray(mDelegate->mEvent,
836 BytesEq((const uint8_t*)
837 expectedDesiredToPresent.c_str(),
838 expectedDesiredToPresent.size()),
839 expectedDesiredToPresent.size()));
840 EXPECT_CALL(*mDelegate,
841 statsEventWriteByteArray(mDelegate->mEvent,
842 BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
843 expectedPostToAcquire.size()),
844 expectedPostToAcquire.size()));
845 EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
846 }
847 EXPECT_EQ(STATS_PULL_SUCCESS,
848 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
849 mDelegate->mCookie));
850
851 SFTimeStatsGlobalProto globalProto;
852 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
853
854 EXPECT_EQ(0, globalProto.stats_size());
855}
856
857TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
858 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
859
860 mTimeStats->onBootFinished();
861
862 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
863 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
864 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
865 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
866
867 EXPECT_THAT(mDelegate->mAtomTags,
868 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
869 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
870 EXPECT_NE(nullptr, mDelegate->mCallback);
871 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
872
873 EXPECT_CALL(*mDelegate,
874 statsEventSetAtomId(mDelegate->mEvent,
875 android::util::SURFACEFLINGER_STATS_LAYER_INFO))
876 .Times(2);
877 EXPECT_CALL(*mDelegate,
878 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
879 EXPECT_CALL(*mDelegate,
880 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
881 EXPECT_EQ(STATS_PULL_SUCCESS,
882 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
883 mDelegate->mCookie));
884}
885
886TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
887 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
888
889 mTimeStats->onBootFinished();
890
891 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
892 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
893 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
894 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
895
896 // Now make sure that TimeStats flushes global stats to register the
897 // callback.
898 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
899 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
900 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
901 EXPECT_THAT(mDelegate->mAtomTags,
902 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
903 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
904 EXPECT_NE(nullptr, mDelegate->mCallback);
905 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
906
907 EXPECT_THAT(mDelegate->mAtomTags,
908 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
909 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
910 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
911 {
912 InSequence seq;
913 EXPECT_CALL(*mDelegate,
914 statsEventWriteByteArray(mDelegate->mEvent,
915 BytesEq((const uint8_t*)
916 expectedPresentToPresent.c_str(),
917 expectedPresentToPresent.size()),
918 expectedPresentToPresent.size()));
919 EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
920 .Times(AnyNumber());
921 }
922 EXPECT_EQ(STATS_PULL_SUCCESS,
923 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
924 mDelegate->mCookie));
925}
926
927TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
928 mDelegate = new FakeStatsEventDelegate;
929 mTimeStats =
930 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
931 std::nullopt, 1);
932 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
933
934 mTimeStats->onBootFinished();
935
936 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
937 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
938 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
939 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
940
941 EXPECT_THAT(mDelegate->mAtomTags,
942 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
943 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
944 EXPECT_NE(nullptr, mDelegate->mCallback);
945 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
946
947 EXPECT_THAT(mDelegate->mAtomTags,
948 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
949 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
950 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
951 {
952 InSequence seq;
953 EXPECT_CALL(*mDelegate,
954 statsEventWriteByteArray(mDelegate->mEvent,
955 BytesEq((const uint8_t*)
956 expectedPresentToPresent.c_str(),
957 expectedPresentToPresent.size()),
958 expectedPresentToPresent.size()));
959 EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
960 .Times(AnyNumber());
961 }
962 EXPECT_EQ(STATS_PULL_SUCCESS,
963 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
964 mDelegate->mCookie));
965}
966
967TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
968 mDelegate = new FakeStatsEventDelegate;
969 mTimeStats =
970 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
971 std::nullopt);
972 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
973
974 mTimeStats->onBootFinished();
975
976 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
977 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
978 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
979 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
980 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
981
982 EXPECT_THAT(mDelegate->mAtomTags,
983 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
984 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
985 EXPECT_NE(nullptr, mDelegate->mCallback);
986 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
987
988 EXPECT_CALL(*mDelegate,
989 statsEventSetAtomId(mDelegate->mEvent,
990 android::util::SURFACEFLINGER_STATS_LAYER_INFO))
991 .Times(1);
992 EXPECT_CALL(*mDelegate,
993 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
994 EXPECT_EQ(STATS_PULL_SUCCESS,
995 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
996 mDelegate->mCookie));
997}
998
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800999TEST_F(TimeStatsTest, canSurviveMonkey) {
Lloyd Pique067fe1e2018-12-06 19:44:13 -08001000 if (g_noSlowTests) {
1001 GTEST_SKIP();
1002 }
1003
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001004 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1005
1006 for (size_t i = 0; i < 10000000; ++i) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001007 const int32_t layerId = genRandomInt32(-1, 10);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001008 const int32_t frameNumber = genRandomInt32(1, 10);
1009 switch (genRandomInt32(0, 100)) {
1010 case 0:
1011 ALOGV("removeTimeRecord");
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001012 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001013 continue;
1014 case 1:
1015 ALOGV("onDestroy");
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001016 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001017 continue;
1018 }
1019 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
1020 const int32_t ts = genRandomInt32(1, 1000000000);
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001021 ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
1022 setTimeStamp(type, layerId, frameNumber, ts);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001023 }
1024}
1025
1026} // namespace
1027} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -08001028
1029// TODO(b/129481165): remove the #pragma below and fix conversion issues
1030#pragma clang diagnostic pop // ignored "-Wconversion"