Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c5a9bca

Browse files
committed
Streamline frame timings recording
`FlutterFrameTimingsRecorder` is passed through the lifecycle of the frame and records the events that happen through it. This also serves as a builder for the `FrameTiming` object that is later passed to the framework. This change also aims to lay the foundation to capture a unique frame identifier which will later be added to `FlutterFrameTimingsRecorder` to identify the trace events corresponding to each frame. x-ref: #25662 x-ref: flutter/flutter#80735
1 parent d61bbfa commit c5a9bca

File tree

19 files changed

+379
-118
lines changed

19 files changed

+379
-118
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ FILE: ../../../flutter/flow/embedded_views.h
4242
FILE: ../../../flutter/flow/flow_run_all_unittests.cc
4343
FILE: ../../../flutter/flow/flow_test_utils.cc
4444
FILE: ../../../flutter/flow/flow_test_utils.h
45+
FILE: ../../../flutter/flow/frame_timings.cc
46+
FILE: ../../../flutter/flow/frame_timings.h
4547
FILE: ../../../flutter/flow/gl_context_switch_unittests.cc
4648
FILE: ../../../flutter/flow/instrumentation.cc
4749
FILE: ../../../flutter/flow/instrumentation.h

flow/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ source_set("flow") {
1414
"diff_context.h",
1515
"embedded_views.cc",
1616
"embedded_views.h",
17+
"frame_timings.cc",
18+
"frame_timings.h",
1719
"instrumentation.cc",
1820
"instrumentation.h",
1921
"layers/backdrop_filter_layer.cc",

flow/frame_timings.cc

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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 "flutter/flow/frame_timings.h"
6+
7+
#include <memory>
8+
9+
#include "flutter/common/settings.h"
10+
#include "flutter/fml/logging.h"
11+
12+
namespace flutter {
13+
14+
FrameTimingsRecorder::FrameTimingsRecorder() = default;
15+
16+
FrameTimingsRecorder::~FrameTimingsRecorder() = default;
17+
18+
fml::TimePoint FrameTimingsRecorder::GetVsyncStartTime() const {
19+
std::scoped_lock state_lock(state_mutex_);
20+
FML_CHECK(state_ >= State::kVsync);
21+
return vsync_start_;
22+
}
23+
24+
fml::TimePoint FrameTimingsRecorder::GetVsyncTargetTime() const {
25+
std::scoped_lock state_lock(state_mutex_);
26+
FML_CHECK(state_ >= State::kVsync);
27+
return vsync_target_;
28+
}
29+
30+
fml::TimePoint FrameTimingsRecorder::GetBuildStartTime() const {
31+
std::scoped_lock state_lock(state_mutex_);
32+
FML_CHECK(state_ >= State::kBuildStart);
33+
return build_start_;
34+
}
35+
36+
fml::TimePoint FrameTimingsRecorder::GetBuildEndTime() const {
37+
std::scoped_lock state_lock(state_mutex_);
38+
FML_CHECK(state_ >= State::kBuildEnd);
39+
return build_end_;
40+
}
41+
42+
fml::TimePoint FrameTimingsRecorder::GetRasterStartTime() const {
43+
std::scoped_lock state_lock(state_mutex_);
44+
FML_CHECK(state_ >= State::kRasterStart);
45+
return raster_start_;
46+
}
47+
48+
fml::TimePoint FrameTimingsRecorder::GetRasterEndTime() const {
49+
std::scoped_lock state_lock(state_mutex_);
50+
FML_CHECK(state_ >= State::kRasterEnd);
51+
return raster_end_;
52+
}
53+
54+
fml::TimeDelta FrameTimingsRecorder::GetBuildDuration() const {
55+
std::scoped_lock state_lock(state_mutex_);
56+
FML_CHECK(state_ >= State::kBuildEnd);
57+
return build_end_ - build_start_;
58+
}
59+
60+
void FrameTimingsRecorder::RecordVsync(fml::TimePoint vsync_start,
61+
fml::TimePoint vsync_target) {
62+
std::scoped_lock state_lock(state_mutex_);
63+
FML_CHECK(state_ == State::kUnitialized);
64+
state_ = State::kVsync;
65+
vsync_start_ = vsync_start;
66+
vsync_target_ = vsync_target;
67+
}
68+
69+
void FrameTimingsRecorder::RecordBuildStart(fml::TimePoint build_start) {
70+
std::scoped_lock state_lock(state_mutex_);
71+
FML_CHECK(state_ == State::kVsync);
72+
state_ = State::kBuildStart;
73+
build_start_ = build_start;
74+
}
75+
76+
void FrameTimingsRecorder::RecordBuildEnd(fml::TimePoint build_end) {
77+
std::scoped_lock state_lock(state_mutex_);
78+
FML_CHECK(state_ == State::kBuildStart);
79+
state_ = State::kBuildEnd;
80+
build_end_ = build_end;
81+
}
82+
83+
void FrameTimingsRecorder::RecordRasterStart(fml::TimePoint raster_start) {
84+
std::scoped_lock state_lock(state_mutex_);
85+
FML_CHECK(state_ == State::kBuildEnd);
86+
state_ = State::kRasterStart;
87+
raster_start_ = raster_start;
88+
}
89+
90+
FrameTiming FrameTimingsRecorder::RecordRasterEnd(fml::TimePoint raster_end) {
91+
std::scoped_lock state_lock(state_mutex_);
92+
FML_CHECK(state_ == State::kRasterStart);
93+
state_ = State::kRasterEnd;
94+
raster_end_ = raster_end;
95+
FrameTiming timing;
96+
timing.Set(FrameTiming::kVsyncStart, vsync_start_);
97+
timing.Set(FrameTiming::kBuildStart, build_start_);
98+
timing.Set(FrameTiming::kBuildFinish, build_end_);
99+
timing.Set(FrameTiming::kRasterStart, raster_start_);
100+
timing.Set(FrameTiming::kRasterFinish, raster_end_);
101+
return timing;
102+
}
103+
104+
std::unique_ptr<FrameTimingsRecorder> FrameTimingsRecorder::CloneUntil(
105+
State state) {
106+
std::scoped_lock state_lock(state_mutex_);
107+
std::unique_ptr<FrameTimingsRecorder> recorder =
108+
std::make_unique<FrameTimingsRecorder>();
109+
recorder->state_ = state;
110+
111+
if (state >= State::kVsync) {
112+
recorder->vsync_start_ = vsync_start_;
113+
recorder->vsync_target_ = vsync_target_;
114+
}
115+
116+
if (state >= State::kBuildStart) {
117+
recorder->build_start_ = build_start_;
118+
}
119+
120+
if (state >= State::kRasterEnd) {
121+
recorder->build_end_ = build_end_;
122+
}
123+
124+
if (state >= State::kRasterStart) {
125+
recorder->raster_start_ = raster_start_;
126+
}
127+
128+
if (state >= State::kRasterEnd) {
129+
recorder->raster_end_ = raster_end_;
130+
}
131+
132+
return recorder;
133+
}
134+
135+
} // namespace flutter

flow/frame_timings.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
#ifndef FLUTTER_FLOW_FRAME_TIMINGS_H_
6+
#define FLUTTER_FLOW_FRAME_TIMINGS_H_
7+
8+
#include <mutex>
9+
10+
#include "flutter/common/settings.h"
11+
#include "flutter/fml/macros.h"
12+
#include "flutter/fml/time/time_delta.h"
13+
#include "flutter/fml/time/time_point.h"
14+
15+
namespace flutter {
16+
17+
class FrameTimingsRecorder {
18+
public:
19+
enum class State : uint32_t {
20+
kUnitialized = 1,
21+
kVsync = 2,
22+
kBuildStart = 3,
23+
kBuildEnd = 4,
24+
kRasterStart = 5,
25+
kRasterEnd = 6,
26+
};
27+
28+
FrameTimingsRecorder();
29+
30+
~FrameTimingsRecorder();
31+
32+
fml::TimePoint GetVsyncStartTime() const;
33+
34+
fml::TimePoint GetVsyncTargetTime() const;
35+
36+
fml::TimePoint GetBuildStartTime() const;
37+
38+
fml::TimePoint GetBuildEndTime() const;
39+
40+
fml::TimePoint GetRasterStartTime() const;
41+
42+
fml::TimePoint GetRasterEndTime() const;
43+
44+
fml::TimeDelta GetBuildDuration() const;
45+
46+
void RecordVsync(fml::TimePoint vsync_start, fml::TimePoint vsync_target);
47+
48+
void RecordBuildStart(fml::TimePoint build_start);
49+
50+
void RecordBuildEnd(fml::TimePoint build_end);
51+
52+
void RecordRasterStart(fml::TimePoint raster_start);
53+
54+
std::unique_ptr<FrameTimingsRecorder> CloneUntil(State state);
55+
56+
FrameTiming RecordRasterEnd(fml::TimePoint raster_end);
57+
58+
private:
59+
mutable std::mutex state_mutex_;
60+
State state_ = State::kUnitialized;
61+
62+
fml::TimePoint vsync_start_ = fml::TimePoint::Min();
63+
fml::TimePoint vsync_target_ = fml::TimePoint::Min();
64+
fml::TimePoint build_start_ = fml::TimePoint::Min();
65+
fml::TimePoint build_end_ = fml::TimePoint::Min();
66+
fml::TimePoint raster_start_ = fml::TimePoint::Min();
67+
fml::TimePoint raster_end_ = fml::TimePoint::Min();
68+
69+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(FrameTimingsRecorder);
70+
};
71+
72+
} // namespace flutter
73+
74+
#endif // FLUTTER_FLOW_FRAME_TIMINGS_H_

flow/layers/layer_tree.cc

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
#include "flutter/flow/layers/layer_tree.h"
66

7+
#include "flutter/flow/frame_timings.h"
78
#include "flutter/flow/layers/layer.h"
9+
#include "flutter/fml/time/time_point.h"
810
#include "flutter/fml/trace_event.h"
911
#include "third_party/skia/include/core/SkPictureRecorder.h"
1012
#include "third_party/skia/include/utils/SkNWayCanvas.h"
@@ -20,15 +22,6 @@ LayerTree::LayerTree(const SkISize& frame_size, float device_pixel_ratio)
2022
FML_CHECK(device_pixel_ratio_ != 0.0f);
2123
}
2224

23-
void LayerTree::RecordBuildTime(fml::TimePoint vsync_start,
24-
fml::TimePoint build_start,
25-
fml::TimePoint target_time) {
26-
vsync_start_ = vsync_start;
27-
build_start_ = build_start;
28-
target_time_ = target_time;
29-
build_finish_ = fml::TimePoint::Now();
30-
}
31-
3225
bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
3326
bool ignore_raster_cache) {
3427
TRACE_EVENT0("flutter", "LayerTree::Preroll");

flow/layers/layer_tree.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,6 @@ class LayerTree {
5656

5757
#endif // FLUTTER_ENABLE_DIFF_CONTEXT
5858

59-
void RecordBuildTime(fml::TimePoint vsync_start,
60-
fml::TimePoint build_start,
61-
fml::TimePoint target_time);
62-
fml::TimePoint vsync_start() const { return vsync_start_; }
63-
fml::TimeDelta vsync_overhead() const { return build_start_ - vsync_start_; }
64-
fml::TimePoint build_start() const { return build_start_; }
65-
fml::TimePoint build_finish() const { return build_finish_; }
66-
fml::TimeDelta build_time() const { return build_finish_ - build_start_; }
67-
fml::TimePoint target_time() const { return target_time_; }
68-
6959
// The number of frame intervals missed after which the compositor must
7060
// trace the rasterized picture to a trace file. Specify 0 to disable all
7161
// tracing
@@ -87,10 +77,6 @@ class LayerTree {
8777

8878
private:
8979
std::shared_ptr<Layer> root_layer_;
90-
fml::TimePoint vsync_start_;
91-
fml::TimePoint build_start_;
92-
fml::TimePoint build_finish_;
93-
fml::TimePoint target_time_;
9480
SkISize frame_size_ = SkISize::MakeEmpty(); // Physical pixels.
9581
const float device_pixel_ratio_; // Logical / Physical pixels ratio.
9682
uint32_t rasterizer_tracing_threshold_;

lib/ui/painting/image_decoder_unittests.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ TEST_F(ImageDecoderFixtureTest, CanDecodeWithResizes) {
427427
latch.Wait();
428428
}
429429

430-
// TODO(https://github.com/flutter/flutter/issues/81232) - disabled due to flakiness
430+
// TODO(https://github.com/flutter/flutter/issues/81232) - disabled due to
431+
// flakiness
431432
TEST_F(ImageDecoderFixtureTest, DISABLED_CanResizeWithoutDecode) {
432433
SkImageInfo info = {};
433434
size_t row_bytes;

0 commit comments

Comments
 (0)