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