mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Tuning resource cache max bytes in lightweight engine scenarios (flutter/engine#32156)
This commit is contained in:
parent
ebbfcee25d
commit
31e332ee32
@ -1108,6 +1108,9 @@ FILE: ../../../flutter/shell/common/pointer_data_dispatcher.h
|
||||
FILE: ../../../flutter/shell/common/rasterizer.cc
|
||||
FILE: ../../../flutter/shell/common/rasterizer.h
|
||||
FILE: ../../../flutter/shell/common/rasterizer_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/resource_cache_limit_calculator.cc
|
||||
FILE: ../../../flutter/shell/common/resource_cache_limit_calculator.h
|
||||
FILE: ../../../flutter/shell/common/resource_cache_limit_calculator_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/run_configuration.cc
|
||||
FILE: ../../../flutter/shell/common/run_configuration.h
|
||||
FILE: ../../../flutter/shell/common/serialization_callbacks.cc
|
||||
|
||||
@ -294,6 +294,9 @@ struct Settings {
|
||||
/// https://github.com/dart-lang/sdk/blob/ca64509108b3e7219c50d6c52877c85ab6a35ff2/runtime/vm/flag_list.h#L150
|
||||
int64_t old_gen_heap_size = -1;
|
||||
|
||||
// Max bytes threshold of resource cache, or 0 for unlimited.
|
||||
size_t resource_cache_max_bytes_threshold = 0;
|
||||
|
||||
/// A timestamp representing when the engine started. The value is based
|
||||
/// on the clock used by the Dart timeline APIs. This timestamp is used
|
||||
/// to log a timeline event that tracks the latency of engine startup.
|
||||
|
||||
@ -81,6 +81,8 @@ source_set("common") {
|
||||
"pointer_data_dispatcher.h",
|
||||
"rasterizer.cc",
|
||||
"rasterizer.h",
|
||||
"resource_cache_limit_calculator.cc",
|
||||
"resource_cache_limit_calculator.h",
|
||||
"run_configuration.cc",
|
||||
"run_configuration.h",
|
||||
"serialization_callbacks.cc",
|
||||
@ -270,6 +272,7 @@ if (enable_unittests) {
|
||||
"persistent_cache_unittests.cc",
|
||||
"pipeline_unittests.cc",
|
||||
"rasterizer_unittests.cc",
|
||||
"resource_cache_limit_calculator_unittests.cc",
|
||||
"shell_unittests.cc",
|
||||
"skp_shader_warmup_unittests.cc",
|
||||
"switches_unittests.cc",
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
// 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/resource_cache_limit_calculator.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
size_t ResourceCacheLimitCalculator::GetResourceCacheMaxBytes() {
|
||||
size_t max_bytes = 0;
|
||||
size_t max_bytes_threshold = max_bytes_threshold_ > 0
|
||||
? max_bytes_threshold_
|
||||
: std::numeric_limits<size_t>::max();
|
||||
std::vector<fml::WeakPtr<ResourceCacheLimitItem>> live_items;
|
||||
for (auto item : items_) {
|
||||
if (item) {
|
||||
live_items.push_back(item);
|
||||
max_bytes += item->GetResourceCacheLimit();
|
||||
}
|
||||
}
|
||||
items_ = std::move(live_items);
|
||||
return std::min(max_bytes, max_bytes_threshold);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -0,0 +1,48 @@
|
||||
// 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_SHELL_COMMON_RESOURCE_CACHE_LIMIT_CALCULATOR_
|
||||
#define FLUTTER_SHELL_COMMON_RESOURCE_CACHE_LIMIT_CALCULATOR_
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/memory/weak_ptr.h"
|
||||
|
||||
namespace flutter {
|
||||
class ResourceCacheLimitItem {
|
||||
public:
|
||||
// The expected GPU resource cache limit in bytes. This will be called on the
|
||||
// platform thread.
|
||||
virtual size_t GetResourceCacheLimit() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ResourceCacheLimitItem() = default;
|
||||
};
|
||||
|
||||
class ResourceCacheLimitCalculator {
|
||||
public:
|
||||
ResourceCacheLimitCalculator(size_t max_bytes_threshold)
|
||||
: max_bytes_threshold_(max_bytes_threshold) {}
|
||||
|
||||
~ResourceCacheLimitCalculator() = default;
|
||||
|
||||
// This will be called on the platform thread.
|
||||
void AddResourceCacheLimitItem(fml::WeakPtr<ResourceCacheLimitItem> item) {
|
||||
items_.push_back(item);
|
||||
}
|
||||
|
||||
// The maximum GPU resource cache limit in bytes calculated by
|
||||
// 'ResourceCacheLimitItem's. This will be called on the platform thread.
|
||||
size_t GetResourceCacheMaxBytes();
|
||||
|
||||
private:
|
||||
std::vector<fml::WeakPtr<ResourceCacheLimitItem>> items_;
|
||||
size_t max_bytes_threshold_;
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ResourceCacheLimitCalculator);
|
||||
};
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_COMMON_RESOURCE_CACHE_LIMIT_CALCULATOR_
|
||||
@ -0,0 +1,54 @@
|
||||
// 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/resource_cache_limit_calculator.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
class TestResourceCacheLimitItem : public ResourceCacheLimitItem {
|
||||
public:
|
||||
explicit TestResourceCacheLimitItem(size_t resource_cache_limit)
|
||||
: resource_cache_limit_(resource_cache_limit), weak_factory_(this) {}
|
||||
|
||||
size_t GetResourceCacheLimit() override { return resource_cache_limit_; }
|
||||
|
||||
fml::WeakPtr<TestResourceCacheLimitItem> GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t resource_cache_limit_;
|
||||
fml::WeakPtrFactory<TestResourceCacheLimitItem> weak_factory_;
|
||||
};
|
||||
|
||||
TEST(ResourceCacheLimitCalculatorTest, GetResourceCacheMaxBytes) {
|
||||
ResourceCacheLimitCalculator calculator(800U);
|
||||
auto item1 = std::make_unique<TestResourceCacheLimitItem>(100.0);
|
||||
calculator.AddResourceCacheLimitItem(item1->GetWeakPtr());
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(100U));
|
||||
|
||||
auto item2 = std::make_unique<TestResourceCacheLimitItem>(200.0);
|
||||
calculator.AddResourceCacheLimitItem(item2->GetWeakPtr());
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(300U));
|
||||
|
||||
auto item3 = std::make_unique<TestResourceCacheLimitItem>(300.0);
|
||||
calculator.AddResourceCacheLimitItem(item3->GetWeakPtr());
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(600U));
|
||||
|
||||
auto item4 = std::make_unique<TestResourceCacheLimitItem>(400.0);
|
||||
calculator.AddResourceCacheLimitItem(item4->GetWeakPtr());
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(800U));
|
||||
|
||||
item3.reset();
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(700U));
|
||||
|
||||
item2.reset();
|
||||
EXPECT_EQ(calculator.GetResourceCacheMaxBytes(), static_cast<size_t>(500U));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -147,10 +147,14 @@ std::unique_ptr<Shell> Shell::Create(
|
||||
if (!isolate_snapshot) {
|
||||
isolate_snapshot = vm->GetVMData()->GetIsolateSnapshot();
|
||||
}
|
||||
auto resource_cache_limit_calculator =
|
||||
std::make_shared<ResourceCacheLimitCalculator>(
|
||||
settings.resource_cache_max_bytes_threshold);
|
||||
return CreateWithSnapshot(std::move(platform_data), //
|
||||
std::move(task_runners), //
|
||||
/*parent_merger=*/nullptr, //
|
||||
/*parent_io_manager=*/nullptr, //
|
||||
resource_cache_limit_calculator, //
|
||||
std::move(settings), //
|
||||
std::move(vm), //
|
||||
std::move(isolate_snapshot), //
|
||||
@ -163,6 +167,8 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
|
||||
DartVMRef vm,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_merger,
|
||||
std::shared_ptr<ShellIOManager> parent_io_manager,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
TaskRunners task_runners,
|
||||
const PlatformData& platform_data,
|
||||
Settings settings,
|
||||
@ -177,7 +183,8 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
|
||||
}
|
||||
|
||||
auto shell = std::unique_ptr<Shell>(
|
||||
new Shell(std::move(vm), task_runners, parent_merger, settings,
|
||||
new Shell(std::move(vm), task_runners, parent_merger,
|
||||
resource_cache_limit_calculator, settings,
|
||||
std::make_shared<VolatilePathTracker>(
|
||||
task_runners.GetUITaskRunner(),
|
||||
!settings.skia_deterministic_rendering_on_cpu),
|
||||
@ -313,6 +320,8 @@ std::unique_ptr<Shell> Shell::CreateWithSnapshot(
|
||||
TaskRunners task_runners,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_thread_merger,
|
||||
std::shared_ptr<ShellIOManager> parent_io_manager,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
Settings settings,
|
||||
DartVMRef vm,
|
||||
fml::RefPtr<const DartSnapshot> isolate_snapshot,
|
||||
@ -340,6 +349,7 @@ std::unique_ptr<Shell> Shell::CreateWithSnapshot(
|
||||
&shell, //
|
||||
parent_thread_merger, //
|
||||
parent_io_manager, //
|
||||
resource_cache_limit_calculator, //
|
||||
task_runners = std::move(task_runners), //
|
||||
platform_data = std::move(platform_data), //
|
||||
settings = std::move(settings), //
|
||||
@ -353,6 +363,7 @@ std::unique_ptr<Shell> Shell::CreateWithSnapshot(
|
||||
std::move(vm), //
|
||||
parent_thread_merger, //
|
||||
parent_io_manager, //
|
||||
resource_cache_limit_calculator, //
|
||||
std::move(task_runners), //
|
||||
std::move(platform_data), //
|
||||
std::move(settings), //
|
||||
@ -369,11 +380,14 @@ std::unique_ptr<Shell> Shell::CreateWithSnapshot(
|
||||
Shell::Shell(DartVMRef vm,
|
||||
TaskRunners task_runners,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_merger,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
Settings settings,
|
||||
std::shared_ptr<VolatilePathTracker> volatile_path_tracker,
|
||||
bool is_gpu_disabled)
|
||||
: task_runners_(std::move(task_runners)),
|
||||
parent_raster_thread_merger_(parent_merger),
|
||||
resource_cache_limit_calculator_(resource_cache_limit_calculator),
|
||||
settings_(std::move(settings)),
|
||||
vm_(std::move(vm)),
|
||||
is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)),
|
||||
@ -385,6 +399,8 @@ Shell::Shell(DartVMRef vm,
|
||||
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
|
||||
|
||||
display_manager_ = std::make_unique<DisplayManager>();
|
||||
resource_cache_limit_calculator->AddResourceCacheLimitItem(
|
||||
weak_factory_.GetWeakPtr());
|
||||
|
||||
// Generate a WeakPtrFactory for use with the raster thread. This does not
|
||||
// need to wait on a latch because it can only ever be used from the raster
|
||||
@ -502,8 +518,9 @@ std::unique_ptr<Shell> Shell::Spawn(
|
||||
.SetIfTrue([&is_gpu_disabled] { is_gpu_disabled = true; }));
|
||||
std::unique_ptr<Shell> result = CreateWithSnapshot(
|
||||
PlatformData{}, task_runners_, rasterizer_->GetRasterThreadMerger(),
|
||||
io_manager_, GetSettings(), vm_, vm_->GetVMData()->GetIsolateSnapshot(),
|
||||
on_create_platform_view, on_create_rasterizer,
|
||||
io_manager_, resource_cache_limit_calculator_, GetSettings(), vm_,
|
||||
vm_->GetVMData()->GetIsolateSnapshot(), on_create_platform_view,
|
||||
on_create_rasterizer,
|
||||
[engine = this->engine_.get(), initial_route](
|
||||
Engine::Delegate& delegate,
|
||||
const PointerDataDispatcherMaker& dispatcher_maker, DartVM& vm,
|
||||
@ -911,12 +928,15 @@ void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) {
|
||||
}
|
||||
|
||||
// This is the formula Android uses.
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/renderthread/CacheManager.cpp#41
|
||||
size_t max_bytes = metrics.physical_width * metrics.physical_height * 12 * 4;
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/39ae5bac216757bc201490f4c7b8c0f63006c6cd/libs/hwui/renderthread/CacheManager.cpp#45
|
||||
resource_cache_limit_ =
|
||||
metrics.physical_width * metrics.physical_height * 12 * 4;
|
||||
size_t resource_cache_max_bytes =
|
||||
resource_cache_limit_calculator_->GetResourceCacheMaxBytes();
|
||||
task_runners_.GetRasterTaskRunner()->PostTask(
|
||||
[rasterizer = rasterizer_->GetWeakPtr(), max_bytes] {
|
||||
[rasterizer = rasterizer_->GetWeakPtr(), resource_cache_max_bytes] {
|
||||
if (rasterizer) {
|
||||
rasterizer->SetResourceCacheMaxBytes(max_bytes, false);
|
||||
rasterizer->SetResourceCacheMaxBytes(resource_cache_max_bytes, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "flutter/shell/common/engine.h"
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/common/rasterizer.h"
|
||||
#include "flutter/shell/common/resource_cache_limit_calculator.h"
|
||||
#include "flutter/shell/common/shell_io_manager.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -108,7 +109,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
public Animator::Delegate,
|
||||
public Engine::Delegate,
|
||||
public Rasterizer::Delegate,
|
||||
public ServiceProtocol::Handler {
|
||||
public ServiceProtocol::Handler,
|
||||
public ResourceCacheLimitItem {
|
||||
public:
|
||||
template <class T>
|
||||
using CreateCallback = std::function<std::unique_ptr<T>(Shell&)>;
|
||||
@ -410,6 +412,9 @@ class Shell final : public PlatformView::Delegate,
|
||||
|
||||
const TaskRunners task_runners_;
|
||||
const fml::RefPtr<fml::RasterThreadMerger> parent_raster_thread_merger_;
|
||||
std::shared_ptr<ResourceCacheLimitCalculator>
|
||||
resource_cache_limit_calculator_;
|
||||
size_t resource_cache_limit_;
|
||||
const Settings settings_;
|
||||
DartVMRef vm_;
|
||||
mutable std::mutex time_recorder_mutex_;
|
||||
@ -476,6 +481,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
Shell(DartVMRef vm,
|
||||
TaskRunners task_runners,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_merger,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
Settings settings,
|
||||
std::shared_ptr<VolatilePathTracker> volatile_path_tracker,
|
||||
bool is_gpu_disabled);
|
||||
@ -484,6 +491,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
DartVMRef vm,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_merger,
|
||||
std::shared_ptr<ShellIOManager> parent_io_manager,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
TaskRunners task_runners,
|
||||
const PlatformData& platform_data,
|
||||
Settings settings,
|
||||
@ -492,11 +501,14 @@ class Shell final : public PlatformView::Delegate,
|
||||
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
|
||||
const EngineCreateCallback& on_create_engine,
|
||||
bool is_gpu_disabled);
|
||||
|
||||
static std::unique_ptr<Shell> CreateWithSnapshot(
|
||||
const PlatformData& platform_data,
|
||||
TaskRunners task_runners,
|
||||
fml::RefPtr<fml::RasterThreadMerger> parent_thread_merger,
|
||||
std::shared_ptr<ShellIOManager> parent_io_manager,
|
||||
const std::shared_ptr<ResourceCacheLimitCalculator>&
|
||||
resource_cache_limit_calculator,
|
||||
Settings settings,
|
||||
DartVMRef vm,
|
||||
fml::RefPtr<const DartSnapshot> isolate_snapshot,
|
||||
@ -694,6 +706,9 @@ class Shell final : public PlatformView::Delegate,
|
||||
const ServiceProtocol::Handler::ServiceProtocolMap& params,
|
||||
rapidjson::Document* response);
|
||||
|
||||
// |ResourceCacheLimitItem|
|
||||
size_t GetResourceCacheLimit() override { return resource_cache_limit_; };
|
||||
|
||||
// Creates an asset bundle from the original settings asset path or
|
||||
// directory.
|
||||
std::unique_ptr<DirectoryAssetBundle> RestoreOriginalAssetResolver();
|
||||
|
||||
@ -107,6 +107,7 @@ class MockPlatformViewDelegate : public PlatformView::Delegate {
|
||||
};
|
||||
|
||||
class MockSurface : public Surface {
|
||||
public:
|
||||
MOCK_METHOD0(IsValid, bool());
|
||||
|
||||
MOCK_METHOD1(AcquireFrame,
|
||||
@ -130,6 +131,13 @@ class MockPlatformView : public PlatformView {
|
||||
std::shared_ptr<PlatformMessageHandler>());
|
||||
};
|
||||
|
||||
class TestPlatformView : public PlatformView {
|
||||
public:
|
||||
TestPlatformView(Shell& shell, TaskRunners task_runners)
|
||||
: PlatformView(shell, task_runners) {}
|
||||
MOCK_METHOD0(CreateRenderingSurface, std::unique_ptr<Surface>());
|
||||
};
|
||||
|
||||
class MockPlatformMessageHandler : public PlatformMessageHandler {
|
||||
public:
|
||||
MOCK_METHOD1(HandlePlatformMessage,
|
||||
@ -1562,6 +1570,128 @@ static size_t GetRasterizerResourceCacheBytesSync(const Shell& shell) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
TEST_F(ShellTest, MultipleFluttersSetResourceCacheBytes) {
|
||||
TaskRunners task_runners = GetTaskRunnersForFixture();
|
||||
auto settings = CreateSettingsForFixture();
|
||||
settings.resource_cache_max_bytes_threshold = 4000000U;
|
||||
GrMockOptions main_context_options;
|
||||
sk_sp<GrDirectContext> main_context =
|
||||
GrDirectContext::MakeMock(&main_context_options);
|
||||
Shell::CreateCallback<PlatformView> platform_view_create_callback =
|
||||
[task_runners, main_context](flutter::Shell& shell) {
|
||||
auto result = std::make_unique<TestPlatformView>(shell, task_runners);
|
||||
ON_CALL(*result, CreateRenderingSurface())
|
||||
.WillByDefault(::testing::Invoke([main_context] {
|
||||
auto surface = std::make_unique<MockSurface>();
|
||||
ON_CALL(*surface, GetContext())
|
||||
.WillByDefault(Return(main_context.get()));
|
||||
ON_CALL(*surface, IsValid()).WillByDefault(Return(true));
|
||||
ON_CALL(*surface, MakeRenderContextCurrent())
|
||||
.WillByDefault(::testing::Invoke([] {
|
||||
return std::make_unique<GLContextDefaultResult>(true);
|
||||
}));
|
||||
return surface;
|
||||
}));
|
||||
return result;
|
||||
};
|
||||
|
||||
auto shell = CreateShell(
|
||||
/*settings=*/std::move(settings),
|
||||
/*task_runners=*/task_runners,
|
||||
/*simulate_vsync=*/false,
|
||||
/*shell_test_external_view_embedder=*/nullptr,
|
||||
/*is_gpu_disabled=*/false,
|
||||
/*rendering_backend=*/
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend,
|
||||
/*platform_view_create_callback=*/platform_view_create_callback);
|
||||
|
||||
// Create the surface needed by rasterizer
|
||||
PlatformViewNotifyCreated(shell.get());
|
||||
|
||||
auto configuration = RunConfiguration::InferFromSettings(settings);
|
||||
configuration.SetEntrypoint("emptyMain");
|
||||
|
||||
RunEngine(shell.get(), std::move(configuration));
|
||||
PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() {
|
||||
shell->GetPlatformView()->SetViewportMetrics({1.0, 100, 100, 22});
|
||||
});
|
||||
|
||||
// first cache bytes
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(480000U));
|
||||
|
||||
auto shell_spawn_callback = [&]() {
|
||||
std::unique_ptr<Shell> spawn;
|
||||
PostSync(
|
||||
shell->GetTaskRunners().GetPlatformTaskRunner(),
|
||||
[this, &spawn, &spawner = shell, platform_view_create_callback]() {
|
||||
auto configuration =
|
||||
RunConfiguration::InferFromSettings(CreateSettingsForFixture());
|
||||
configuration.SetEntrypoint("emptyMain");
|
||||
spawn = spawner->Spawn(
|
||||
std::move(configuration), "", platform_view_create_callback,
|
||||
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); });
|
||||
ASSERT_NE(nullptr, spawn.get());
|
||||
ASSERT_TRUE(ValidateShell(spawn.get()));
|
||||
});
|
||||
return spawn;
|
||||
};
|
||||
|
||||
std::unique_ptr<Shell> second_shell = shell_spawn_callback();
|
||||
PlatformViewNotifyCreated(second_shell.get());
|
||||
PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(),
|
||||
[&second_shell]() {
|
||||
second_shell->GetPlatformView()->SetViewportMetrics(
|
||||
{1.0, 100, 100, 22});
|
||||
});
|
||||
// first cache bytes + second cache bytes
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(960000U));
|
||||
|
||||
PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(),
|
||||
[&second_shell]() {
|
||||
second_shell->GetPlatformView()->SetViewportMetrics(
|
||||
{1.0, 100, 300, 22});
|
||||
});
|
||||
// first cache bytes + second cache bytes
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(1920000U));
|
||||
|
||||
std::unique_ptr<Shell> third_shell = shell_spawn_callback();
|
||||
PlatformViewNotifyCreated(third_shell.get());
|
||||
PostSync(
|
||||
third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() {
|
||||
third_shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 100, 22});
|
||||
});
|
||||
// first cache bytes + second cache bytes + third cache bytes
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(3840000U));
|
||||
|
||||
PostSync(
|
||||
third_shell->GetTaskRunners().GetPlatformTaskRunner(), [&third_shell]() {
|
||||
third_shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 100, 22});
|
||||
});
|
||||
// max bytes threshold
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(4000000U));
|
||||
DestroyShell(std::move(third_shell), std::move(task_runners));
|
||||
// max bytes threshold
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(4000000U));
|
||||
|
||||
PostSync(second_shell->GetTaskRunners().GetPlatformTaskRunner(),
|
||||
[&second_shell]() {
|
||||
second_shell->GetPlatformView()->SetViewportMetrics(
|
||||
{1.0, 100, 100, 22});
|
||||
});
|
||||
// first cache bytes + second cache bytes
|
||||
EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell),
|
||||
static_cast<size_t>(960000U));
|
||||
|
||||
DestroyShell(std::move(second_shell), std::move(task_runners));
|
||||
DestroyShell(std::move(shell), std::move(task_runners));
|
||||
}
|
||||
|
||||
TEST_F(ShellTest, SetResourceCacheSize) {
|
||||
Settings settings = CreateSettingsForFixture();
|
||||
auto task_runner = CreateNewThread();
|
||||
|
||||
@ -470,6 +470,16 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
settings.old_gen_heap_size = std::stoi(old_gen_heap_size);
|
||||
}
|
||||
|
||||
if (command_line.HasOption(
|
||||
FlagForSwitch(Switch::ResourceCacheMaxBytesThreshold))) {
|
||||
std::string resource_cache_max_bytes_threshold;
|
||||
command_line.GetOptionValue(
|
||||
FlagForSwitch(Switch::ResourceCacheMaxBytesThreshold),
|
||||
&resource_cache_max_bytes_threshold);
|
||||
settings.resource_cache_max_bytes_threshold =
|
||||
std::stoi(resource_cache_max_bytes_threshold);
|
||||
}
|
||||
|
||||
if (command_line.HasOption(FlagForSwitch(Switch::MsaaSamples))) {
|
||||
std::string msaa_samples;
|
||||
command_line.GetOptionValue(FlagForSwitch(Switch::MsaaSamples),
|
||||
|
||||
@ -220,6 +220,10 @@ DEF_SWITCH(
|
||||
DEF_SWITCH(OldGenHeapSize,
|
||||
"old-gen-heap-size",
|
||||
"The size limit in megabytes for the Dart VM old gen heap space.")
|
||||
|
||||
DEF_SWITCH(ResourceCacheMaxBytesThreshold,
|
||||
"resource-cache-max-bytes-threshold",
|
||||
"The max bytes threshold of resource cache, or 0 for unlimited.")
|
||||
DEF_SWITCH(EnableSkParagraph,
|
||||
"enable-skparagraph",
|
||||
"Selects the SkParagraph implementation of the text layout engine.")
|
||||
|
||||
@ -15,6 +15,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.WindowManager;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -302,9 +303,16 @@ public class FlutterLoader {
|
||||
activityManager.getMemoryInfo(memInfo);
|
||||
oldGenHeapSizeMegaBytes = (int) (memInfo.totalMem / 1e6 / 2);
|
||||
}
|
||||
|
||||
shellArgs.add("--old-gen-heap-size=" + oldGenHeapSizeMegaBytes);
|
||||
|
||||
DisplayMetrics displayMetrics = applicationContext.getResources().getDisplayMetrics();
|
||||
int screenWidth = displayMetrics.widthPixels;
|
||||
int screenHeight = displayMetrics.heightPixels;
|
||||
// This is the formula Android uses.
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/39ae5bac216757bc201490f4c7b8c0f63006c6cd/libs/hwui/renderthread/CacheManager.cpp#45
|
||||
int resourceCacheMaxBytesThreshold = screenWidth * screenHeight * 12 * 4;
|
||||
shellArgs.add("--resource-cache-max-bytes-threshold=" + resourceCacheMaxBytesThreshold);
|
||||
|
||||
shellArgs.add("--prefetched-default-font-manager");
|
||||
|
||||
if (metaData == null || metaData.getBoolean(ENABLE_SKPARAGRAPH_META_DATA_KEY, true)) {
|
||||
|
||||
@ -22,6 +22,7 @@ import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import java.util.Arrays;
|
||||
@ -87,6 +88,36 @@ public class FlutterLoaderTest {
|
||||
assertTrue(arguments.contains(oldGenHeapArg));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itDefaultsTheResourceCacheMaxBytesThresholdAppropriately() {
|
||||
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
|
||||
FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI);
|
||||
|
||||
assertFalse(flutterLoader.initialized());
|
||||
flutterLoader.startInitialization(RuntimeEnvironment.application);
|
||||
flutterLoader.ensureInitializationComplete(RuntimeEnvironment.application, null);
|
||||
shadowOf(getMainLooper()).idle();
|
||||
|
||||
DisplayMetrics displayMetrics =
|
||||
RuntimeEnvironment.application.getResources().getDisplayMetrics();
|
||||
int screenWidth = displayMetrics.widthPixels;
|
||||
int screenHeight = displayMetrics.heightPixels;
|
||||
int resourceCacheMaxBytesThreshold = screenWidth * screenHeight * 12 * 4;
|
||||
final String resourceCacheMaxBytesThresholdArg =
|
||||
"--resource-cache-max-bytes-threshold=" + resourceCacheMaxBytesThreshold;
|
||||
ArgumentCaptor<String[]> shellArgsCaptor = ArgumentCaptor.forClass(String[].class);
|
||||
verify(mockFlutterJNI, times(1))
|
||||
.init(
|
||||
eq(RuntimeEnvironment.application),
|
||||
shellArgsCaptor.capture(),
|
||||
anyString(),
|
||||
anyString(),
|
||||
anyString(),
|
||||
anyLong());
|
||||
List<String> arguments = Arrays.asList(shellArgsCaptor.getValue());
|
||||
assertTrue(arguments.contains(resourceCacheMaxBytesThresholdArg));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itSetsLeakVMToTrueByDefault() {
|
||||
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
|
||||
|
||||
@ -195,6 +195,14 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle) {
|
||||
settings.old_gen_heap_size = std::round([NSProcessInfo processInfo].physicalMemory * .48 /
|
||||
flutter::kMegaByteSizeInBytes);
|
||||
}
|
||||
|
||||
// This is the formula Android uses.
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/39ae5bac216757bc201490f4c7b8c0f63006c6cd/libs/hwui/renderthread/CacheManager.cpp#45
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
|
||||
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
|
||||
settings.resource_cache_max_bytes_threshold = screenWidth * screenHeight * 12 * 4;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,16 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertEqual(project.settings.old_gen_heap_size, old_gen_heap_size);
|
||||
}
|
||||
|
||||
- (void)testResourceCacheMaxBytesThresholdSetting {
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc] init];
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
|
||||
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
|
||||
size_t resource_cache_max_bytes_threshold = screenWidth * screenHeight * 12 * 4;
|
||||
XCTAssertEqual(project.settings.resource_cache_max_bytes_threshold,
|
||||
resource_cache_max_bytes_threshold);
|
||||
}
|
||||
|
||||
- (void)testMainBundleSettingsAreCorrectlyParsed {
|
||||
NSBundle* mainBundle = [NSBundle mainBundle];
|
||||
NSDictionary* appTransportSecurity =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user