Skip to content

Commit da07c33

Browse files
authored
Make NotifyIdle reject close and past deadlines. (flutter#37737)
This patch also eliminates some extraneous tracing that is happening every frame. It is possible to get the same trace calls by enabling the API stream if needed. Also refactors the NotifyIdle callsites to just always work in TimeDeltas rather than converting back and forth between them and TimePoints, which I think reads more clearly.
1 parent 30aa3cc commit da07c33

File tree

13 files changed

+83
-46
lines changed

13 files changed

+83
-46
lines changed

runtime/runtime_controller.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,15 @@ bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
211211
return false;
212212
}
213213

214-
bool RuntimeController::NotifyIdle(fml::TimePoint deadline) {
214+
bool RuntimeController::NotifyIdle(fml::TimeDelta deadline) {
215+
if (deadline - fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros()) <
216+
fml::TimeDelta::FromMilliseconds(1)) {
217+
// There's less than 1ms left before the deadline. Upstream callers do not
218+
// check to see if the deadline is in the past, and work after this point
219+
// will be in vain.
220+
return false;
221+
}
222+
215223
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
216224
if (!root_isolate) {
217225
return false;
@@ -225,12 +233,12 @@ bool RuntimeController::NotifyIdle(fml::TimePoint deadline) {
225233
return false;
226234
}
227235

228-
Dart_NotifyIdle(deadline.ToEpochDelta().ToMicroseconds());
236+
Dart_NotifyIdle(deadline.ToMicroseconds());
229237

230238
// Idle notifications being in isolate scope are part of the contract.
231239
if (idle_notification_callback_) {
232240
TRACE_EVENT0("flutter", "EmbedderIdleNotification");
233-
idle_notification_callback_(deadline.ToEpochDelta().ToMicroseconds());
241+
idle_notification_callback_(deadline.ToMicroseconds());
234242
}
235243
return true;
236244
}

runtime/runtime_controller.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ class RuntimeController : public PlatformConfigurationClient {
358358
///
359359
/// @return If the idle notification was forwarded to the running isolate.
360360
///
361-
virtual bool NotifyIdle(fml::TimePoint deadline);
361+
virtual bool NotifyIdle(fml::TimeDelta deadline);
362362

363363
//----------------------------------------------------------------------------
364364
/// @brief Notify the Dart VM that the attached flutter view has been

shell/common/animator.cc

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ void Animator::EnqueueTraceFlowId(uint64_t trace_flow_id) {
5757
});
5858
}
5959

60-
static fml::TimePoint FxlToDartOrEarlier(fml::TimePoint time) {
61-
auto dart_now = fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros());
62-
fml::TimePoint fxl_now = fml::TimePoint::Now();
63-
return fml::TimePoint::FromEpochDelta(time - fxl_now + dart_now);
64-
}
65-
6660
void Animator::BeginFrame(
6761
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
6862
TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending",
@@ -81,7 +75,6 @@ void Animator::BeginFrame(
8175
}
8276

8377
frame_scheduled_ = false;
84-
notify_idle_task_id_++;
8578
regenerate_layer_tree_ = false;
8679
pending_frame_semaphore_.Signal();
8780

@@ -106,34 +99,29 @@ void Animator::BeginFrame(
10699
FML_DCHECK(producer_continuation_);
107100
const fml::TimePoint frame_target_time =
108101
frame_timings_recorder_->GetVsyncTargetTime();
109-
dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time);
102+
dart_frame_deadline_ = frame_target_time.ToEpochDelta();
110103
uint64_t frame_number = frame_timings_recorder_->GetFrameNumber();
111104
delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
112105

113106
if (!frame_scheduled_ && has_rendered_) {
114-
// Under certain workloads (such as our parent view resizing us, which is
115-
// communicated to us by repeat viewport metrics events), we won't
116-
// actually have a frame scheduled yet, despite the fact that we *will* be
117-
// producing a frame next vsync (it will be scheduled once we receive the
118-
// viewport event). Because of this, we hold off on calling
119-
// |OnAnimatorNotifyIdle| for a little bit, as that could cause garbage
120-
// collection to trigger at a highly undesirable time.
107+
// Wait a tad more than 3 60hz frames before reporting a big idle period.
108+
// This is a heuristic that is meant to avoid giving false positives to the
109+
// VM when we are about to schedule a frame in the next vsync, the idea
110+
// being that if there have been three vsyncs with no frames it's a good
111+
// time to start doing GC work.
121112
task_runners_.GetUITaskRunner()->PostDelayedTask(
122-
[self = weak_factory_.GetWeakPtr(),
123-
notify_idle_task_id = notify_idle_task_id_]() {
113+
[self = weak_factory_.GetWeakPtr()]() {
124114
if (!self) {
125115
return;
126116
}
127-
// If our (this task's) task id is the same as the current one
128-
// (meaning there were no follow up frames to the |BeginFrame| call
129-
// that posted this task) and no frame is currently scheduled, then
130-
// assume that we are idle, and notify the engine of this.
131-
if (notify_idle_task_id == self->notify_idle_task_id_ &&
132-
!self->frame_scheduled_) {
117+
auto now = fml::TimeDelta::FromMicroseconds(Dart_TimelineGetMicros());
118+
// If there's a frame scheduled, bail.
119+
// If there's no frame scheduled, but we're not yet past the last
120+
// vsync deadline, bail.
121+
if (!self->frame_scheduled_ && now > self->dart_frame_deadline_) {
133122
TRACE_EVENT0("flutter", "BeginFrame idle callback");
134123
self->delegate_.OnAnimatorNotifyIdle(
135-
FxlToDartOrEarlier(fml::TimePoint::Now() +
136-
fml::TimeDelta::FromMicroseconds(100000)));
124+
now + fml::TimeDelta::FromMilliseconds(100));
137125
}
138126
},
139127
kNotifyIdleTaskWaitTime);

shell/common/animator.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Animator final {
3434
virtual void OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
3535
uint64_t frame_number) = 0;
3636

37-
virtual void OnAnimatorNotifyIdle(fml::TimePoint deadline) = 0;
37+
virtual void OnAnimatorNotifyIdle(fml::TimeDelta deadline) = 0;
3838

3939
virtual void OnAnimatorUpdateLatestFrameTargetTime(
4040
fml::TimePoint frame_target_time) = 0;
@@ -100,13 +100,12 @@ class Animator final {
100100

101101
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder_;
102102
uint64_t frame_request_number_ = 1;
103-
fml::TimePoint dart_frame_deadline_;
103+
fml::TimeDelta dart_frame_deadline_;
104104
std::shared_ptr<LayerTreePipeline> layer_tree_pipeline_;
105105
fml::Semaphore pending_frame_semaphore_;
106106
LayerTreePipeline::ProducerContinuation producer_continuation_;
107107
bool regenerate_layer_tree_ = false;
108108
bool frame_scheduled_ = false;
109-
int notify_idle_task_id_ = 0;
110109
SkISize last_layer_tree_size_ = {0, 0};
111110
std::deque<uint64_t> trace_flow_ids_;
112111
bool has_rendered_ = false;

shell/common/animator_unittests.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class FakeAnimatorDelegate : public Animator::Delegate {
2828
MOCK_METHOD2(OnAnimatorBeginFrame,
2929
void(fml::TimePoint frame_target_time, uint64_t frame_number));
3030

31-
void OnAnimatorNotifyIdle(fml::TimePoint deadline) override {
31+
void OnAnimatorNotifyIdle(fml::TimeDelta deadline) override {
3232
notify_idle_called_ = true;
3333
}
3434

shell/common/engine.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,10 @@ void Engine::BeginFrame(fml::TimePoint frame_time, uint64_t frame_number) {
254254
}
255255

256256
void Engine::ReportTimings(std::vector<int64_t> timings) {
257-
TRACE_EVENT0("flutter", "Engine::ReportTimings");
258257
runtime_controller_->ReportTimings(std::move(timings));
259258
}
260259

261-
void Engine::NotifyIdle(fml::TimePoint deadline) {
262-
auto trace_event = std::to_string(deadline.ToEpochDelta().ToMicroseconds() -
263-
Dart_TimelineGetMicros());
264-
TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
265-
trace_event.c_str());
260+
void Engine::NotifyIdle(fml::TimeDelta deadline) {
266261
runtime_controller_->NotifyIdle(deadline);
267262
}
268263

shell/common/engine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
552552
/// corresponding sweep can be performed within the
553553
/// deadline.
554554
///
555-
void NotifyIdle(fml::TimePoint deadline);
555+
void NotifyIdle(fml::TimeDelta deadline);
556556

557557
//----------------------------------------------------------------------------
558558
/// @brief Notifies the engine that the attached flutter view has been

shell/common/engine_unittests.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class MockRuntimeController : public RuntimeController {
7777
MOCK_METHOD3(LoadDartDeferredLibraryError,
7878
void(intptr_t, const std::string, bool));
7979
MOCK_CONST_METHOD0(GetDartVM, DartVM*());
80-
MOCK_METHOD1(NotifyIdle, bool(fml::TimePoint));
80+
MOCK_METHOD1(NotifyIdle, bool(fml::TimeDelta));
8181
};
8282

8383
std::unique_ptr<PlatformMessage> MakePlatformMessage(

shell/common/shell.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
11331133
}
11341134

11351135
// |Animator::Delegate|
1136-
void Shell::OnAnimatorNotifyIdle(fml::TimePoint deadline) {
1136+
void Shell::OnAnimatorNotifyIdle(fml::TimeDelta deadline) {
11371137
FML_DCHECK(is_setup_);
11381138
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
11391139

shell/common/shell.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ class Shell final : public PlatformView::Delegate,
591591
uint64_t frame_number) override;
592592

593593
// |Animator::Delegate|
594-
void OnAnimatorNotifyIdle(fml::TimePoint deadline) override;
594+
void OnAnimatorNotifyIdle(fml::TimeDelta deadline) override;
595595

596596
// |Animator::Delegate|
597597
void OnAnimatorUpdateLatestFrameTargetTime(

0 commit comments

Comments
 (0)