-
Notifications
You must be signed in to change notification settings - Fork 6k
Eliminates Dart->Host response copy for large buffers #35468
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,11 @@ static std::atomic<uint64_t> platform_message_counter = 1; | |
|
|
||
| namespace flutter { | ||
| namespace { | ||
|
|
||
| void MappingFinalizer(void* isolate_callback_data, void* peer) { | ||
| delete static_cast<fml::Mapping*>(peer); | ||
| } | ||
|
|
||
| template <typename Callback, typename TaskRunner, typename Result> | ||
| void PostCompletion(Callback&& callback, | ||
| const TaskRunner& ui_task_runner, | ||
|
|
@@ -63,11 +68,35 @@ PlatformMessageResponseDart::~PlatformMessageResponseDart() { | |
| } | ||
|
|
||
| void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) { | ||
| PostCompletion(std::move(callback_), ui_task_runner_, &is_complete_, channel_, | ||
| [data = std::move(data)] { | ||
| return tonic::DartByteData::Create(data->GetMapping(), | ||
| data->GetSize()); | ||
| }); | ||
| PostCompletion( | ||
| std::move(callback_), ui_task_runner_, &is_complete_, channel_, | ||
| [data = std::move(data)]() mutable { | ||
| Dart_Handle byte_buffer; | ||
| intptr_t size = data->GetSize(); | ||
| if (data->GetSize() > tonic::DartByteData::kExternalSizeThreshold) { | ||
| const void* mapping = data->GetMapping(); | ||
| byte_buffer = Dart_NewUnmodifiableExternalTypedDataWithFinalizer( | ||
| /*type=*/Dart_TypedData_kByteData, | ||
| /*data=*/mapping, | ||
| /*length=*/size, | ||
| /*peer=*/data.release(), | ||
| /*external_allocation_size=*/size, | ||
| /*callback=*/MappingFinalizer); | ||
| } else { | ||
| Dart_Handle mutable_byte_buffer = | ||
| tonic::DartByteData::Create(data->GetMapping(), data->GetSize()); | ||
| Dart_Handle ui_lib = Dart_LookupLibrary( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DBC You may be able to speed this up by using the I'd suggest also caching the string
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh yeah allocating these strings does add up if this gets chatty. We store a bunch of things like this in
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, I considered it but didn't know where to put it. FWIW I don't think the wrapping code had a big impact on the microbenchmark, less than 1% of the round trip time for a message. I expected looking up the library to be expensive too but seemed fast. I'll double check everything this afternoon when i go back and look at the official performance numbers.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The lookup is fast but the string creation adds up. |
||
| tonic::DartConverter<std::string>().ToDart("dart:ui")); | ||
| FML_DCHECK(!(Dart_IsNull(ui_lib) || Dart_IsError(ui_lib))); | ||
| byte_buffer = Dart_Invoke(ui_lib, | ||
| tonic::DartConverter<std::string>().ToDart( | ||
| "_wrapUnmodifiableByteData"), | ||
| 1, &mutable_byte_buffer); | ||
| FML_DCHECK(!(Dart_IsNull(byte_buffer) || Dart_IsError(byte_buffer))); | ||
| } | ||
|
|
||
| return byte_buffer; | ||
| }); | ||
| } | ||
|
|
||
| void PlatformMessageResponseDart::CompleteEmpty() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // 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/common/task_runners.h" | ||
| #include "flutter/fml/mapping.h" | ||
| #include "flutter/fml/synchronization/waitable_event.h" | ||
| #include "flutter/lib/ui/window/platform_message_response_dart.h" | ||
| #include "flutter/runtime/dart_vm.h" | ||
| #include "flutter/shell/common/shell_test.h" | ||
| #include "flutter/shell/common/thread_host.h" | ||
| #include "flutter/testing/testing.h" | ||
|
|
||
| namespace flutter { | ||
| namespace testing { | ||
|
|
||
| TEST_F(ShellTest, PlatformMessageResponseDart) { | ||
| bool did_pass = false; | ||
| auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>(); | ||
| TaskRunners task_runners("test", // label | ||
| GetCurrentTaskRunner(), // platform | ||
| CreateNewThread(), // raster | ||
| CreateNewThread(), // ui | ||
| CreateNewThread() // io | ||
| ); | ||
|
|
||
| auto nativeCallPlatformMessageResponseDart = | ||
| [ui_task_runner = | ||
| task_runners.GetUITaskRunner()](Dart_NativeArguments args) { | ||
| auto dart_state = std::make_shared<tonic::DartState>(); | ||
| auto response = fml::MakeRefCounted<PlatformMessageResponseDart>( | ||
| tonic::DartPersistentValue(tonic::DartState::Current(), | ||
| Dart_GetNativeArgument(args, 0)), | ||
| ui_task_runner, "foobar"); | ||
| uint8_t* data = static_cast<uint8_t*>(malloc(100)); | ||
| auto mapping = std::make_unique<fml::MallocMapping>(data, 100); | ||
| response->Complete(std::move(mapping)); | ||
| }; | ||
|
|
||
| AddNativeCallback("CallPlatformMessageResponseDart", | ||
| CREATE_NATIVE_ENTRY(nativeCallPlatformMessageResponseDart)); | ||
|
|
||
| auto nativeFinishCallResponse = [message_latch, | ||
| &did_pass](Dart_NativeArguments args) { | ||
| did_pass = | ||
| tonic::DartConverter<bool>::FromDart(Dart_GetNativeArgument(args, 0)); | ||
| message_latch->Signal(); | ||
| }; | ||
|
|
||
| AddNativeCallback("FinishCallResponse", | ||
| CREATE_NATIVE_ENTRY(nativeFinishCallResponse)); | ||
|
|
||
| Settings settings = CreateSettingsForFixture(); | ||
|
|
||
| std::unique_ptr<Shell> shell = | ||
| CreateShell(std::move(settings), std::move(task_runners)); | ||
|
|
||
| ASSERT_TRUE(shell->IsSetup()); | ||
| auto configuration = RunConfiguration::InferFromSettings(settings); | ||
| configuration.SetEntrypoint("platformMessageResponseTest"); | ||
|
|
||
| shell->RunEngine(std::move(configuration), [](auto result) { | ||
| ASSERT_EQ(result, Engine::RunStatus::Success); | ||
| }); | ||
|
|
||
| message_latch->Wait(); | ||
|
|
||
| ASSERT_TRUE(did_pass); | ||
| DestroyShell(std::move(shell), std::move(task_runners)); | ||
| } | ||
|
|
||
| } // namespace testing | ||
| } // namespace flutter |
Uh oh!
There was an error while loading. Please reload this page.