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