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

Commit 3fc6fb4

Browse files
lucky-chenpeihan.cph
authored and
peihan.cph
committed
Reducing startup latency block time by 50% at least
- add Shell::CreateAsync mode - supprot android && ios - add testcase for engine、Android、iOS - add benchmamrk on shell_benchmark.cc
1 parent 03d5e50 commit 3fc6fb4

File tree

15 files changed

+731
-55
lines changed

15 files changed

+731
-55
lines changed

shell/common/shell.cc

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,144 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
175175
return shell;
176176
}
177177

178+
bool Shell::CreateShellAsyncOnPlatformThread(
179+
ShellCreateCallback async_init_callback,
180+
DartVMRef vm,
181+
TaskRunners task_runners,
182+
WindowData window_data,
183+
Settings settings,
184+
fml::RefPtr<const DartSnapshot> isolate_snapshot,
185+
Shell::CreateCallback<PlatformView> on_create_platform_view,
186+
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
187+
if (!task_runners.IsValid()) {
188+
FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
189+
return false;
190+
}
191+
192+
auto shell =
193+
std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
194+
195+
// Create the rasterizer on the GPU thread.
196+
auto rasterizer_promise =
197+
std::make_shared<std::promise<std::unique_ptr<Rasterizer>>>();
198+
199+
fml::TaskRunner::RunNowOrPostTask(
200+
task_runners.GetRasterTaskRunner(),
201+
[rasterizer_promise,
202+
on_create_rasterizer = std::move(on_create_rasterizer), //
203+
shell = shell.get() //
204+
]() mutable {
205+
TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
206+
std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
207+
rasterizer_promise->set_value(std::move(rasterizer));
208+
});
209+
210+
// Create the platform view on the platform thread (this thread).
211+
auto platform_view = on_create_platform_view(*shell.get());
212+
if (!platform_view || !platform_view->GetWeakPtr()) {
213+
return false;
214+
}
215+
216+
// Ask the platform view for the vsync waiter. This will be used by the engine
217+
// to create the animator.
218+
auto vsync_waiter = platform_view->CreateVSyncWaiter();
219+
if (!vsync_waiter) {
220+
return false;
221+
}
222+
223+
// Create the IO manager on the IO thread. The IO manager must be initialized
224+
// first because it has state that the other subsystems depend on. It must
225+
// first be booted and the necessary references obtained to initialize the
226+
// other subsystems.
227+
auto io_manager_promise =
228+
std::make_shared<std::promise<std::unique_ptr<ShellIOManager>>>();
229+
auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
230+
231+
fml::TaskRunner::RunNowOrPostTask(
232+
io_task_runner,
233+
[io_task_runner,
234+
io_manager_promise, //
235+
weak_platform_view = platform_view->GetWeakPtr(), //
236+
is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch() //
237+
]() mutable {
238+
TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
239+
auto io_manager = std::make_unique<ShellIOManager>(
240+
weak_platform_view.getUnsafe()->CreateResourceContext(),
241+
is_backgrounded_sync_switch, io_task_runner);
242+
io_manager_promise->set_value(std::move(io_manager));
243+
});
244+
245+
// Send dispatcher_maker to the engine constructor because shell won't have
246+
// platform_view set until Shell::Setup is called later.
247+
auto dispatcher_maker = platform_view->GetDispatcherMaker();
248+
249+
// Create the engine on the UI thread.
250+
fml::TaskRunner::RunNowOrPostTask(
251+
shell->GetTaskRunners().GetUITaskRunner(),
252+
fml::MakeCopyable(
253+
[shell = std::move(shell), //
254+
platform_view = std::move(platform_view),
255+
async_init_callback = std::move(async_init_callback), //
256+
dispatcher_in = std::move(dispatcher_maker), //
257+
window_data = std::move(window_data), //
258+
isolate_snapshot = std::move(isolate_snapshot), //
259+
vsync_waiter = std::move(vsync_waiter), //
260+
io_manager_promise, //
261+
// io_manager_future, //
262+
// rasterizer_future,
263+
rasterizer_promise //
264+
]() mutable {
265+
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
266+
const auto& task_runners = shell->GetTaskRunners();
267+
268+
// The animator is owned by the UI thread but it gets its vsync
269+
// pulses from the platform.
270+
auto animator = std::make_unique<Animator>(*shell, task_runners,
271+
std::move(vsync_waiter));
272+
273+
// wait params(io、gpu task end)
274+
auto rasterizer = rasterizer_promise->get_future().get();
275+
auto snapshot_delegate = rasterizer->GetSnapshotDelegate();
276+
auto io_manager = io_manager_promise->get_future().get();
277+
auto unref_queue = io_manager->GetSkiaUnrefQueue();
278+
279+
auto engine_ref =
280+
std::make_unique<Engine>(*(shell.get()), //
281+
dispatcher_in, //
282+
*shell->GetDartVM(), //
283+
std::move(isolate_snapshot), //
284+
task_runners, //
285+
window_data, //
286+
shell->GetSettings(), //
287+
std::move(animator), //
288+
io_manager->GetWeakPtr(), //
289+
std::move(unref_queue), //
290+
std::move(snapshot_delegate) //
291+
);
292+
293+
fml::TaskRunner::RunNowOrPostTask(
294+
shell->GetTaskRunners().GetPlatformTaskRunner(),
295+
fml::MakeCopyable(
296+
[async_init_callback = std::move(async_init_callback),
297+
shell = std::move(shell),
298+
platform_view = std::move(platform_view),
299+
rasterizer = std::move(rasterizer),
300+
io_manager = std::move(io_manager),
301+
engine = std::move(engine_ref)]() mutable {
302+
if (!shell->Setup(std::move(platform_view), //
303+
std::move(engine), //
304+
std::move(rasterizer), //
305+
std::move(io_manager)) //
306+
) {
307+
async_init_callback(false, nullptr);
308+
} else {
309+
async_init_callback(true, std::move(shell));
310+
}
311+
}));
312+
}));
313+
return true;
314+
}
315+
178316
static void RecordStartupTimestamp() {
179317
if (engine_main_enter_ts == 0) {
180318
engine_main_enter_ts = Dart_TimelineGetMicros();
@@ -240,6 +378,58 @@ static void PerformInitializationTasks(const Settings& settings) {
240378
});
241379
}
242380

381+
void Shell::CreateAsync(
382+
ShellCreateCallback create_callback,
383+
TaskRunners task_runners,
384+
WindowData window_data,
385+
Settings settings,
386+
Shell::CreateCallback<PlatformView> on_create_platform_view,
387+
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
388+
if (!create_callback) {
389+
FML_CHECK(create_callback) << "CreateAsync: create_callback must be vaild!";
390+
return;
391+
}
392+
PerformInitializationTasks(settings);
393+
PersistentCache::SetCacheSkSL(settings.cache_sksl);
394+
395+
TRACE_EVENT0("flutter", "Shell::CreateAsync");
396+
397+
auto vm = DartVMRef::Create(settings);
398+
FML_CHECK(vm) << "Must be able to initialize the VM.";
399+
400+
auto vm_data = vm->GetVMData();
401+
402+
if (!task_runners.IsValid() || !on_create_platform_view ||
403+
!on_create_rasterizer) {
404+
create_callback(false, nullptr);
405+
return;
406+
}
407+
auto isolate_snapshot = vm_data->GetIsolateSnapshot();
408+
fml::TaskRunner::RunNowOrPostTask(
409+
task_runners.GetPlatformTaskRunner(),
410+
fml::MakeCopyable(
411+
[vm = std::move(vm), //
412+
create_callback = std::move(create_callback), //
413+
task_runners = std::move(task_runners), //
414+
window_data = std::move(window_data), //
415+
settings = std::move(settings), //
416+
isolate_snapshot = std::move(isolate_snapshot), //
417+
on_create_platform_view = std::move(on_create_platform_view), //
418+
on_create_rasterizer = std::move(on_create_rasterizer) //
419+
]() mutable {
420+
CreateShellAsyncOnPlatformThread(
421+
std::move(create_callback), //
422+
std::move(vm), //
423+
std::move(task_runners), //
424+
std::move(window_data), //
425+
std::move(settings), //
426+
std::move(isolate_snapshot), //
427+
std::move(on_create_platform_view), //
428+
std::move(on_create_rasterizer) //
429+
);
430+
}));
431+
}
432+
243433
std::unique_ptr<Shell> Shell::Create(
244434
TaskRunners task_runners,
245435
Settings settings,

shell/common/shell.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class Shell final : public PlatformView::Delegate,
9595
public:
9696
template <class T>
9797
using CreateCallback = std::function<std::unique_ptr<T>(Shell&)>;
98+
using ShellCreateCallback =
99+
std::function<void(bool success, std::unique_ptr<Shell> shell)>;
98100

99101
//----------------------------------------------------------------------------
100102
/// @brief Creates a shell instance using the provided settings. The
@@ -166,6 +168,13 @@ class Shell final : public PlatformView::Delegate,
166168
CreateCallback<PlatformView> on_create_platform_view,
167169
CreateCallback<Rasterizer> on_create_rasterizer);
168170

171+
static void CreateAsync(ShellCreateCallback callBack,
172+
TaskRunners task_runners,
173+
WindowData window_data,
174+
Settings settings,
175+
CreateCallback<PlatformView> on_create_platform_view,
176+
CreateCallback<Rasterizer> on_create_rasterizer);
177+
169178
//----------------------------------------------------------------------------
170179
/// @brief Creates a shell instance using the provided settings. The
171180
/// callbacks to create the various shell subcomponents will be
@@ -431,6 +440,16 @@ class Shell final : public PlatformView::Delegate,
431440
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
432441
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer);
433442

443+
static bool CreateShellAsyncOnPlatformThread(
444+
ShellCreateCallback async_init_callback,
445+
DartVMRef vm,
446+
TaskRunners task_runners,
447+
WindowData window_data,
448+
Settings settings,
449+
fml::RefPtr<const DartSnapshot> isolate_snapshot,
450+
Shell::CreateCallback<PlatformView> on_create_platform_view,
451+
Shell::CreateCallback<Rasterizer> on_create_rasterizer);
452+
434453
bool Setup(std::unique_ptr<PlatformView> platform_view,
435454
std::unique_ptr<Engine> engine,
436455
std::unique_ptr<Rasterizer> rasterizer,

shell/common/shell_benchmarks.cc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,79 @@ static void StartupAndShutdownShell(benchmark::State& state,
8181
FML_CHECK(!shell);
8282
}
8383

84+
static void StartupAsync(benchmark::State& state, bool mesure_async_total) {
85+
auto assets_dir = fml::OpenDirectory(testing::GetFixturesPath(), false,
86+
fml::FilePermission::kRead);
87+
std::unique_ptr<Shell> shell_res;
88+
std::unique_ptr<ThreadHost> thread_host;
89+
testing::ELFAOTSymbols aot_symbols;
90+
{
91+
Settings settings = {};
92+
settings.task_observer_add = [](intptr_t, fml::closure) {};
93+
settings.task_observer_remove = [](intptr_t) {};
94+
95+
if (DartVM::IsRunningPrecompiledCode()) {
96+
aot_symbols = testing::LoadELFSymbolFromFixturesIfNeccessary();
97+
FML_CHECK(
98+
testing::PrepareSettingsForAOTWithSymbols(settings, aot_symbols))
99+
<< "Could not setup settings with AOT symbols.";
100+
} else {
101+
settings.application_kernels = [&]() {
102+
std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
103+
kernel_mappings.emplace_back(
104+
fml::FileMapping::CreateReadOnly(assets_dir, "kernel_blob.bin"));
105+
return kernel_mappings;
106+
};
107+
}
108+
109+
thread_host = std::make_unique<ThreadHost>(
110+
"io.flutter.bench.", ThreadHost::Type::Platform |
111+
ThreadHost::Type::GPU | ThreadHost::Type::IO |
112+
ThreadHost::Type::UI);
113+
114+
TaskRunners task_runners("test",
115+
thread_host->platform_thread->GetTaskRunner(),
116+
thread_host->raster_thread->GetTaskRunner(),
117+
thread_host->ui_thread->GetTaskRunner(),
118+
thread_host->io_thread->GetTaskRunner());
119+
120+
fml::AutoResetWaitableEvent latch;
121+
Shell::CreateAsync(
122+
[&latch, &shell_res](bool success, std::unique_ptr<Shell> shell) {
123+
if (success) {
124+
shell_res = std::move(shell);
125+
}
126+
latch.Signal();
127+
},
128+
std::move(task_runners), WindowData{/* default window data */},
129+
settings,
130+
[](Shell& shell) {
131+
return std::make_unique<PlatformView>(shell, shell.GetTaskRunners());
132+
},
133+
[](Shell& shell) {
134+
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
135+
});
136+
benchmarking::ScopedPauseTiming pause(state, !mesure_async_total);
137+
latch.Wait();
138+
FML_CHECK(shell_res);
139+
}
140+
{
141+
// dont' care shutdown time here
142+
benchmarking::ScopedPauseTiming pause(state, true);
143+
// Shutdown must occur synchronously on the platform thread.
144+
fml::AutoResetWaitableEvent latch;
145+
fml::TaskRunner::RunNowOrPostTask(
146+
thread_host->platform_thread->GetTaskRunner(),
147+
[&shell_res, &latch]() mutable {
148+
shell_res.reset();
149+
latch.Signal();
150+
});
151+
latch.Wait();
152+
thread_host.reset();
153+
}
154+
FML_CHECK(!shell_res);
155+
}
156+
84157
static void BM_ShellInitialization(benchmark::State& state) {
85158
while (state.KeepRunning()) {
86159
StartupAndShutdownShell(state, true, false);
@@ -105,4 +178,18 @@ static void BM_ShellInitializationAndShutdown(benchmark::State& state) {
105178

106179
BENCHMARK(BM_ShellInitializationAndShutdown);
107180

181+
static void BM_ShellInitializationAsyncLockTime(benchmark::State& state) {
182+
while (state.KeepRunning()) {
183+
StartupAsync(state, false);
184+
}
185+
}
186+
BENCHMARK(BM_ShellInitializationAsyncLockTime);
187+
188+
static void BM_ShellInitializationAsyncTotalTime(benchmark::State& state) {
189+
while (state.KeepRunning()) {
190+
StartupAsync(state, true);
191+
}
192+
}
193+
BENCHMARK(BM_ShellInitializationAsyncTotalTime);
194+
108195
} // namespace flutter

0 commit comments

Comments
 (0)