blob: f65af77748b59882fdd4327330b4c18ac883f57e [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
Alec Mouri3ecd5cd2020-01-29 12:53:07 -0800261TEST_F(TimeStatsTest, registersCallbacksAfterBoot) {
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000262 mTimeStats->onBootFinished();
Alec Mouri3ecd5cd2020-01-29 12:53:07 -0800263 EXPECT_THAT(mDelegate->mAtomTags,
264 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
265 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
266}
267
268TEST_F(TimeStatsTest, unregistersCallbacksOnDestruction) {
269 EXPECT_CALL(*mDelegate,
270 unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
271 EXPECT_CALL(*mDelegate,
272 unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
273 mTimeStats.reset();
Alec Mourib3885ad2019-09-06 17:08:55 -0700274}
275
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800276TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
277 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
278 ASSERT_TRUE(mTimeStats->isEnabled());
279
280 EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
281 ASSERT_FALSE(mTimeStats->isEnabled());
282}
283
284TEST_F(TimeStatsTest, canIncreaseGlobalStats) {
285 constexpr size_t TOTAL_FRAMES = 5;
286 constexpr size_t MISSED_FRAMES = 4;
287 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
288
289 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
290
291 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
292 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
293 }
294 for (size_t i = 0; i < MISSED_FRAMES; i++) {
295 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
296 }
297 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
298 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
299 }
300
301 SFTimeStatsGlobalProto globalProto;
302 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
303
304 ASSERT_TRUE(globalProto.has_total_frames());
305 EXPECT_EQ(TOTAL_FRAMES, globalProto.total_frames());
306 ASSERT_TRUE(globalProto.has_missed_frames());
307 EXPECT_EQ(MISSED_FRAMES, globalProto.missed_frames());
308 ASSERT_TRUE(globalProto.has_client_composition_frames());
309 EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
310}
311
Vishnu Nair9b079a22020-01-21 14:36:08 -0800312TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
313 // this stat is not in the proto so verify by checking the string dump
314 constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
315
316 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
317 for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
318 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
319 }
320
321 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
322 const std::string expectedResult =
323 "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
324 EXPECT_THAT(result, HasSubstr(expectedResult));
325}
326
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800327TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
328 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
329
330 ASSERT_NO_FATAL_FAILURE(
331 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
332 ASSERT_NO_FATAL_FAILURE(
333 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
334
335 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
336 ASSERT_NO_FATAL_FAILURE(
337 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
338 ASSERT_NO_FATAL_FAILURE(
339 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
340
341 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
342 ASSERT_NO_FATAL_FAILURE(
343 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
344 ASSERT_NO_FATAL_FAILURE(
345 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(8000000)));
346
347 SFTimeStatsGlobalProto globalProto;
348 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
349
350 ASSERT_EQ(1, globalProto.present_to_present_size());
351 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.present_to_present().Get(0);
352 EXPECT_EQ(1, histogramProto.frame_count());
353 EXPECT_EQ(2, histogramProto.time_millis());
354}
355
Alec Mouri9519bf12019-11-15 16:54:44 -0800356TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
357 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
358
359 using namespace std::chrono_literals;
360
361 mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
362 mTimeStats
363 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
364 std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
365 .count());
366 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
367 mTimeStats
368 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
369 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
370 .count());
371
372 SFTimeStatsGlobalProto globalProto;
373 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
374
375 ASSERT_EQ(1, globalProto.frame_duration_size());
376 const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
377 EXPECT_EQ(1, histogramProto.frame_count());
378 EXPECT_EQ(3, histogramProto.time_millis());
379}
380
Alec Mourie4034bb2019-11-19 12:45:54 -0800381TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
382 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
383
384 using namespace std::chrono_literals;
385
386 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
387 .count(),
388 std::make_shared<FenceTime>(
389 std::chrono::duration_cast<
390 std::chrono::nanoseconds>(3ms)
391 .count()));
392
393 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
394 .count(),
395 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
396 .count());
397
398 // First verify that flushing RenderEngine durations did not occur yet.
399 SFTimeStatsGlobalProto preFlushProto;
400 ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
401 ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
402
403 // Push a dummy present fence to trigger flushing the RenderEngine timings.
404 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
405 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
406 std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
407
408 // Now we can verify that RenderEngine durations were flushed now.
409 SFTimeStatsGlobalProto postFlushProto;
410 ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
411
412 ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
413 const SFTimeStatsHistogramBucketProto& histogramProto =
414 postFlushProto.render_engine_timing().Get(0);
415 EXPECT_EQ(2, histogramProto.frame_count());
416 EXPECT_EQ(2, histogramProto.time_millis());
417}
418
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800419TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
420 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
421
422 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
423 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
424
425 SFTimeStatsGlobalProto globalProto;
426 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
427
428 ASSERT_EQ(1, globalProto.stats_size());
429 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
430 ASSERT_TRUE(layerProto.has_layer_name());
431 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
432 ASSERT_TRUE(layerProto.has_total_frames());
433 EXPECT_EQ(1, layerProto.total_frames());
434 ASSERT_EQ(6, layerProto.deltas_size());
435 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
436 ASSERT_EQ(1, deltaProto.histograms_size());
437 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
438 EXPECT_EQ(1, histogramProto.frame_count());
439 if ("post2acquire" == deltaProto.delta_name()) {
440 EXPECT_EQ(1, histogramProto.time_millis());
441 } else if ("post2present" == deltaProto.delta_name()) {
442 EXPECT_EQ(4, histogramProto.time_millis());
443 } else if ("acquire2present" == deltaProto.delta_name()) {
444 EXPECT_EQ(3, histogramProto.time_millis());
445 } else if ("latch2present" == deltaProto.delta_name()) {
446 EXPECT_EQ(2, histogramProto.time_millis());
447 } else if ("desired2present" == deltaProto.delta_name()) {
448 EXPECT_EQ(1, histogramProto.time_millis());
449 } else if ("present2present" == deltaProto.delta_name()) {
450 EXPECT_EQ(1, histogramProto.time_millis());
451 } else {
452 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
453 }
454 }
455}
456
457TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
458 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
459
460 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_INVALID, 1, 1000000);
461 insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_INVALID, 2, 2000000);
462
463 SFTimeStatsGlobalProto globalProto;
464 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
465
466 ASSERT_EQ(0, globalProto.stats_size());
467}
468
469TEST_F(TimeStatsTest, canInsertMultipleLayersTimeStats) {
470 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
471
472 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
473 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
474 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
475 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
476
477 SFTimeStatsGlobalProto globalProto;
478 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
479
480 EXPECT_EQ(2, globalProto.stats_size());
481}
482
483TEST_F(TimeStatsTest, canInsertUnorderedLayerTimeStats) {
484 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
485
486 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
487 insertTimeRecord(UNORDERED_SEQUENCE, LAYER_ID_0, 2, 2000000);
488
489 SFTimeStatsGlobalProto globalProto;
490 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
491
492 ASSERT_EQ(1, globalProto.stats_size());
493 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
494 ASSERT_TRUE(layerProto.has_layer_name());
495 EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
496 ASSERT_TRUE(layerProto.has_total_frames());
497 EXPECT_EQ(1, layerProto.total_frames());
498 ASSERT_EQ(6, layerProto.deltas_size());
499 for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
500 ASSERT_EQ(1, deltaProto.histograms_size());
501 const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
502 EXPECT_EQ(1, histogramProto.frame_count());
503 if ("post2acquire" == deltaProto.delta_name()) {
504 EXPECT_EQ(0, histogramProto.time_millis());
505 } else if ("post2present" == deltaProto.delta_name()) {
506 EXPECT_EQ(2, histogramProto.time_millis());
507 } else if ("acquire2present" == deltaProto.delta_name()) {
508 EXPECT_EQ(2, histogramProto.time_millis());
509 } else if ("latch2present" == deltaProto.delta_name()) {
510 EXPECT_EQ(2, histogramProto.time_millis());
511 } else if ("desired2present" == deltaProto.delta_name()) {
512 EXPECT_EQ(1, histogramProto.time_millis());
513 } else if ("present2present" == deltaProto.delta_name()) {
514 EXPECT_EQ(1, histogramProto.time_millis());
515 } else {
516 FAIL() << "Unknown delta_name: " << deltaProto.delta_name();
517 }
518 }
519}
520
Alec Mourifb571ea2019-01-24 18:42:10 -0800521TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
522 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
523
524 uint32_t fpsOne = 30;
525 uint32_t fpsTwo = 90;
526 uint64_t millisOne = 5000;
527 uint64_t millisTwo = 7000;
528
529 mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
530 mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
531
532 SFTimeStatsGlobalProto globalProto;
533 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
534
535 SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
536 SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
537 expectedConfigOne->set_fps(fpsOne);
538 expectedBucketOne.set_duration_millis(millisOne);
539
540 SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
541 SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
542 expectedConfigTwo->set_fps(fpsTwo);
543 expectedBucketTwo.set_duration_millis(millisTwo);
544
545 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
546
547 std::unordered_set<uint32_t> seen_fps;
548 for (const auto& bucket : globalProto.display_config_stats()) {
549 seen_fps.emplace(bucket.config().fps());
550 if (fpsOne == bucket.config().fps()) {
551 EXPECT_EQ(millisOne, bucket.duration_millis());
552 } else if (fpsTwo == bucket.config().fps()) {
553 EXPECT_EQ(millisTwo, bucket.duration_millis());
554 } else {
555 FAIL() << "Unknown fps: " << bucket.config().fps();
556 }
557 }
558 EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
559}
560
561TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
562 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
563
564 uint32_t fps = 30;
565 uint64_t millisOne = 5000;
566 uint64_t millisTwo = 7000;
567
568 mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
569 mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
570
571 SFTimeStatsGlobalProto globalProto;
572 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
573 EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
574 EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
575 EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
576}
577
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800578TEST_F(TimeStatsTest, canRemoveTimeRecord) {
579 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
580
581 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
582 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 2, 2000000);
583 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(0, 2));
584 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
585
586 SFTimeStatsGlobalProto globalProto;
587 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
588
589 ASSERT_EQ(1, globalProto.stats_size());
590 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
591 ASSERT_TRUE(layerProto.has_total_frames());
592 EXPECT_EQ(1, layerProto.total_frames());
593}
594
595TEST_F(TimeStatsTest, canRecoverFromIncompleteTimeRecordError) {
596 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
597
598 uint64_t frameNumber = 1;
599 nsecs_t ts = 1000000;
600 insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
Alec Mourifb571ea2019-01-24 18:42:10 -0800601 for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800602 frameNumber++;
603 ts += 1000000;
604 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
605 }
606
607 SFTimeStatsGlobalProto globalProto;
608 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
609
610 ASSERT_EQ(1, globalProto.stats_size());
611 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
612 ASSERT_TRUE(layerProto.has_total_frames());
613 EXPECT_EQ(1, layerProto.total_frames());
614}
615
616TEST_F(TimeStatsTest, layerTimeStatsOnDestroy) {
617 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
618
619 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
620 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
621 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(0));
622 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000);
623
624 SFTimeStatsGlobalProto globalProto;
625 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
626
627 ASSERT_EQ(1, globalProto.stats_size());
628 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
629 ASSERT_TRUE(layerProto.has_total_frames());
630 EXPECT_EQ(1, layerProto.total_frames());
631}
632
633TEST_F(TimeStatsTest, canClearTimeStats) {
634 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
635
636 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
637 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
638 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
639 ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
Alec Mouri31ac64a2020-01-09 09:26:22 -0800640
641 using namespace std::chrono_literals;
642 mTimeStats
643 ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
644 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
645 .count());
646 mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
647 .count(),
648 std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
649 .count());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800650 ASSERT_NO_FATAL_FAILURE(
651 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
652 ASSERT_NO_FATAL_FAILURE(
653 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
654 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
655 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
656
657 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
658
659 SFTimeStatsGlobalProto globalProto;
660 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
661
662 EXPECT_EQ(0, globalProto.total_frames());
663 EXPECT_EQ(0, globalProto.missed_frames());
664 EXPECT_EQ(0, globalProto.client_composition_frames());
665 EXPECT_EQ(0, globalProto.present_to_present_size());
Alec Mouri31ac64a2020-01-09 09:26:22 -0800666 EXPECT_EQ(0, globalProto.frame_duration_size());
667 EXPECT_EQ(0, globalProto.render_engine_timing_size());
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800668 EXPECT_EQ(0, globalProto.stats_size());
669}
670
Vishnu Nair9b079a22020-01-21 14:36:08 -0800671TEST_F(TimeStatsTest, canClearClientCompositionSkippedFrames) {
672 // this stat is not in the proto so verify by checking the string dump
673 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
674 ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
675 EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
676
677 const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
678 EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
679}
680
Yiwei Zhang16faa5d2018-11-13 18:12:59 -0800681TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
682 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
683
684 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
685 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 1000000);
686 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
687 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 2000000);
688 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 3, 2000000);
689
690 SFTimeStatsGlobalProto globalProto;
691 ASSERT_TRUE(
692 globalProto.ParseFromString(inputCommand(InputCommand::DUMP_MAXLAYERS_1, FMT_PROTO)));
693
694 ASSERT_EQ(1, globalProto.stats_size());
695 const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
696 ASSERT_TRUE(layerProto.has_layer_name());
697 EXPECT_EQ(genLayerName(LAYER_ID_1), layerProto.layer_name());
698 ASSERT_TRUE(layerProto.has_total_frames());
699 EXPECT_EQ(2, layerProto.total_frames());
700}
701
702TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) {
703 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
704
705 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
706 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
707
708 SFTimeStatsGlobalProto globalProto;
709 ASSERT_TRUE(globalProto.ParseFromString(
710 inputCommand(InputCommand::DUMP_MAXLAYERS_INVALID, FMT_PROTO)));
711
712 ASSERT_EQ(0, globalProto.stats_size());
713}
714
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000715TEST_F(TimeStatsTest, globalStatsCallback) {
716 constexpr size_t TOTAL_FRAMES = 5;
717 constexpr size_t MISSED_FRAMES = 4;
718 constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
719
720 mTimeStats->onBootFinished();
721 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
722
723 for (size_t i = 0; i < TOTAL_FRAMES; i++) {
724 mTimeStats->incrementTotalFrames();
725 }
726 for (size_t i = 0; i < MISSED_FRAMES; i++) {
727 mTimeStats->incrementMissedFrames();
728 }
729 for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
730 mTimeStats->incrementClientCompositionFrames();
731 }
732
733 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
734 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
735 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
736
Alec Mouri37384342020-01-02 17:23:37 -0800737 EXPECT_THAT(mDelegate->mAtomTags,
738 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
739 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000740 EXPECT_NE(nullptr, mDelegate->mCallback);
741 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
742
743 {
744 InSequence seq;
745 EXPECT_CALL(*mDelegate,
746 statsEventSetAtomId(mDelegate->mEvent,
747 android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
748 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
749 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
750 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
751 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
752 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
753 EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
754 }
755 EXPECT_EQ(STATS_PULL_SUCCESS,
Alec Mouri37384342020-01-02 17:23:37 -0800756 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
757 mDelegate->mCookie));
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000758
759 SFTimeStatsGlobalProto globalProto;
760 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
761
762 EXPECT_EQ(0, globalProto.total_frames());
763 EXPECT_EQ(0, globalProto.missed_frames());
764 EXPECT_EQ(0, globalProto.client_composition_frames());
765 EXPECT_EQ(0, globalProto.present_to_present_size());
766}
767
Alec Mouri37384342020-01-02 17:23:37 -0800768namespace {
769std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
770 const std::vector<int32_t>& frameCounts) {
771 util::ProtoOutputStream proto;
772 for (int i = 0; i < times.size(); i++) {
773 ALOGE("Writing time: %d", times[i]);
774 proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
775 (int32_t)times[i]);
776 ALOGE("Writing count: %d", frameCounts[i]);
777 proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
778 (int64_t)frameCounts[i]);
779 }
780 std::string byteString;
781 proto.serializeToString(&byteString);
782 return byteString;
783}
784
785std::string dumpByteStringHex(const std::string& str) {
786 std::stringstream ss;
787 ss << std::hex;
788 for (const char& c : str) {
789 ss << (int)c << " ";
790 }
791
792 return ss.str();
793}
794
795} // namespace
796
797MATCHER_P2(BytesEq, bytes, size, "") {
798 std::string expected;
799 expected.append((const char*)bytes, size);
800 std::string actual;
801 actual.append((const char*)arg, size);
802
803 *result_listener << "Bytes are not equal! \n";
804 *result_listener << "size: " << size << "\n";
805 *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
806 *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
807
808 return expected == actual;
809}
810
811TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) {
812 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
813
814 mTimeStats->onBootFinished();
815
816 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
817 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
818
819 EXPECT_THAT(mDelegate->mAtomTags,
820 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
821 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
822 EXPECT_NE(nullptr, mDelegate->mCallback);
823 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
824
825 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
826 std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
827 std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
828 std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
829 std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
830 std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
831 {
832 InSequence seq;
833 EXPECT_CALL(*mDelegate,
834 statsEventSetAtomId(mDelegate->mEvent,
835 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
836 EXPECT_CALL(*mDelegate,
837 statsEventWriteString8(mDelegate->mEvent,
838 StrEq(genLayerName(LAYER_ID_0).c_str())));
839 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
840 EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
841 EXPECT_CALL(*mDelegate,
842 statsEventWriteByteArray(mDelegate->mEvent,
843 BytesEq((const uint8_t*)
844 expectedPresentToPresent.c_str(),
845 expectedPresentToPresent.size()),
846 expectedPresentToPresent.size()));
847 EXPECT_CALL(*mDelegate,
848 statsEventWriteByteArray(mDelegate->mEvent,
849 BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
850 expectedPostToPresent.size()),
851 expectedPostToPresent.size()));
852 EXPECT_CALL(*mDelegate,
853 statsEventWriteByteArray(mDelegate->mEvent,
854 BytesEq((const uint8_t*)
855 expectedAcquireToPresent.c_str(),
856 expectedAcquireToPresent.size()),
857 expectedAcquireToPresent.size()));
858 EXPECT_CALL(*mDelegate,
859 statsEventWriteByteArray(mDelegate->mEvent,
860 BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
861 expectedLatchToPresent.size()),
862 expectedLatchToPresent.size()));
863 EXPECT_CALL(*mDelegate,
864 statsEventWriteByteArray(mDelegate->mEvent,
865 BytesEq((const uint8_t*)
866 expectedDesiredToPresent.c_str(),
867 expectedDesiredToPresent.size()),
868 expectedDesiredToPresent.size()));
869 EXPECT_CALL(*mDelegate,
870 statsEventWriteByteArray(mDelegate->mEvent,
871 BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
872 expectedPostToAcquire.size()),
873 expectedPostToAcquire.size()));
874 EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
875 }
876 EXPECT_EQ(STATS_PULL_SUCCESS,
877 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
878 mDelegate->mCookie));
879
880 SFTimeStatsGlobalProto globalProto;
881 ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
882
883 EXPECT_EQ(0, globalProto.stats_size());
884}
885
886TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
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_1, 1, 2000000);
894 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
895
896 EXPECT_THAT(mDelegate->mAtomTags,
897 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
898 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
899 EXPECT_NE(nullptr, mDelegate->mCallback);
900 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
901
902 EXPECT_CALL(*mDelegate,
903 statsEventSetAtomId(mDelegate->mEvent,
904 android::util::SURFACEFLINGER_STATS_LAYER_INFO))
905 .Times(2);
906 EXPECT_CALL(*mDelegate,
907 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
908 EXPECT_CALL(*mDelegate,
909 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
910 EXPECT_EQ(STATS_PULL_SUCCESS,
911 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
912 mDelegate->mCookie));
913}
914
915TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
916 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
917
918 mTimeStats->onBootFinished();
919
920 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
921 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
922 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
923 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
924
925 // Now make sure that TimeStats flushes global stats to register the
926 // callback.
927 mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
928 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
929 mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
930 EXPECT_THAT(mDelegate->mAtomTags,
931 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
932 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
933 EXPECT_NE(nullptr, mDelegate->mCallback);
934 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
935
936 EXPECT_THAT(mDelegate->mAtomTags,
937 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
938 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
939 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
940 {
941 InSequence seq;
942 EXPECT_CALL(*mDelegate,
943 statsEventWriteByteArray(mDelegate->mEvent,
944 BytesEq((const uint8_t*)
945 expectedPresentToPresent.c_str(),
946 expectedPresentToPresent.size()),
947 expectedPresentToPresent.size()));
948 EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
949 .Times(AnyNumber());
950 }
951 EXPECT_EQ(STATS_PULL_SUCCESS,
952 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
953 mDelegate->mCookie));
954}
955
956TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
957 mDelegate = new FakeStatsEventDelegate;
958 mTimeStats =
959 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
960 std::nullopt, 1);
961 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
962
963 mTimeStats->onBootFinished();
964
965 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
966 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
967 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
968 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
969
970 EXPECT_THAT(mDelegate->mAtomTags,
971 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
972 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
973 EXPECT_NE(nullptr, mDelegate->mCallback);
974 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
975
976 EXPECT_THAT(mDelegate->mAtomTags,
977 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
978 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
979 std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
980 {
981 InSequence seq;
982 EXPECT_CALL(*mDelegate,
983 statsEventWriteByteArray(mDelegate->mEvent,
984 BytesEq((const uint8_t*)
985 expectedPresentToPresent.c_str(),
986 expectedPresentToPresent.size()),
987 expectedPresentToPresent.size()));
988 EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
989 .Times(AnyNumber());
990 }
991 EXPECT_EQ(STATS_PULL_SUCCESS,
992 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
993 mDelegate->mCookie));
994}
995
996TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
997 mDelegate = new FakeStatsEventDelegate;
998 mTimeStats =
999 std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
1000 std::nullopt);
1001 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1002
1003 mTimeStats->onBootFinished();
1004
1005 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
1006 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
1007 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
1008 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
1009 insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
1010
1011 EXPECT_THAT(mDelegate->mAtomTags,
1012 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
1013 android::util::SURFACEFLINGER_STATS_LAYER_INFO));
1014 EXPECT_NE(nullptr, mDelegate->mCallback);
1015 EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
1016
1017 EXPECT_CALL(*mDelegate,
1018 statsEventSetAtomId(mDelegate->mEvent,
1019 android::util::SURFACEFLINGER_STATS_LAYER_INFO))
1020 .Times(1);
1021 EXPECT_CALL(*mDelegate,
1022 statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
1023 EXPECT_EQ(STATS_PULL_SUCCESS,
1024 mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
1025 mDelegate->mCookie));
1026}
1027
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001028TEST_F(TimeStatsTest, canSurviveMonkey) {
Lloyd Pique067fe1e2018-12-06 19:44:13 -08001029 if (g_noSlowTests) {
1030 GTEST_SKIP();
1031 }
1032
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001033 EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
1034
1035 for (size_t i = 0; i < 10000000; ++i) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001036 const int32_t layerId = genRandomInt32(-1, 10);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001037 const int32_t frameNumber = genRandomInt32(1, 10);
1038 switch (genRandomInt32(0, 100)) {
1039 case 0:
1040 ALOGV("removeTimeRecord");
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001041 ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001042 continue;
1043 case 1:
1044 ALOGV("onDestroy");
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001045 ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001046 continue;
1047 }
1048 TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
1049 const int32_t ts = genRandomInt32(1, 1000000000);
Yiwei Zhang1a88c402019-11-18 10:43:58 -08001050 ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
1051 setTimeStamp(type, layerId, frameNumber, ts);
Yiwei Zhang16faa5d2018-11-13 18:12:59 -08001052 }
1053}
1054
1055} // namespace
1056} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -08001057
1058// TODO(b/129481165): remove the #pragma below and fix conversion issues
1059#pragma clang diagnostic pop // ignored "-Wconversion"