Skip to content

Commit

Permalink
Allow spawning additional UI isolates in flutter_tester (flutter#48706)
Browse files Browse the repository at this point in the history
This enables work ongoing by @derekxu16 to improve performance in flutter_tester when running multiple files from large test suites.

Specifically, it:

- Exposes a `Spawn` C symbol from flutter_tester that runs the current kernel in a new UI isolate with a different entrypoint and/or route name
- Exposes two symbols from flutter_tester to allow a test harness to more efficiently load particular kernel files or to lookup an entrypoint from an imported source file.
- Avoids re-loading the kernel file completely when spawning a new UI isolate

Googlers can look at go/flutter-tester-isolates for some more context. If anyone wants I'm happy to create a public version of that doc.
  • Loading branch information
dnfield authored Jan 5, 2024
1 parent f3496a7 commit edbce21
Show file tree
Hide file tree
Showing 17 changed files with 329 additions and 30 deletions.
17 changes: 17 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ config("export_dynamic_symbols") {
}
}

config("export_dynamic_test_symbols") {
# See comment in :export_dynamic_symbols.
# This config exposes an additional symbol meant for flutter_tester.
if (is_linux || is_fuchsia) {
inputs = [ "//flutter/common/exported_test_symbols.sym" ]
ldflags = [ "-Wl,--dynamic-list=" + rebase_path(inputs[0], root_build_dir) ]
} else if (is_mac) {
inputs = [ "//flutter/common/exported_test_symbols_mac.sym" ]
ldflags = [
"-Xlinker",
"-exported_symbols_list",
"-Xlinker",
rebase_path(inputs[0], root_build_dir),
]
}
}

group("flutter") {
testonly = true

Expand Down
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -7414,6 +7414,8 @@ FILE: ../../../flutter/benchmarking/library.h
FILE: ../../../flutter/common/constants.h
FILE: ../../../flutter/common/exported_symbols.sym
FILE: ../../../flutter/common/exported_symbols_mac.sym
FILE: ../../../flutter/common/exported_test_symbols.sym
FILE: ../../../flutter/common/exported_test_symbols_mac.sym
FILE: ../../../flutter/common/graphics/gl_context_switch.cc
FILE: ../../../flutter/common/graphics/gl_context_switch.h
FILE: ../../../flutter/common/graphics/msaa_sample_count.h
Expand Down
13 changes: 13 additions & 0 deletions common/exported_test_symbols.sym
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# These symbols are looked up from within the executable at runtime and must
# be exported in the dynamic symbol table.
{
kDartVmSnapshotData;
kDartVmSnapshotInstructions;
kDartIsolateSnapshotData;
kDartIsolateSnapshotInstructions;
InternalFlutterGpu*;
kInternalFlutterGpu*;
Spawn;
LoadLibraryFromKernel;
LookupEntryPoint;
};
11 changes: 11 additions & 0 deletions common/exported_test_symbols_mac.sym
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# These symbols are looked up from within the executable at runtime and must
# be exported in the dynamic symbol table.
_kDartVmSnapshotData
_kDartVmSnapshotInstructions
_kDartIsolateSnapshotData
_kDartIsolateSnapshotInstructions
_InternalFlutterGpu*
_kInternalFlutterGpu*
_Spawn
_LoadLibraryFromKernel
_LookupEntryPoint
31 changes: 28 additions & 3 deletions runtime/dart_isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@ bool DartIsolate::LoadKernel(const std::shared_ptr<const fml::Mapping>& mapping,
return false;
}

// Mapping must be retained until isolate shutdown.
kernel_buffers_.push_back(mapping);
// Mapping must be retained until isolate group shutdown.
GetIsolateGroupData().AddKernelBuffer(mapping);

Dart_Handle library =
Dart_LoadLibraryFromKernel(mapping->GetMapping(), mapping->GetSize());
Expand Down Expand Up @@ -589,7 +589,8 @@ bool DartIsolate::LoadKernel(const std::shared_ptr<const fml::Mapping>& mapping,
// executed leads to crashes.
if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
GetIsolateGroupData().SetChildIsolatePreparer(
[buffers = kernel_buffers_](DartIsolate* isolate) {
[buffers =
GetIsolateGroupData().GetKernelBuffers()](DartIsolate* isolate) {
for (uint64_t i = 0; i < buffers.size(); i++) {
bool last_piece = i + 1 == buffers.size();
const std::shared_ptr<const fml::Mapping>& buffer = buffers.at(i);
Expand Down Expand Up @@ -1130,6 +1131,30 @@ Dart_Handle DartIsolate::OnDartLoadLibrary(intptr_t loading_unit_id) {
return Dart_NewApiError(error_message.c_str());
}

Dart_Handle DartIsolate::LoadLibraryFromKernel(
const std::shared_ptr<const fml::Mapping>& mapping) {
if (DartVM::IsRunningPrecompiledCode()) {
return Dart_Null();
}

auto* isolate_group_data =
static_cast<std::shared_ptr<DartIsolateGroupData>*>(
Dart_CurrentIsolateGroupData());
// Mapping must be retained until isolate shutdown.
(*isolate_group_data)->AddKernelBuffer(mapping);

auto lib =
Dart_LoadLibraryFromKernel(mapping->GetMapping(), mapping->GetSize());
if (tonic::CheckAndHandleError(lib)) {
return Dart_Null();
}
auto result = Dart_FinalizeLoading(false);
if (Dart_IsError(result)) {
return result;
}
return Dart_GetField(lib, Dart_NewStringFromCString("main"));
}

DartIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)
: closure_(closure) {}

Expand Down
6 changes: 5 additions & 1 deletion runtime/dart_isolate.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@ class DartIsolate : public UIDartState {

const DartIsolateGroupData& GetIsolateGroupData() const;

/// Returns the "main" entrypoint of the library contained in the kernel
/// data in `mapping`.
static Dart_Handle LoadLibraryFromKernel(
const std::shared_ptr<const fml::Mapping>& mapping);

private:
friend class IsolateConfiguration;
class AutoFireClosure {
Expand All @@ -407,7 +412,6 @@ class DartIsolate : public UIDartState {
friend class DartVM;

Phase phase_ = Phase::Unknown;
std::vector<std::shared_ptr<const fml::Mapping>> kernel_buffers_;
std::vector<std::unique_ptr<AutoFireClosure>> shutdown_callbacks_;
std::unordered_set<fml::RefPtr<DartSnapshot>> loading_unit_snapshots_;
fml::RefPtr<fml::TaskRunner> message_handling_task_runner_;
Expand Down
10 changes: 10 additions & 0 deletions runtime/dart_isolate_group_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,14 @@ DartIsolateGroupData::GetPlatformMessageHandler(
: it->second;
}

void DartIsolateGroupData::AddKernelBuffer(
const std::shared_ptr<const fml::Mapping>& buffer) {
kernel_buffers_.push_back(buffer);
}

std::vector<std::shared_ptr<const fml::Mapping>>
DartIsolateGroupData::GetKernelBuffers() const {
return kernel_buffers_;
}

} // namespace flutter
8 changes: 8 additions & 0 deletions runtime/dart_isolate_group_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage {

void SetChildIsolatePreparer(const ChildIsolatePreparer& value);

/// Adds a kernel buffer mapping to the kernels loaded for this isolate group.
void AddKernelBuffer(const std::shared_ptr<const fml::Mapping>& buffer);

/// A copy of the mappings for all kernel buffer objects loaded into this
/// isolate group.
std::vector<std::shared_ptr<const fml::Mapping>> GetKernelBuffers() const;

// |PlatformMessageHandlerStorage|
void SetPlatformMessageHandler(
int64_t root_isolate_token,
Expand All @@ -66,6 +73,7 @@ class DartIsolateGroupData : public PlatformMessageHandlerStorage {
int64_t root_isolate_token) const override;

private:
std::vector<std::shared_ptr<const fml::Mapping>> kernel_buffers_;
const Settings settings_;
const fml::RefPtr<const DartSnapshot> isolate_snapshot_;
const std::string advisory_script_uri_;
Expand Down
6 changes: 4 additions & 2 deletions shell/common/run_configuration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
#include "flutter/fml/file.h"
#include "flutter/fml/unique_fd.h"
#include "flutter/runtime/dart_vm.h"
#include "runtime/isolate_configuration.h"

namespace flutter {

RunConfiguration RunConfiguration::InferFromSettings(
const Settings& settings,
const fml::RefPtr<fml::TaskRunner>& io_worker) {
const fml::RefPtr<fml::TaskRunner>& io_worker,
IsolateLaunchType launch_type) {
auto asset_manager = std::make_shared<AssetManager>();

if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) {
Expand All @@ -31,7 +33,7 @@ RunConfiguration RunConfiguration::InferFromSettings(
true));

return {IsolateConfiguration::InferFromSettings(settings, asset_manager,
io_worker),
io_worker, launch_type),
asset_manager};
}

Expand Down
5 changes: 4 additions & 1 deletion shell/common/run_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,16 @@ class RunConfiguration {
/// serial worker is kept alive for the lifetime of the
/// shell associated with the engine that this run
/// configuration is given to.
/// @param[in] launch_type Whether to launch the new isolate into an existing
/// group or a new one.
///
/// @return A run configuration. Depending on the completeness of the
/// settings, This object may potentially be invalid.
///
static RunConfiguration InferFromSettings(
const Settings& settings,
const fml::RefPtr<fml::TaskRunner>& io_worker = nullptr);
const fml::RefPtr<fml::TaskRunner>& io_worker = nullptr,
IsolateLaunchType launch_type = IsolateLaunchType::kNewGroup);

//----------------------------------------------------------------------------
/// @brief Creates a run configuration with only an isolate
Expand Down
3 changes: 2 additions & 1 deletion shell/testing/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ executable("testing") {

public_configs = [
"//flutter:config",
"//flutter:export_dynamic_symbols",
"//flutter:export_dynamic_test_symbols",
]

sources = [ "tester_main.cc" ]
Expand All @@ -42,6 +42,7 @@ executable("testing") {
"//flutter/shell/gpu:gpu_surface_software",
"//flutter/skia",
"//flutter/third_party/tonic",
"//third_party/abseil-cpp/absl/base:no_destructor",
"//third_party/dart/runtime:libdart_jit",
"//third_party/dart/runtime/bin:dart_io_api",
]
Expand Down
Loading

0 comments on commit edbce21

Please sign in to comment.