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

Commit efcb53e

Browse files
authored
Reland "Add benchmarks to measure dart -> native time (#28492)" (#28726)
1 parent 9e45508 commit efcb53e

File tree

10 files changed

+252
-94
lines changed

10 files changed

+252
-94
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ FILE: ../../../flutter/shell/common/canvas_spy.h
692692
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
693693
FILE: ../../../flutter/shell/common/context_options.cc
694694
FILE: ../../../flutter/shell/common/context_options.h
695+
FILE: ../../../flutter/shell/common/dart_native_benchmarks.cc
695696
FILE: ../../../flutter/shell/common/display.h
696697
FILE: ../../../flutter/shell/common/display_manager.cc
697698
FILE: ../../../flutter/shell/common/display_manager.h

runtime/dart_isolate_unittests.cc

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,9 @@ TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {
247247

248248
TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
249249
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
250-
AddNativeCallback("NotifyNative",
251-
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
252-
FML_LOG(ERROR) << "Hello from Dart!";
253-
Signal();
254-
})));
250+
AddNativeCallback(
251+
"NotifyNative",
252+
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) { Signal(); })));
255253
const auto settings = CreateSettingsForFixture();
256254
auto vm_ref = DartVMRef::Create(settings);
257255
auto thread = CreateNewThread();
@@ -524,11 +522,9 @@ TEST_F(DartIsolateTest, DISABLED_ValidLoadingUnitSucceeds) {
524522
}
525523

526524
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
527-
AddNativeCallback("NotifyNative",
528-
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
529-
FML_LOG(ERROR) << "Hello from Dart!";
530-
Signal();
531-
})));
525+
AddNativeCallback(
526+
"NotifyNative",
527+
CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) { Signal(); })));
532528
AddNativeCallback(
533529
"NotifySuccess", CREATE_NATIVE_ENTRY([this](Dart_NativeArguments args) {
534530
auto bool_handle = Dart_GetNativeArgument(args, 0);

shell/common/BUILD.gn

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,17 @@ if (enable_unittests) {
158158
}
159159

160160
shell_host_executable("shell_benchmarks") {
161-
sources = [ "shell_benchmarks.cc" ]
161+
sources = [
162+
"dart_native_benchmarks.cc",
163+
"shell_benchmarks.cc",
164+
]
162165

163166
deps = [
164167
":shell_unittests_fixtures",
165168
"//flutter/benchmarking",
166169
"//flutter/flow",
167170
"//flutter/testing:dart",
171+
"//flutter/testing:fixture_test",
168172
"//flutter/testing:testing_lib",
169173
]
170174
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/common/shell.h"
6+
7+
#include "flutter/benchmarking/benchmarking.h"
8+
#include "flutter/shell/common/thread_host.h"
9+
#include "flutter/testing/dart_fixture.h"
10+
#include "flutter/testing/dart_isolate_runner.h"
11+
#include "flutter/testing/testing.h"
12+
#include "fml/synchronization/count_down_latch.h"
13+
#include "runtime/dart_vm_lifecycle.h"
14+
15+
namespace flutter::testing {
16+
17+
class DartNativeBenchmarks : public DartFixture, public benchmark::Fixture {
18+
public:
19+
DartNativeBenchmarks() : DartFixture() {}
20+
21+
void SetUp(const ::benchmark::State& state) {}
22+
23+
void TearDown(const ::benchmark::State& state) {}
24+
25+
private:
26+
FML_DISALLOW_COPY_AND_ASSIGN(DartNativeBenchmarks);
27+
};
28+
29+
BENCHMARK_F(DartNativeBenchmarks, TimeToFirstNativeMessageFromIsolateInNewVM)
30+
(benchmark::State& st) {
31+
while (st.KeepRunning()) {
32+
fml::AutoResetWaitableEvent latch;
33+
st.PauseTiming();
34+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
35+
AddNativeCallback("NotifyNative",
36+
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
37+
latch.Signal();
38+
})));
39+
40+
const auto settings = CreateSettingsForFixture();
41+
DartVMRef vm_ref = DartVMRef::Create(settings);
42+
43+
ThreadHost thread_host("io.flutter.test.DartNativeBenchmarks.",
44+
ThreadHost::Type::Platform | ThreadHost::Type::IO |
45+
ThreadHost::Type::UI);
46+
TaskRunners task_runners(
47+
"test",
48+
thread_host.platform_thread->GetTaskRunner(), // platform
49+
thread_host.platform_thread->GetTaskRunner(), // raster
50+
thread_host.ui_thread->GetTaskRunner(), // ui
51+
thread_host.io_thread->GetTaskRunner() // io
52+
);
53+
54+
{
55+
st.ResumeTiming();
56+
auto isolate =
57+
RunDartCodeInIsolate(vm_ref, settings, task_runners, "notifyNative",
58+
{}, GetDefaultKernelFilePath());
59+
ASSERT_TRUE(isolate);
60+
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
61+
latch.Wait();
62+
}
63+
}
64+
}
65+
66+
BENCHMARK_F(DartNativeBenchmarks, MultipleDartToNativeMessages)
67+
(benchmark::State& st) {
68+
while (st.KeepRunning()) {
69+
fml::CountDownLatch latch(1000);
70+
st.PauseTiming();
71+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
72+
AddNativeCallback("NotifyNative",
73+
CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) {
74+
latch.CountDown();
75+
})));
76+
77+
const auto settings = CreateSettingsForFixture();
78+
DartVMRef vm_ref = DartVMRef::Create(settings);
79+
80+
ThreadHost thread_host("io.flutter.test.DartNativeBenchmarks.",
81+
ThreadHost::Type::Platform | ThreadHost::Type::IO |
82+
ThreadHost::Type::UI);
83+
TaskRunners task_runners(
84+
"test",
85+
thread_host.platform_thread->GetTaskRunner(), // platform
86+
thread_host.platform_thread->GetTaskRunner(), // raster
87+
thread_host.ui_thread->GetTaskRunner(), // ui
88+
thread_host.io_thread->GetTaskRunner() // io
89+
);
90+
91+
{
92+
st.ResumeTiming();
93+
auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
94+
"thousandCallsToNative", {},
95+
GetDefaultKernelFilePath());
96+
ASSERT_TRUE(isolate);
97+
ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
98+
latch.Wait();
99+
}
100+
}
101+
}
102+
103+
} // namespace flutter::testing

shell/common/fixtures/shell_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,16 @@ void fixturesAreFunctionalMain() {
7373

7474
void sayHiFromFixturesAreFunctionalMain() native 'SayHiFromFixturesAreFunctionalMain';
7575

76+
@pragma('vm:entry-point')
7677
void notifyNative() native 'NotifyNative';
7778

79+
@pragma('vm:entry-point')
80+
void thousandCallsToNative() {
81+
for (int i = 0; i < 1000; i++) {
82+
notifyNative();
83+
}
84+
}
85+
7886
void secondaryIsolateMain(String message) {
7987
print('Secondary isolate got message: ' + message);
8088
notifyNative();

testing/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ source_set("fixture_test") {
9292
testonly = true
9393

9494
sources = [
95+
"dart_fixture.cc",
96+
"dart_fixture.h",
9597
"fixture_test.cc",
9698
"fixture_test.h",
9799
]

testing/dart_fixture.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/testing/dart_fixture.h"
6+
7+
namespace flutter::testing {
8+
9+
DartFixture::DartFixture()
10+
: DartFixture("kernel_blob.bin",
11+
kDefaultAOTAppELFFileName,
12+
kDefaultAOTAppELFSplitFileName) {}
13+
14+
DartFixture::DartFixture(std::string kernel_filename,
15+
std::string elf_filename,
16+
std::string elf_split_filename)
17+
: native_resolver_(std::make_shared<TestDartNativeResolver>()),
18+
split_aot_symbols_(
19+
LoadELFSplitSymbolFromFixturesIfNeccessary(elf_split_filename)),
20+
kernel_filename_(kernel_filename),
21+
assets_dir_(fml::OpenDirectory(GetFixturesPath(),
22+
false,
23+
fml::FilePermission::kRead)),
24+
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary(elf_filename)) {}
25+
26+
Settings DartFixture::CreateSettingsForFixture() {
27+
Settings settings;
28+
settings.leak_vm = false;
29+
settings.task_observer_add = [](intptr_t, fml::closure) {};
30+
settings.task_observer_remove = [](intptr_t) {};
31+
settings.isolate_create_callback = [this]() {
32+
native_resolver_->SetNativeResolverForIsolate();
33+
};
34+
settings.enable_observatory = false;
35+
SetSnapshotsAndAssets(settings);
36+
return settings;
37+
}
38+
39+
void DartFixture::SetSnapshotsAndAssets(Settings& settings) {
40+
if (!assets_dir_.is_valid()) {
41+
return;
42+
}
43+
44+
settings.assets_dir = assets_dir_.get();
45+
46+
// In JIT execution, all snapshots are present within the binary itself and
47+
// don't need to be explicitly supplied by the embedder. In AOT, these
48+
// snapshots will be present in the application AOT dylib.
49+
if (DartVM::IsRunningPrecompiledCode()) {
50+
FML_CHECK(PrepareSettingsForAOTWithSymbols(settings, aot_symbols_));
51+
} else {
52+
settings.application_kernels = [this]() -> Mappings {
53+
std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
54+
auto kernel_mapping =
55+
fml::FileMapping::CreateReadOnly(assets_dir_, kernel_filename_);
56+
if (!kernel_mapping || !kernel_mapping->IsValid()) {
57+
FML_LOG(ERROR) << "Could not find kernel blob for test fixture not "
58+
"running in precompiled mode.";
59+
return kernel_mappings;
60+
}
61+
kernel_mappings.emplace_back(std::move(kernel_mapping));
62+
return kernel_mappings;
63+
};
64+
}
65+
}
66+
67+
void DartFixture::AddNativeCallback(std::string name,
68+
Dart_NativeFunction callback) {
69+
native_resolver_->AddNativeCallback(std::move(name), callback);
70+
}
71+
72+
} // namespace flutter::testing

testing/dart_fixture.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_TESTING_DART_FIXTURE_H_
6+
#define FLUTTER_TESTING_DART_FIXTURE_H_
7+
8+
#include <memory>
9+
10+
#include "flutter/common/settings.h"
11+
#include "flutter/runtime/dart_vm.h"
12+
#include "flutter/testing/elf_loader.h"
13+
#include "flutter/testing/test_dart_native_resolver.h"
14+
#include "flutter/testing/testing.h"
15+
#include "flutter/testing/thread_test.h"
16+
17+
namespace flutter::testing {
18+
19+
class DartFixture {
20+
public:
21+
// Uses the default filenames from the fixtures generator.
22+
DartFixture();
23+
24+
// Allows to customize the kernel, ELF and split ELF filenames.
25+
DartFixture(std::string kernel_filename,
26+
std::string elf_filename,
27+
std::string elf_split_filename);
28+
29+
virtual Settings CreateSettingsForFixture();
30+
31+
void AddNativeCallback(std::string name, Dart_NativeFunction callback);
32+
33+
protected:
34+
void SetSnapshotsAndAssets(Settings& settings);
35+
36+
std::shared_ptr<TestDartNativeResolver> native_resolver_;
37+
ELFAOTSymbols split_aot_symbols_;
38+
std::string kernel_filename_;
39+
std::string elf_filename_;
40+
fml::UniqueFD assets_dir_;
41+
ELFAOTSymbols aot_symbols_;
42+
43+
private:
44+
FML_DISALLOW_COPY_AND_ASSIGN(DartFixture);
45+
};
46+
47+
} // namespace flutter::testing
48+
49+
#endif // FLUTTER_TESTING_DART_FIXTURE_H_

testing/fixture_test.cc

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,71 +4,17 @@
44

55
#include "flutter/testing/fixture_test.h"
66

7+
#include "flutter/testing/dart_fixture.h"
8+
79
namespace flutter {
810
namespace testing {
911

10-
FixtureTest::FixtureTest()
11-
: FixtureTest("kernel_blob.bin",
12-
kDefaultAOTAppELFFileName,
13-
kDefaultAOTAppELFSplitFileName) {}
12+
FixtureTest::FixtureTest() : DartFixture() {}
1413

1514
FixtureTest::FixtureTest(std::string kernel_filename,
1615
std::string elf_filename,
1716
std::string elf_split_filename)
18-
: native_resolver_(std::make_shared<TestDartNativeResolver>()),
19-
split_aot_symbols_(
20-
LoadELFSplitSymbolFromFixturesIfNeccessary(elf_split_filename)),
21-
kernel_filename_(kernel_filename),
22-
assets_dir_(fml::OpenDirectory(GetFixturesPath(),
23-
false,
24-
fml::FilePermission::kRead)),
25-
aot_symbols_(LoadELFSymbolFromFixturesIfNeccessary(elf_filename)) {}
26-
27-
Settings FixtureTest::CreateSettingsForFixture() {
28-
Settings settings;
29-
settings.leak_vm = false;
30-
settings.task_observer_add = [](intptr_t, fml::closure) {};
31-
settings.task_observer_remove = [](intptr_t) {};
32-
settings.isolate_create_callback = [this]() {
33-
native_resolver_->SetNativeResolverForIsolate();
34-
};
35-
settings.enable_observatory = false;
36-
SetSnapshotsAndAssets(settings);
37-
return settings;
38-
}
39-
40-
void FixtureTest::SetSnapshotsAndAssets(Settings& settings) {
41-
if (!assets_dir_.is_valid()) {
42-
return;
43-
}
44-
45-
settings.assets_dir = assets_dir_.get();
46-
47-
// In JIT execution, all snapshots are present within the binary itself and
48-
// don't need to be explicitly supplied by the embedder. In AOT, these
49-
// snapshots will be present in the application AOT dylib.
50-
if (DartVM::IsRunningPrecompiledCode()) {
51-
FML_CHECK(PrepareSettingsForAOTWithSymbols(settings, aot_symbols_));
52-
} else {
53-
settings.application_kernels = [this]() -> Mappings {
54-
std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
55-
auto kernel_mapping =
56-
fml::FileMapping::CreateReadOnly(assets_dir_, kernel_filename_);
57-
if (!kernel_mapping || !kernel_mapping->IsValid()) {
58-
FML_LOG(ERROR) << "Could not find kernel blob for test fixture not "
59-
"running in precompiled mode.";
60-
return kernel_mappings;
61-
}
62-
kernel_mappings.emplace_back(std::move(kernel_mapping));
63-
return kernel_mappings;
64-
};
65-
}
66-
}
67-
68-
void FixtureTest::AddNativeCallback(std::string name,
69-
Dart_NativeFunction callback) {
70-
native_resolver_->AddNativeCallback(std::move(name), callback);
71-
}
17+
: DartFixture(kernel_filename, elf_filename, elf_split_filename) {}
7218

7319
} // namespace testing
7420
} // namespace flutter

0 commit comments

Comments
 (0)