// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/shell/common/shell.h" #include "flutter/benchmarking/benchmarking.h" #include "flutter/fml/logging.h" #include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/thread_host.h" #include "flutter/testing/elf_loader.h" #include "flutter/testing/testing.h" namespace flutter { static void StartupAndShutdownShell(benchmark::State& state, bool measure_startup, bool measure_shutdown) { auto assets_dir = fml::OpenDirectory(testing::GetFixturesPath(), false, fml::FilePermission::kRead); std::unique_ptr shell; std::unique_ptr thread_host; testing::ELFAOTSymbols aot_symbols; { benchmarking::ScopedPauseTiming pause(state, !measure_startup); Settings settings = {}; settings.task_observer_add = [](intptr_t, const fml::closure&) {}; settings.task_observer_remove = [](intptr_t) {}; if (DartVM::IsRunningPrecompiledCode()) { aot_symbols = testing::LoadELFSymbolFromFixturesIfNeccessary( testing::kDefaultAOTAppELFFileName); FML_CHECK( testing::PrepareSettingsForAOTWithSymbols(settings, aot_symbols)) << "Could not set up settings with AOT symbols."; } else { settings.application_kernels = [&]() { std::vector> kernel_mappings; kernel_mappings.emplace_back( fml::FileMapping::CreateReadOnly(assets_dir, "kernel_blob.bin")); return kernel_mappings; }; } thread_host = std::make_unique(ThreadHost::ThreadHostConfig( "io.flutter.bench.", ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster | ThreadHost::Type::kIo | ThreadHost::Type::kUi)); TaskRunners task_runners("test", thread_host->platform_thread->GetTaskRunner(), thread_host->raster_thread->GetTaskRunner(), thread_host->ui_thread->GetTaskRunner(), thread_host->io_thread->GetTaskRunner()); shell = Shell::Create( flutter::PlatformData(), task_runners, settings, [](Shell& shell) { return std::make_unique(shell, shell.GetTaskRunners()); }, [](Shell& shell) { return std::make_unique(shell); }); } FML_CHECK(shell); { // The ui thread could be busy processing tasks after shell created, e.g., // default font manager setup. The measurement of shell shutdown should be // considered after those ui tasks have been done. // // However, if we're measuring the complete time from startup to shutdown, // this time should still be included. benchmarking::ScopedPauseTiming pause( state, !measure_shutdown || !measure_startup); fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask(thread_host->ui_thread->GetTaskRunner(), [&latch]() { latch.Signal(); }); latch.Wait(); } { benchmarking::ScopedPauseTiming pause(state, !measure_shutdown); // Shutdown must occur synchronously on the platform thread. fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( thread_host->platform_thread->GetTaskRunner(), [&shell, &latch]() mutable { shell.reset(); latch.Signal(); }); latch.Wait(); thread_host.reset(); } FML_CHECK(!shell); } static void BM_ShellInitialization(benchmark::State& state) { while (state.KeepRunning()) { StartupAndShutdownShell(state, true, false); } } BENCHMARK(BM_ShellInitialization); static void BM_ShellShutdown(benchmark::State& state) { while (state.KeepRunning()) { StartupAndShutdownShell(state, false, true); } } BENCHMARK(BM_ShellShutdown); static void BM_ShellInitializationAndShutdown(benchmark::State& state) { while (state.KeepRunning()) { StartupAndShutdownShell(state, true, true); } } BENCHMARK(BM_ShellInitializationAndShutdown); } // namespace flutter