Flutter Engine
The Flutter Engine
frame_timings_recorder_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <thread>
6#include "flutter/flow/frame_timings.h"
7#include "flutter/flow/testing/layer_test.h"
8#include "flutter/flow/testing/mock_layer.h"
9#include "flutter/flow/testing/mock_raster_cache.h"
10
11#include "flutter/fml/time/time_delta.h"
12#include "flutter/fml/time/time_point.h"
13
14#include "gtest/gtest.h"
15
16namespace flutter {
17
18using testing::MockRasterCache;
19
20TEST(FrameTimingsRecorderTest, RecordVsync) {
21 auto recorder = std::make_unique<FrameTimingsRecorder>();
22 const auto st = fml::TimePoint::Now();
23 const auto en = st + fml::TimeDelta::FromMillisecondsF(16);
24 recorder->RecordVsync(st, en);
25
26 ASSERT_EQ(st, recorder->GetVsyncStartTime());
27 ASSERT_EQ(en, recorder->GetVsyncTargetTime());
28}
29
30TEST(FrameTimingsRecorderTest, RecordBuildTimes) {
31 auto recorder = std::make_unique<FrameTimingsRecorder>();
32
33 const auto st = fml::TimePoint::Now();
34 const auto en = st + fml::TimeDelta::FromMillisecondsF(16);
35 recorder->RecordVsync(st, en);
36
37 const auto build_start = fml::TimePoint::Now();
38 const auto build_end = build_start + fml::TimeDelta::FromMillisecondsF(16);
39 recorder->RecordBuildStart(build_start);
40 recorder->RecordBuildEnd(build_end);
41
42 ASSERT_EQ(build_start, recorder->GetBuildStartTime());
43 ASSERT_EQ(build_end, recorder->GetBuildEndTime());
44}
45
46TEST(FrameTimingsRecorderTest, RecordRasterTimes) {
47 auto recorder = std::make_unique<FrameTimingsRecorder>();
48
49 const auto st = fml::TimePoint::Now();
50 const auto en = st + fml::TimeDelta::FromMillisecondsF(16);
51 recorder->RecordVsync(st, en);
52
53 const auto build_start = fml::TimePoint::Now();
54 const auto build_end = build_start + fml::TimeDelta::FromMillisecondsF(16);
55 recorder->RecordBuildStart(build_start);
56 recorder->RecordBuildEnd(build_end);
57
58 using namespace std::chrono_literals;
59
60 const auto raster_start = fml::TimePoint::Now();
61 recorder->RecordRasterStart(raster_start);
62 const auto before_raster_end_wall_time = fml::TimePoint::CurrentWallTime();
63 std::this_thread::sleep_for(1ms);
64 const auto timing = recorder->RecordRasterEnd();
65 std::this_thread::sleep_for(1ms);
66 const auto after_raster_end_wall_time = fml::TimePoint::CurrentWallTime();
67
68 ASSERT_EQ(raster_start, recorder->GetRasterStartTime());
69 ASSERT_GT(recorder->GetRasterEndWallTime(), before_raster_end_wall_time);
70 ASSERT_LT(recorder->GetRasterEndWallTime(), after_raster_end_wall_time);
71 ASSERT_EQ(recorder->GetFrameNumber(), timing.GetFrameNumber());
72 ASSERT_EQ(recorder->GetLayerCacheCount(), 0u);
73 ASSERT_EQ(recorder->GetLayerCacheBytes(), 0u);
74 ASSERT_EQ(recorder->GetPictureCacheCount(), 0u);
75 ASSERT_EQ(recorder->GetPictureCacheBytes(), 0u);
76}
77
78TEST(FrameTimingsRecorderTest, RecordRasterTimesWithCache) {
79 auto recorder = std::make_unique<FrameTimingsRecorder>();
80
81 const auto st = fml::TimePoint::Now();
82 const auto en = st + fml::TimeDelta::FromMillisecondsF(16);
83 recorder->RecordVsync(st, en);
84
85 const auto build_start = fml::TimePoint::Now();
86 const auto build_end = build_start + fml::TimeDelta::FromMillisecondsF(16);
87 recorder->RecordBuildStart(build_start);
88 recorder->RecordBuildEnd(build_end);
89
90 using namespace std::chrono_literals;
91
93 cache.BeginFrame();
94
95 const auto raster_start = fml::TimePoint::Now();
96 recorder->RecordRasterStart(raster_start);
97
98 cache.AddMockLayer(100, 100);
99 size_t layer_bytes = cache.EstimateLayerCacheByteSize();
100 EXPECT_GT(layer_bytes, 0u);
101 cache.AddMockPicture(100, 100);
102 size_t picture_bytes = cache.EstimatePictureCacheByteSize();
103 EXPECT_GT(picture_bytes, 0u);
104 cache.EvictUnusedCacheEntries();
105
106 cache.EndFrame();
107
108 const auto before_raster_end_wall_time = fml::TimePoint::CurrentWallTime();
109 std::this_thread::sleep_for(1ms);
110 const auto timing = recorder->RecordRasterEnd(&cache);
111 std::this_thread::sleep_for(1ms);
112 const auto after_raster_end_wall_time = fml::TimePoint::CurrentWallTime();
113
114 ASSERT_EQ(raster_start, recorder->GetRasterStartTime());
115 ASSERT_GT(recorder->GetRasterEndWallTime(), before_raster_end_wall_time);
116 ASSERT_LT(recorder->GetRasterEndWallTime(), after_raster_end_wall_time);
117 ASSERT_EQ(recorder->GetFrameNumber(), timing.GetFrameNumber());
118 ASSERT_EQ(recorder->GetLayerCacheCount(), 1u);
119 ASSERT_EQ(recorder->GetLayerCacheBytes(), layer_bytes);
120 ASSERT_EQ(recorder->GetPictureCacheCount(), 1u);
121 ASSERT_EQ(recorder->GetPictureCacheBytes(), picture_bytes);
122}
123
124// Windows and Fuchsia don't allow testing with killed by signal.
125#if !defined(OS_FUCHSIA) && !defined(FML_OS_WIN) && \
126 (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG)
127
128TEST(FrameTimingsRecorderTest, ThrowWhenRecordBuildBeforeVsync) {
129 auto recorder = std::make_unique<FrameTimingsRecorder>();
130
131 const auto build_start = fml::TimePoint::Now();
132 fml::Status status = recorder->RecordBuildStartImpl(build_start);
133 EXPECT_FALSE(status.ok());
134 EXPECT_EQ(status.message(), "Check failed: state_ == State::kVsync.");
135}
136
137TEST(FrameTimingsRecorderTest, ThrowWhenRecordRasterBeforeBuildEnd) {
138 auto recorder = std::make_unique<FrameTimingsRecorder>();
139
140 const auto st = fml::TimePoint::Now();
141 const auto en = st + fml::TimeDelta::FromMillisecondsF(16);
142 recorder->RecordVsync(st, en);
143
144 const auto raster_start = fml::TimePoint::Now();
145 fml::Status status = recorder->RecordRasterStartImpl(raster_start);
146 EXPECT_FALSE(status.ok());
147 EXPECT_EQ(status.message(), "Check failed: state_ == State::kBuildEnd.");
148}
149
150#endif
151
152TEST(FrameTimingsRecorderTest, RecordersHaveUniqueFrameNumbers) {
153 auto recorder1 = std::make_unique<FrameTimingsRecorder>();
154 auto recorder2 = std::make_unique<FrameTimingsRecorder>();
155
156 ASSERT_TRUE(recorder2->GetFrameNumber() > recorder1->GetFrameNumber());
157}
158
159TEST(FrameTimingsRecorderTest, ClonedHasSameFrameNumber) {
160 auto recorder = std::make_unique<FrameTimingsRecorder>();
161
162 auto cloned =
164 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
165}
166
167TEST(FrameTimingsRecorderTest, ClonedHasSameVsyncStartAndTarget) {
168 auto recorder = std::make_unique<FrameTimingsRecorder>();
169
170 const auto now = fml::TimePoint::Now();
171 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
172
173 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kVsync);
174 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
175 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
176 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
177}
178
179TEST(FrameTimingsRecorderTest, ClonedHasSameBuildStart) {
180 auto recorder = std::make_unique<FrameTimingsRecorder>();
181
182 const auto now = fml::TimePoint::Now();
183 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
184 recorder->RecordBuildStart(fml::TimePoint::Now());
185
186 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kBuildStart);
187 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
188 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
189 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
190 ASSERT_EQ(recorder->GetBuildStartTime(), cloned->GetBuildStartTime());
191}
192
193TEST(FrameTimingsRecorderTest, ClonedHasSameBuildEnd) {
194 auto recorder = std::make_unique<FrameTimingsRecorder>();
195
196 const auto now = fml::TimePoint::Now();
197 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
198 recorder->RecordBuildStart(fml::TimePoint::Now());
199 recorder->RecordBuildEnd(fml::TimePoint::Now());
200
201 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kBuildEnd);
202 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
203 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
204 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
205 ASSERT_EQ(recorder->GetBuildStartTime(), cloned->GetBuildStartTime());
206 ASSERT_EQ(recorder->GetBuildEndTime(), cloned->GetBuildEndTime());
207}
208
209TEST(FrameTimingsRecorderTest, ClonedHasSameRasterStart) {
210 auto recorder = std::make_unique<FrameTimingsRecorder>();
211
212 const auto now = fml::TimePoint::Now();
213 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
214 recorder->RecordBuildStart(fml::TimePoint::Now());
215 recorder->RecordBuildEnd(fml::TimePoint::Now());
216 recorder->RecordRasterStart(fml::TimePoint::Now());
217
218 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kRasterStart);
219 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
220 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
221 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
222 ASSERT_EQ(recorder->GetBuildStartTime(), cloned->GetBuildStartTime());
223 ASSERT_EQ(recorder->GetBuildEndTime(), cloned->GetBuildEndTime());
224 ASSERT_EQ(recorder->GetRasterStartTime(), cloned->GetRasterStartTime());
225}
226
227TEST(FrameTimingsRecorderTest, ClonedHasSameRasterEnd) {
228 auto recorder = std::make_unique<FrameTimingsRecorder>();
229
230 const auto now = fml::TimePoint::Now();
231 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
232 recorder->RecordBuildStart(fml::TimePoint::Now());
233 recorder->RecordBuildEnd(fml::TimePoint::Now());
234 recorder->RecordRasterStart(fml::TimePoint::Now());
235 recorder->RecordRasterEnd();
236
237 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kRasterEnd);
238 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
239 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
240 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
241 ASSERT_EQ(recorder->GetBuildStartTime(), cloned->GetBuildStartTime());
242 ASSERT_EQ(recorder->GetBuildEndTime(), cloned->GetBuildEndTime());
243 ASSERT_EQ(recorder->GetRasterStartTime(), cloned->GetRasterStartTime());
244 ASSERT_EQ(recorder->GetRasterEndTime(), cloned->GetRasterEndTime());
245 ASSERT_EQ(recorder->GetRasterEndWallTime(), cloned->GetRasterEndWallTime());
246 ASSERT_EQ(recorder->GetLayerCacheCount(), cloned->GetLayerCacheCount());
247 ASSERT_EQ(recorder->GetLayerCacheBytes(), cloned->GetLayerCacheBytes());
248 ASSERT_EQ(recorder->GetPictureCacheCount(), cloned->GetPictureCacheCount());
249 ASSERT_EQ(recorder->GetPictureCacheBytes(), cloned->GetPictureCacheBytes());
250}
251
252TEST(FrameTimingsRecorderTest, ClonedHasSameRasterEndWithCache) {
253 auto recorder = std::make_unique<FrameTimingsRecorder>();
254 MockRasterCache cache(1, 10);
255 cache.BeginFrame();
256
257 const auto now = fml::TimePoint::Now();
258 recorder->RecordVsync(now, now + fml::TimeDelta::FromMilliseconds(16));
259 recorder->RecordBuildStart(fml::TimePoint::Now());
260 recorder->RecordBuildEnd(fml::TimePoint::Now());
261 recorder->RecordRasterStart(fml::TimePoint::Now());
262
263 cache.AddMockLayer(100, 100);
264 size_t layer_bytes = cache.EstimateLayerCacheByteSize();
265 EXPECT_GT(layer_bytes, 0u);
266 cache.AddMockPicture(100, 100);
267 size_t picture_bytes = cache.EstimatePictureCacheByteSize();
268 EXPECT_GT(picture_bytes, 0u);
269 cache.EvictUnusedCacheEntries();
270 cache.EndFrame();
271 recorder->RecordRasterEnd(&cache);
272
273 auto cloned = recorder->CloneUntil(FrameTimingsRecorder::State::kRasterEnd);
274 ASSERT_EQ(recorder->GetFrameNumber(), cloned->GetFrameNumber());
275 ASSERT_EQ(recorder->GetVsyncStartTime(), cloned->GetVsyncStartTime());
276 ASSERT_EQ(recorder->GetVsyncTargetTime(), cloned->GetVsyncTargetTime());
277 ASSERT_EQ(recorder->GetBuildStartTime(), cloned->GetBuildStartTime());
278 ASSERT_EQ(recorder->GetBuildEndTime(), cloned->GetBuildEndTime());
279 ASSERT_EQ(recorder->GetRasterStartTime(), cloned->GetRasterStartTime());
280 ASSERT_EQ(recorder->GetRasterEndTime(), cloned->GetRasterEndTime());
281 ASSERT_EQ(recorder->GetRasterEndWallTime(), cloned->GetRasterEndWallTime());
282 ASSERT_EQ(recorder->GetLayerCacheCount(), cloned->GetLayerCacheCount());
283 ASSERT_EQ(recorder->GetLayerCacheBytes(), cloned->GetLayerCacheBytes());
284 ASSERT_EQ(recorder->GetPictureCacheCount(), cloned->GetPictureCacheCount());
285 ASSERT_EQ(recorder->GetPictureCacheBytes(), cloned->GetPictureCacheBytes());
286}
287
288TEST(FrameTimingsRecorderTest, FrameNumberTraceArgIsValid) {
289 auto recorder = std::make_unique<FrameTimingsRecorder>();
290
291 char buff[50];
292 sprintf(buff, "%d", static_cast<int>(recorder->GetFrameNumber()));
293 std::string actual_arg = buff;
294 std::string expected_arg = recorder->GetFrameNumberTraceArg();
295
296 ASSERT_EQ(actual_arg, expected_arg);
297}
298
299} // namespace flutter
A RasterCache implementation that simulates the act of rendering a Layer or DisplayList without the o...
bool ok() const
Definition: status.h:71
std::string_view message() const
Definition: status.h:75
static constexpr TimeDelta FromMillisecondsF(double millis)
Definition: time_delta.h:57
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
static TimePoint CurrentWallTime()
Definition: time_point.cc:57
static TimePoint Now()
Definition: time_point.cc:49
TEST(FrameTimingsRecorderTest, RecordVsync)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition: switches.h:191