Skip to content

Commit

Permalink
Add benchmarks to measure dart -> native time (flutter#28492)
Browse files Browse the repository at this point in the history
  • Loading branch information
iskakaushik authored Sep 8, 2021
1 parent 07896f7 commit 3155b00
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 94 deletions.
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ FILE: ../../../flutter/shell/common/canvas_spy.h
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
FILE: ../../../flutter/shell/common/context_options.cc
FILE: ../../../flutter/shell/common/context_options.h
FILE: ../../../flutter/shell/common/dart_native_benchmarks.cc
FILE: ../../../flutter/shell/common/display.h
FILE: ../../../flutter/shell/common/display_manager.cc
FILE: ../../../flutter/shell/common/display_manager.h
Expand Down
16 changes: 6 additions & 10 deletions runtime/dart_isolate_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,9 @@ TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {

TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
AddNativeCallback("NotifyNative",
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
FML_LOG(ERROR) << "Hello from Dart!";
Signal();
})));
AddNativeCallback(
"NotifyNative",
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) { Signal(); })));
const auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto thread = CreateNewThread();
Expand Down Expand Up @@ -524,11 +522,9 @@ TEST_F(DartIsolateTest, DISABLED_ValidLoadingUnitSucceeds) {
}

ASSERT_FALSE(DartVMRef::IsInstanceRunning());
AddNativeCallback("NotifyNative",
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
FML_LOG(ERROR) << "Hello from Dart!";
Signal();
})));
AddNativeCallback(
"NotifyNative",
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) { Signal(); })));
AddNativeCallback(
"NotifySuccess", CREATE_NATIVE_ENTRY([this](Dart_NativeArguments args) {
auto bool_handle = Dart_GetNativeArgument(args, 0);
Expand Down
6 changes: 5 additions & 1 deletion shell/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,17 @@ if (enable_unittests) {
}

shell_host_executable("shell_benchmarks") {
sources = [ "shell_benchmarks.cc" ]
sources = [
"dart_native_benchmarks.cc",
"shell_benchmarks.cc",
]

deps = [
":shell_unittests_fixtures",
"//flutter/benchmarking",
"//flutter/flow",
"//flutter/testing:dart",
"//flutter/testing:fixture_test",
"//flutter/testing:testing_lib",
]
}
Expand Down
103 changes: 103 additions & 0 deletions shell/common/dart_native_benchmarks.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// 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/shell/common/thread_host.h"
#include "flutter/testing/dart_fixture.h"
#include "flutter/testing/dart_isolate_runner.h"
#include "flutter/testing/testing.h"
#include "fml/synchronization/count_down_latch.h"
#include "runtime/dart_vm_lifecycle.h"

namespace flutter::testing {

class DartNativeBenchmarks : public DartFixture, public benchmark::Fixture {
public:
DartNativeBenchmarks() : DartFixture() {}

void SetUp(const ::benchmark::State& state) {}

void TearDown(const ::benchmark::State& state) {}

private:
FML_DISALLOW_COPY_AND_ASSIGN(DartNativeBenchmarks);
};

BENCHMARK_F(DartNativeBenchmarks, TimeToFirstNativeMessageFromIsolateInNewVM)
(benchmark::State& st) {
while (st.KeepRunning()) {
fml::AutoResetWaitableEvent latch;
st.PauseTiming();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
AddNativeCallback("NotifyNative",
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
latch.Signal();
})));

const auto settings = CreateSettingsForFixture();
DartVMRef vm_ref = DartVMRef::Create(settings);

ThreadHost thread_host("io.flutter.test.DartNativeBenchmarks.",
ThreadHost::Type::Platform | ThreadHost::Type::IO |
ThreadHost::Type::UI);
TaskRunners task_runners(
"test",
thread_host.platform_thread->GetTaskRunner(), // platform
thread_host.platform_thread->GetTaskRunner(), // raster
thread_host.ui_thread->GetTaskRunner(), // ui
thread_host.io_thread->GetTaskRunner() // io
);

{
st.ResumeTiming();
auto isolate =
RunDartCodeInIsolate(vm_ref, settings, task_runners, "notifyNative",
{}, GetDefaultKernelFilePath());
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
latch.Wait();
}
}
}

BENCHMARK_F(DartNativeBenchmarks, MultipleDartToNativeMessages)
(benchmark::State& st) {
while (st.KeepRunning()) {
fml::CountDownLatch latch(1000);
st.PauseTiming();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
AddNativeCallback("NotifyNative",
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
latch.CountDown();
})));

const auto settings = CreateSettingsForFixture();
DartVMRef vm_ref = DartVMRef::Create(settings);

ThreadHost thread_host("io.flutter.test.DartNativeBenchmarks.",
ThreadHost::Type::Platform | ThreadHost::Type::IO |
ThreadHost::Type::UI);
TaskRunners task_runners(
"test",
thread_host.platform_thread->GetTaskRunner(), // platform
thread_host.platform_thread->GetTaskRunner(), // raster
thread_host.ui_thread->GetTaskRunner(), // ui
thread_host.io_thread->GetTaskRunner() // io
);

{
st.ResumeTiming();
auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
"thousandCallsToNative", {},
GetDefaultKernelFilePath());
ASSERT_TRUE(isolate);
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
latch.Wait();
}
}
}

} // namespace flutter::testing
6 changes: 6 additions & 0 deletions shell/common/fixtures/shell_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ void sayHiFromFixturesAreFunctionalMain() native 'SayHiFromFixturesAreFunctional

void notifyNative() native 'NotifyNative';

void thousandCallsToNative() {
for (int i = 0; i < 1000; i++) {
notifyNative();
}
}

void secondaryIsolateMain(String message) {
print('Secondary isolate got message: ' + message);
notifyNative();
Expand Down
2 changes: 2 additions & 0 deletions testing/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ source_set("fixture_test") {
testonly = true

sources = [
"dart_fixture.cc",
"dart_fixture.h",
"fixture_test.cc",
"fixture_test.h",
]
Expand Down
72 changes: 72 additions & 0 deletions testing/dart_fixture.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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/testing/dart_fixture.h"

namespace flutter::testing {

DartFixture::DartFixture()
: DartFixture("kernel_blob.bin",
kDefaultAOTAppELFFileName,
kDefaultAOTAppELFSplitFileName) {}

DartFixture::DartFixture(std::string kernel_filename,
std::string elf_filename,
std::string elf_split_filename)
: native_resolver_(std::make_shared<TestDartNativeResolver>()),
split_aot_symbols_(
LoadELFSplitSymbolFromFixturesIfNeccessary(elf_split_filename)),
kernel_filename_(kernel_filename),
assets_dir_(fml::OpenDirectory(GetFixturesPath(),
false,
fml::FilePermission::kRead)),
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary(elf_filename)) {}

Settings DartFixture::CreateSettingsForFixture() {
Settings settings;
settings.leak_vm = false;
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
settings.isolate_create_callback = [this]() {
native_resolver_->SetNativeResolverForIsolate();
};
settings.enable_observatory = false;
SetSnapshotsAndAssets(settings);
return settings;
}

void DartFixture::SetSnapshotsAndAssets(Settings& settings) {
if (!assets_dir_.is_valid()) {
return;
}

settings.assets_dir = assets_dir_.get();

// In JIT execution, all snapshots are present within the binary itself and
// don't need to be explicitly supplied by the embedder. In AOT, these
// snapshots will be present in the application AOT dylib.
if (DartVM::IsRunningPrecompiledCode()) {
FML_CHECK(PrepareSettingsForAOTWithSymbols(settings, aot_symbols_));
} else {
settings.application_kernels = [this]() -> Mappings {
std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
auto kernel_mapping =
fml::FileMapping::CreateReadOnly(assets_dir_, kernel_filename_);
if (!kernel_mapping || !kernel_mapping->IsValid()) {
FML_LOG(ERROR) << "Could not find kernel blob for test fixture not "
"running in precompiled mode.";
return kernel_mappings;
}
kernel_mappings.emplace_back(std::move(kernel_mapping));
return kernel_mappings;
};
}
}

void DartFixture::AddNativeCallback(std::string name,
Dart_NativeFunction callback) {
native_resolver_->AddNativeCallback(std::move(name), callback);
}

} // namespace flutter::testing
49 changes: 49 additions & 0 deletions testing/dart_fixture.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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.

#ifndef FLUTTER_TESTING_DART_FIXTURE_H_
#define FLUTTER_TESTING_DART_FIXTURE_H_

#include <memory>

#include "flutter/common/settings.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/testing/elf_loader.h"
#include "flutter/testing/test_dart_native_resolver.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/thread_test.h"

namespace flutter::testing {

class DartFixture {
public:
// Uses the default filenames from the fixtures generator.
DartFixture();

// Allows to customize the kernel, ELF and split ELF filenames.
DartFixture(std::string kernel_filename,
std::string elf_filename,
std::string elf_split_filename);

virtual Settings CreateSettingsForFixture();

void AddNativeCallback(std::string name, Dart_NativeFunction callback);

protected:
void SetSnapshotsAndAssets(Settings& settings);

std::shared_ptr<TestDartNativeResolver> native_resolver_;
ELFAOTSymbols split_aot_symbols_;
std::string kernel_filename_;
std::string elf_filename_;
fml::UniqueFD assets_dir_;
ELFAOTSymbols aot_symbols_;

private:
FML_DISALLOW_COPY_AND_ASSIGN(DartFixture);
};

} // namespace flutter::testing

#endif // FLUTTER_TESTING_DART_FIXTURE_H_
62 changes: 4 additions & 58 deletions testing/fixture_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,17 @@

#include "flutter/testing/fixture_test.h"

#include "flutter/testing/dart_fixture.h"

namespace flutter {
namespace testing {

FixtureTest::FixtureTest()
: FixtureTest("kernel_blob.bin",
kDefaultAOTAppELFFileName,
kDefaultAOTAppELFSplitFileName) {}
FixtureTest::FixtureTest() : DartFixture() {}

FixtureTest::FixtureTest(std::string kernel_filename,
std::string elf_filename,
std::string elf_split_filename)
: native_resolver_(std::make_shared<TestDartNativeResolver>()),
split_aot_symbols_(
LoadELFSplitSymbolFromFixturesIfNeccessary(elf_split_filename)),
kernel_filename_(kernel_filename),
assets_dir_(fml::OpenDirectory(GetFixturesPath(),
false,
fml::FilePermission::kRead)),
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary(elf_filename)) {}

Settings FixtureTest::CreateSettingsForFixture() {
Settings settings;
settings.leak_vm = false;
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
settings.isolate_create_callback = [this]() {
native_resolver_->SetNativeResolverForIsolate();
};
settings.enable_observatory = false;
SetSnapshotsAndAssets(settings);
return settings;
}

void FixtureTest::SetSnapshotsAndAssets(Settings& settings) {
if (!assets_dir_.is_valid()) {
return;
}

settings.assets_dir = assets_dir_.get();

// In JIT execution, all snapshots are present within the binary itself and
// don't need to be explicitly supplied by the embedder. In AOT, these
// snapshots will be present in the application AOT dylib.
if (DartVM::IsRunningPrecompiledCode()) {
FML_CHECK(PrepareSettingsForAOTWithSymbols(settings, aot_symbols_));
} else {
settings.application_kernels = [this]() -> Mappings {
std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
auto kernel_mapping =
fml::FileMapping::CreateReadOnly(assets_dir_, kernel_filename_);
if (!kernel_mapping || !kernel_mapping->IsValid()) {
FML_LOG(ERROR) << "Could not find kernel blob for test fixture not "
"running in precompiled mode.";
return kernel_mappings;
}
kernel_mappings.emplace_back(std::move(kernel_mapping));
return kernel_mappings;
};
}
}

void FixtureTest::AddNativeCallback(std::string name,
Dart_NativeFunction callback) {
native_resolver_->AddNativeCallback(std::move(name), callback);
}
: DartFixture(kernel_filename, elf_filename, elf_split_filename) {}

} // namespace testing
} // namespace flutter
Loading

0 comments on commit 3155b00

Please sign in to comment.