diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 976d1befb37b5..130c6c5b06bcd 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -39,7 +39,8 @@ constexpr char kSystemChannel[] = "flutter/system"; constexpr char kTypeKey[] = "type"; constexpr char kFontChange[] = "fontsChange"; -std::unique_ptr Shell::CreateShellOnPlatformThread( +void Shell::CreateShellOnPlatformThread( + std::promise> shell_holder_promise, DartVMRef vm, TaskRunners task_runners, const WindowData window_data, @@ -47,54 +48,58 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( fml::RefPtr isolate_snapshot, const Shell::CreateCallback& on_create_platform_view, const Shell::CreateCallback& on_create_rasterizer) { + FML_CHECK(task_runners.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()) + << "CreateShellOnPlatformThread() must run in platformThread!"; if (!task_runners.IsValid()) { FML_LOG(ERROR) << "Task runners to run the shell were invalid."; - return nullptr; + shell_holder_promise.set_value(nullptr); + return; } auto shell = std::unique_ptr(new Shell(std::move(vm), task_runners, settings)); // Create the rasterizer on the raster thread. - std::promise> rasterizer_promise; - auto rasterizer_future = rasterizer_promise.get_future(); - std::promise> snapshot_delegate_promise; - auto snapshot_delegate_future = snapshot_delegate_promise.get_future(); + auto rasterizer_promise = + std::make_shared>>(); + auto snapshot_delegate_promise = + std::make_shared>>(); + fml::TaskRunner::RunNowOrPostTask( - task_runners.GetRasterTaskRunner(), [&rasterizer_promise, // - &snapshot_delegate_promise, - on_create_rasterizer, // - shell = shell.get() // - ]() { + task_runners.GetRasterTaskRunner(), + [rasterizer_promise, snapshot_delegate_promise, + on_create_rasterizer, // + shell = shell.get() // + ]() mutable { TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem"); std::unique_ptr rasterizer(on_create_rasterizer(*shell)); - snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate()); - rasterizer_promise.set_value(std::move(rasterizer)); + snapshot_delegate_promise->set_value(rasterizer->GetSnapshotDelegate()); + rasterizer_promise->set_value(std::move(rasterizer)); }); // Create the platform view on the platform thread (this thread). auto platform_view = on_create_platform_view(*shell.get()); if (!platform_view || !platform_view->GetWeakPtr()) { - return nullptr; + shell_holder_promise.set_value(nullptr); + return; } // Ask the platform view for the vsync waiter. This will be used by the engine // to create the animator. auto vsync_waiter = platform_view->CreateVSyncWaiter(); if (!vsync_waiter) { - return nullptr; + shell_holder_promise.set_value(nullptr); + return; } // Create the IO manager on the IO thread. The IO manager must be initialized // first because it has state that the other subsystems depend on. It must // first be booted and the necessary references obtained to initialize the // other subsystems. - std::promise> io_manager_promise; - auto io_manager_future = io_manager_promise.get_future(); - std::promise> weak_io_manager_promise; - auto weak_io_manager_future = weak_io_manager_promise.get_future(); - std::promise> unref_queue_promise; - auto unref_queue_future = unref_queue_promise.get_future(); + auto io_manager_promise = + std::make_shared>>(); + auto weak_io_manager_promise = + std::make_shared>>(); auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner(); // TODO(gw280): The WeakPtr here asserts that we are derefing it on the @@ -105,20 +110,16 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( // https://github.com/flutter/flutter/issues/42948 fml::TaskRunner::RunNowOrPostTask( io_task_runner, - [&io_manager_promise, // - &weak_io_manager_promise, // - &unref_queue_promise, // - platform_view = platform_view->GetWeakPtr(), // - io_task_runner, // + [io_task_runner, io_manager_promise, weak_io_manager_promise, + weak_platform_view = platform_view->GetWeakPtr(), // is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch() // - ]() { + ]() mutable { TRACE_EVENT0("flutter", "ShellSetupIOSubsystem"); auto io_manager = std::make_unique( - platform_view.getUnsafe()->CreateResourceContext(), + weak_platform_view.getUnsafe()->CreateResourceContext(), is_backgrounded_sync_switch, io_task_runner); - weak_io_manager_promise.set_value(io_manager->GetWeakPtr()); - unref_queue_promise.set_value(io_manager->GetSkiaUnrefQueue()); - io_manager_promise.set_value(std::move(io_manager)); + weak_io_manager_promise->set_value(io_manager->GetWeakPtr()); + io_manager_promise->set_value(std::move(io_manager)); }); // Send dispatcher_maker to the engine constructor because shell won't have @@ -126,52 +127,53 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( auto dispatcher_maker = platform_view->GetDispatcherMaker(); // Create the engine on the UI thread. - std::promise> engine_promise; - auto engine_future = engine_promise.get_future(); fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetUITaskRunner(), - fml::MakeCopyable([&engine_promise, // - shell = shell.get(), // - &dispatcher_maker, // - &window_data, // + fml::MakeCopyable([shell = std::move(shell), // + shell_holder_promise = std::move(shell_holder_promise), + platform_view = std::move(platform_view), + dispatcher_in = std::move(dispatcher_maker), // + window_data = std::move(window_data), // isolate_snapshot = std::move(isolate_snapshot), // vsync_waiter = std::move(vsync_waiter), // - &weak_io_manager_future, // - &snapshot_delegate_future, // - &unref_queue_future // - ]() mutable { + io_manager_promise, // + rasterizer_promise, // + weak_io_manager_promise, // + snapshot_delegate_promise]() mutable { TRACE_EVENT0("flutter", "ShellSetupUISubsystem"); const auto& task_runners = shell->GetTaskRunners(); - // The animator is owned by the UI thread but it gets its vsync pulses - // from the platform. + // The animator is owned by the UI thread but it gets its vsync + // pulses from the platform. auto animator = std::make_unique(*shell, task_runners, std::move(vsync_waiter)); - engine_promise.set_value(std::make_unique( - *shell, // - dispatcher_maker, // - *shell->GetDartVM(), // - std::move(isolate_snapshot), // - task_runners, // - window_data, // - shell->GetSettings(), // - std::move(animator), // - weak_io_manager_future.get(), // - unref_queue_future.get(), // - snapshot_delegate_future.get() // - )); + // wait params(io、gpu task end) + auto rasterizer = rasterizer_promise->get_future().get(); + auto snapshot_delegate = snapshot_delegate_promise->get_future().get(); + auto io_manager = io_manager_promise->get_future().get(); + auto weak_io_manager = weak_io_manager_promise->get_future().get(); + + auto unref_queue = io_manager->GetSkiaUnrefQueue(); + + auto engine_ref = + std::make_unique(*(shell.get()), // + dispatcher_in, // + *shell->GetDartVM(), // + std::move(isolate_snapshot), // + task_runners, // + window_data, // + shell->GetSettings(), // + std::move(animator), // + std::move(weak_io_manager), // + std::move(unref_queue), // + std::move(snapshot_delegate) // + ); + shell_holder_promise.set_value(std::make_unique( + std::move(shell), std::move(platform_view), std::move(engine_ref), + std::move(rasterizer), std::move(io_manager))); })); - - if (!shell->Setup(std::move(platform_view), // - engine_future.get(), // - rasterizer_future.get(), // - io_manager_future.get()) // - ) { - return nullptr; - } - - return shell; + return; } static void Tokenize(const std::string& input, @@ -249,6 +251,21 @@ std::unique_ptr Shell::Create( ); } +std::future> Shell::CreateShellHolder( + std::unique_ptr params) { + PerformInitializationTasks(params->settings); + PersistentCache::SetCacheSkSL(params->settings.cache_sksl); + TRACE_EVENT0("flutter", "Shell::Create"); + auto vm = DartVMRef::Create(params->settings); + FML_CHECK(vm) << "Must be able to initialize the VM."; + auto vm_data = vm->GetVMData(); + return Shell::InitShellEnv( + std::move(params->task_runners), std::move(params->window_data), + std::move(params->settings), vm_data->GetIsolateSnapshot(), + std::move(params->on_create_platform_view), + std::move(params->on_create_rasterizer), std::move(vm)); +} + std::unique_ptr Shell::Create( TaskRunners task_runners, const WindowData window_data, @@ -283,6 +300,38 @@ std::unique_ptr Shell::Create( const Shell::CreateCallback& on_create_platform_view, const Shell::CreateCallback& on_create_rasterizer, DartVMRef vm) { + auto shell_holder_future = Shell::InitShellEnv( + std::move(task_runners), window_data, settings, + std::move(isolate_snapshot), std::move(on_create_platform_view), + std::move(on_create_rasterizer), std::move(vm)); + auto shell_holder = shell_holder_future.get(); + if (!shell_holder) { + return nullptr; + } + + fml::AutoResetWaitableEvent latch; + std::unique_ptr shell; + fml::TaskRunner::RunNowOrPostTask( + task_runners.GetPlatformTaskRunner(), + fml::MakeCopyable([&latch, &shell, &shell_holder + + ]() mutable { + shell = Shell::MakeShellFromHolder(std::move(shell_holder)); + latch.Signal(); + })); + latch.Wait(); + + return shell; +} + +std::future> Shell::InitShellEnv( + TaskRunners task_runners, + const WindowData window_data, + Settings settings, + fml::RefPtr isolate_snapshot, + const Shell::CreateCallback& on_create_platform_view, + const Shell::CreateCallback& on_create_rasterizer, + DartVMRef vm) { PerformInitializationTasks(settings); PersistentCache::SetCacheSkSL(settings.cache_sksl); @@ -290,16 +339,19 @@ std::unique_ptr Shell::Create( if (!task_runners.IsValid() || !on_create_platform_view || !on_create_rasterizer) { - return nullptr; + std::promise> shell_holder_promise; + shell_holder_promise.set_value(nullptr); + return shell_holder_promise.get_future(); } - fml::AutoResetWaitableEvent latch; - std::unique_ptr shell; + // fml::AutoResetWaitableEvent latch; + std::promise> shell_holder_promise; + auto shell_holder_future = shell_holder_promise.get_future(); + fml::TaskRunner::RunNowOrPostTask( task_runners.GetPlatformTaskRunner(), - fml::MakeCopyable([&latch, // + fml::MakeCopyable([shell_holder_promise = std::move(shell_holder_promise), vm = std::move(vm), // - &shell, // task_runners = std::move(task_runners), // window_data, // settings, // @@ -307,18 +359,17 @@ std::unique_ptr Shell::Create( on_create_platform_view, // on_create_rasterizer // ]() mutable { - shell = CreateShellOnPlatformThread(std::move(vm), - std::move(task_runners), // - window_data, // - settings, // - std::move(isolate_snapshot), // - on_create_platform_view, // - on_create_rasterizer // + CreateShellOnPlatformThread(std::move(shell_holder_promise), + std::move(vm), // + std::move(task_runners), // + window_data, // + settings, // + std::move(isolate_snapshot), // + on_create_platform_view, // + on_create_rasterizer // ); - latch.Signal(); })); - latch.Wait(); - return shell; + return shell_holder_future; } Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings) @@ -1537,4 +1588,16 @@ std::shared_ptr Shell::GetIsGpuDisabledSyncSwitch() const { return is_gpu_disabled_sync_switch_; } +std::unique_ptr Shell::MakeShellFromHolder( + std::unique_ptr holder) { + FML_CHECK(holder->shell->GetTaskRunners() + .GetPlatformTaskRunner() + ->RunsTasksOnCurrentThread()) + << "MakeShellFromHolder() must run in platformThread!"; + holder->shell->Setup(std::move(holder->platform_view), + std::move(holder->engine), std::move(holder->rasterizer), + std::move(holder->io_manager)); + return std::move(holder->shell); +} + } // namespace flutter diff --git a/shell/common/shell.h b/shell/common/shell.h index fd1a30d3f4e35..f7c89f7924463 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -48,6 +48,7 @@ enum class DartErrorCode { /// The Dart error code for an unkonwn error. UnknownError = 255 }; +struct ShellCreateParams; //------------------------------------------------------------------------------ /// Perhaps the single most important class in the Flutter engine repository. @@ -96,6 +97,46 @@ class Shell final : public PlatformView::Delegate, template using CreateCallback = std::function(Shell&)>; + ///---------------------------------------------------------------------------- + /// Used by method `CreateShellHolder`,Provide synchronous and asynchronous + /// initialization methods. + /// auto shell_holder_future = Shell::CreateShellHolder(...); + /// 1.synchronous + /// auto shell_holder = shell_holder_future.get(); + /// //must run in platformThread + /// auto shell = Shell::MakeShellFromHolder(std::move(shell_holder)); + /// 2.asynchronous + /// std::async(std::launch::async,[](){ + /// auto shell_holder = shell_holder_future.get(); + /// fml::TaskRunner::RunNowOrPostTask(task_runners.GetPlatformTaskRunner(),[](){ + /// auto shell = + /// Shell::MakeShellFromHolder(std::move(shell_holder)); + /// }); + /// }); + /// + class ShellHolder { + public: + ShellHolder(std::unique_ptr shell_ref, + std::unique_ptr platform_view_ref, + std::unique_ptr engine_ref, + std::unique_ptr rasterizer_ref, + std::unique_ptr io_manager_ref) + : shell(std::move(shell_ref)), + platform_view(std::move(platform_view_ref)), + engine(std::move(engine_ref)), + rasterizer(std::move(rasterizer_ref)), + io_manager(std::move(io_manager_ref)) {} + + private: + /// shell has not been Setup. + std::unique_ptr shell; + std::unique_ptr platform_view; + std::unique_ptr engine; + std::unique_ptr rasterizer; + std::unique_ptr io_manager; + friend Shell; + }; + //---------------------------------------------------------------------------- /// @brief Creates a shell instance using the provided settings. The /// callbacks to create the various shell subcomponents will be @@ -210,6 +251,25 @@ class Shell final : public PlatformView::Delegate, const CreateCallback& on_create_rasterizer, DartVMRef vm); + //---------------------------------------------------------------------------- + /// @brief Creates a shell instance asynchronously using the provided + /// params. + /// + /// @param[in] params shell init params + /// + /// @return future with shell which is full initialized or null if the params + /// are valid + + static std::future> CreateShellHolder( + std::unique_ptr params); + + //---------------------------------------------------------------------------- + /// @brief return full init shell. (call `shell.setup` on + /// platformThread) + /// must run in platfromThread , else abort + static std::unique_ptr MakeShellFromHolder( + std::unique_ptr holder); + //---------------------------------------------------------------------------- /// @brief Destroys the shell. This is a synchronous operation and /// synchronous barrier blocks are introduced on the various @@ -423,7 +483,8 @@ class Shell final : public PlatformView::Delegate, Shell(DartVMRef vm, TaskRunners task_runners, Settings settings); - static std::unique_ptr CreateShellOnPlatformThread( + static void CreateShellOnPlatformThread( + std::promise> shell_holder_promise, DartVMRef vm, TaskRunners task_runners, const WindowData window_data, @@ -432,6 +493,15 @@ class Shell final : public PlatformView::Delegate, const Shell::CreateCallback& on_create_platform_view, const Shell::CreateCallback& on_create_rasterizer); + static std::future> InitShellEnv( + TaskRunners task_runners, + const WindowData window_data, + Settings settings, + fml::RefPtr isolate_snapshot, + const CreateCallback& on_create_platform_view, + const CreateCallback& on_create_rasterizer, + DartVMRef vm); + bool Setup(std::unique_ptr platform_view, std::unique_ptr engine, std::unique_ptr rasterizer, @@ -595,6 +665,36 @@ class Shell final : public PlatformView::Delegate, FML_DISALLOW_COPY_AND_ASSIGN(Shell); }; +//---------------------------------------------------------------------------- +/// @brief shell init params, used by create method +struct ShellCreateParams { + // The task runners + TaskRunners task_runners; + // The default data for setting up ui.Window that attached to this intance. + WindowData window_data; + // The settings + Settings settings; + // The callback that must return a platform view. This will be called on the + // platform task runner before this method returns + Shell::CreateCallback on_create_platform_view; + // valid rasterizer. This will be called on the render task runner before + // thismethod returns. + Shell::CreateCallback on_create_rasterizer; + + ShellCreateParams( + flutter::TaskRunners task_runners, + flutter::WindowData window_data, + flutter::Settings settings, + flutter::Shell::CreateCallback + on_create_platform_view, + flutter::Shell::CreateCallback on_create_rasterizer) + : task_runners(std::move(task_runners)), + window_data(window_data), + settings(settings), + on_create_platform_view(std::move(on_create_platform_view)), + on_create_rasterizer(std::move(on_create_rasterizer)) {} +}; + } // namespace flutter #endif // SHELL_COMMON_SHELL_H_ diff --git a/shell/common/shell_benchmarks.cc b/shell/common/shell_benchmarks.cc index 01c39d192fbd6..ada4e45ba46ea 100644 --- a/shell/common/shell_benchmarks.cc +++ b/shell/common/shell_benchmarks.cc @@ -4,6 +4,7 @@ #include "flutter/benchmarking/benchmarking.h" #include "flutter/fml/logging.h" +#include "flutter/fml/make_copyable.h" #include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" @@ -98,6 +99,89 @@ static void StartupAndShutdownShell(benchmark::State& state, FML_CHECK(!shell); } +static void StartupAsync(benchmark::State& state, bool mesure_async_total) { + auto assets_dir = fml::OpenDirectory(testing::GetFixturesPath(), false, + fml::FilePermission::kRead); + std::unique_ptr shell_res; + std::unique_ptr thread_host; + testing::ELFAOTSymbols aot_symbols; + { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fml::closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + + if (DartVM::IsRunningPrecompiledCode()) { + aot_symbols = testing::LoadELFSymbolFromFixturesIfNeccessary(); + FML_CHECK( + testing::PrepareSettingsForAOTWithSymbols(settings, aot_symbols)) + << "Could not setup 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( + "io.flutter.bench.", ThreadHost::Type::Platform | + ThreadHost::Type::GPU | ThreadHost::Type::IO | + ThreadHost::Type::UI); + + TaskRunners task_runners("test", + thread_host->platform_thread->GetTaskRunner(), + thread_host->raster_thread->GetTaskRunner(), + thread_host->ui_thread->GetTaskRunner(), + thread_host->io_thread->GetTaskRunner()); + + auto shell_holder_future = + Shell::CreateShellHolder(std::make_unique( + std::move(task_runners), WindowData{/* default window data */}, + settings, + [](Shell& shell) { + return std::make_unique(shell, + shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique( + shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); + })); + std::unique_ptr shell_holder; + { + benchmarking::ScopedPauseTiming pause(state, !mesure_async_total); + shell_holder = shell_holder_future.get(); + } + fml::AutoResetWaitableEvent latch; + + fml::TaskRunner::RunNowOrPostTask( + task_runners.GetPlatformTaskRunner(), + fml::MakeCopyable([&latch, &shell_res, &shell_holder]() mutable { + shell_res = Shell::MakeShellFromHolder(std::move(shell_holder)); + latch.Signal(); + })); + latch.Wait(); + + FML_CHECK(shell_res); + } + { + // don't care shutdown time here + benchmarking::ScopedPauseTiming pause(state, true); + // Shutdown must occur synchronously on the platform thread. + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + thread_host->platform_thread->GetTaskRunner(), + [&shell_res, &latch]() mutable { + shell_res.reset(); + latch.Signal(); + }); + latch.Wait(); + thread_host.reset(); + } + FML_CHECK(!shell_res); +} + static void BM_ShellInitialization(benchmark::State& state) { while (state.KeepRunning()) { StartupAndShutdownShell(state, true, false); @@ -122,4 +206,18 @@ static void BM_ShellInitializationAndShutdown(benchmark::State& state) { BENCHMARK(BM_ShellInitializationAndShutdown); +static void BM_ShellInitializationAsyncbBLockTime(benchmark::State& state) { + while (state.KeepRunning()) { + StartupAsync(state, false); + } +} +BENCHMARK(BM_ShellInitializationAsyncbBLockTime); + +static void BM_ShellInitializationAsyncTotalTime(benchmark::State& state) { + while (state.KeepRunning()) { + StartupAsync(state, true); + } +} +BENCHMARK(BM_ShellInitializationAsyncTotalTime); + } // namespace flutter diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index a2b04b8a44543..918ed0a94dbb9 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -154,6 +154,67 @@ TEST_F(ShellTest, ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } +TEST_F(ShellTest, + AsyncInitializeWithMultipleThreadButCallingThreadAsPlatformThread) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::GPU | ThreadHost::Type::IO | + ThreadHost::Type::UI | ThreadHost::Type::Platform); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + + auto shell_holder_future = + Shell::CreateShellHolder(std::make_unique( + task_runners, WindowData{/* default window data */}, settings, + [](Shell& shell) { + const auto vsync_clock = std::make_shared(); + return ShellTestPlatformView::Create( + shell, shell.GetTaskRunners(), vsync_clock, + [task_runners = shell.GetTaskRunners()]() { + return static_cast>( + std::make_unique(task_runners)); + }, + ShellTestPlatformView::BackendType::kDefaultBackend, nullptr); + }, + [](Shell& shell) { + return std::make_unique( + shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); + })); + + fml::AutoResetWaitableEvent latch; + auto handle = std::async( + std::launch::async, + fml::MakeCopyable([shell_test_point = this, &latch, task_runners, + shell_holder_future = + std::move(shell_holder_future)]() mutable { + // wait + auto shell_holder = shell_holder_future.get(); + // check shell_res on platformthread + auto lambda_shell_res = fml::MakeCopyable( + [shell_test_point, &latch, task_runners, + shell_holder = std::move(shell_holder)]() mutable { + auto shell_res = + Shell::MakeShellFromHolder(std::move(shell_holder)); + ASSERT_TRUE(ValidateShell(shell_res.get())); + ASSERT_TRUE(DartVMRef::IsInstanceRunning()); + shell_test_point->DestroyShell(std::move(shell_res), + std::move(task_runners)); + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + latch.Signal(); + }); + fml::TaskRunner::RunNowOrPostTask(task_runners.GetPlatformTaskRunner(), + std::move(lambda_shell_res)); + })); + + latch.Wait(); + handle.get(); +} + TEST_F(ShellTest, InitializeWithGPUAndPlatformThreadsTheSame) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture();