Skip to content

Commit de350c4

Browse files
authored
Report timings faster (100ms) in profile/debug (flutter#9287)
This should satisfy the low-latency need of DevTools. Test added: * ReportTimingsIsCalledSoonerInNonReleaseMode * ReportTimingsIsCalledLaterInReleaseMode
1 parent 6dc4d6c commit de350c4

File tree

3 files changed

+66
-7
lines changed

3 files changed

+66
-7
lines changed

lib/ui/window.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ typedef FrameCallback = void Function(Duration duration);
1313
/// Signature for [Window.onReportTimings].
1414
///
1515
/// {@template dart.ui.TimingsCallback.list}
16-
/// The callback takes a list of [FrameTiming] because it may not be immediately
17-
/// triggered after each frame. Instead, Flutter tries to batch frames together
18-
/// and send all their timings at once to decrease the overhead (as this is
19-
/// available in the release mode). The list is sorted in ascending order of
20-
/// time (earliest frame first). The timing of any frame will be sent within
21-
/// about 1 second even if there are no later frames to batch.
16+
/// The callback takes a list of [FrameTiming] because it may not be
17+
/// immediately triggered after each frame. Instead, Flutter tries to batch
18+
/// frames together and send all their timings at once to decrease the
19+
/// overhead (as this is available in the release mode). The list is sorted in
20+
/// ascending order of time (earliest frame first). The timing of any frame
21+
/// will be sent within about 1 second (100ms if in the profile/debug mode)
22+
/// even if there are no later frames to batch.
2223
/// {@endtemplate}
2324
typedef TimingsCallback = void Function(List<FrameTiming> timings);
2425

shell/common/shell.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,9 +934,20 @@ void Shell::OnFrameRasterized(const FrameTiming& timing) {
934934
// threshold here is mainly for unit tests (so we don't have to write a
935935
// 1-second unit test), and make sure that our vector won't grow too big with
936936
// future 120fps, 240fps, or 1000fps displays.
937+
//
938+
// In the profile/debug mode, the timings are used by development tools which
939+
// require a latency of no more than 100ms. Hence we lower that 1-second
940+
// threshold to 100ms because performance overhead isn't that critical in
941+
// those cases.
937942
if (UnreportedFramesCount() >= 100) {
938943
ReportTimings();
939944
} else if (!frame_timings_report_scheduled_) {
945+
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE
946+
constexpr int kBatchTimeInMilliseconds = 1000;
947+
#else
948+
constexpr int kBatchTimeInMilliseconds = 100;
949+
#endif
950+
940951
// Also make sure that frame times get reported with a max latency of 1
941952
// second. Otherwise, the timings of last few frames of an animation may
942953
// never be reported until the next animation starts.
@@ -951,7 +962,7 @@ void Shell::OnFrameRasterized(const FrameTiming& timing) {
951962
self->ReportTimings();
952963
}
953964
},
954-
fml::TimeDelta::FromSeconds(1));
965+
fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
955966
}
956967
}
957968

shell/common/shell_unittests.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,5 +434,52 @@ TEST(SettingsTest, FrameTimingSetsAndGetsProperly) {
434434
}
435435
}
436436

437+
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE
438+
TEST_F(ShellTest, ReportTimingsIsCalledSoonerInNonReleaseMode) {
439+
#else
440+
TEST_F(ShellTest, ReportTimingsIsCalledLaterInNonReleaseMode) {
441+
#endif
442+
fml::TimePoint start = fml::TimePoint::Now();
443+
auto settings = CreateSettingsForFixture();
444+
std::unique_ptr<Shell> shell = CreateShell(std::move(settings));
445+
446+
// Create the surface needed by rasterizer
447+
PlatformViewNotifyCreated(shell.get());
448+
449+
auto configuration = RunConfiguration::InferFromSettings(settings);
450+
ASSERT_TRUE(configuration.IsValid());
451+
configuration.SetEntrypoint("reportTimingsMain");
452+
fml::AutoResetWaitableEvent reportLatch;
453+
std::vector<int64_t> timestamps;
454+
auto nativeTimingCallback = [&reportLatch,
455+
&timestamps](Dart_NativeArguments args) {
456+
Dart_Handle exception = nullptr;
457+
timestamps = tonic::DartConverter<std::vector<int64_t>>::FromArguments(
458+
args, 0, exception);
459+
reportLatch.Signal();
460+
};
461+
AddNativeCallback("NativeReportTimingsCallback",
462+
CREATE_NATIVE_ENTRY(nativeTimingCallback));
463+
RunEngine(shell.get(), std::move(configuration));
464+
465+
PumpOneFrame(shell.get());
466+
467+
reportLatch.Wait();
468+
shell.reset();
469+
470+
fml::TimePoint finish = fml::TimePoint::Now();
471+
fml::TimeDelta ellapsed = finish - start;
472+
473+
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE
474+
// Our batch time is 1000ms. Hopefully the 800ms limit is relaxed enough to
475+
// make it not too flaky.
476+
ASSERT_TRUE(ellapsed >= fml::TimeDelta::FromMilliseconds(800));
477+
#else
478+
// Our batch time is 100ms. Hopefully the 500ms limit is relaxed enough to
479+
// make it not too flaky.
480+
ASSERT_TRUE(ellapsed <= fml::TimeDelta::FromMilliseconds(500));
481+
#endif
482+
}
483+
437484
} // namespace testing
438485
} // namespace flutter

0 commit comments

Comments
 (0)