Commit 2e538b99 authored by Hajime Hoshi's avatar Hajime Hoshi Committed by Commit Bot

Avoid using TaskObserver at MemoryCache

We want to avoid TaskObserver since this binds the current message
loop's default task runner and a class tightly.

This CL makes MemoryCache not be a TaskObserver and actual pruning is
deferred by posting a task. This changes the behavior that the pruning
task is enqueued to the end of the task runner. This should not affect
actual memory usages so much.

This CL also replaces the default task runner usages in the tests with
the test task runner since we also want to avoid the default task runner
in the test as much as possible.

Bug: 870606
Change-Id: I6865ffe2a02800b5106b6da8605e7624498d6316
Reviewed-on: https://chromium-review.googlesource.com/c/1258805Reviewed-by: default avatarHiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Commit-Queue: Hajime Hoshi <hajimehoshi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596476}
parent c7083bbc
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
...@@ -74,7 +75,8 @@ class ImageBitmapTest : public testing::Test { ...@@ -74,7 +75,8 @@ class ImageBitmapTest : public testing::Test {
image2_ = surface2->makeImageSnapshot(); image2_ = surface2->makeImageSnapshot();
// Save the global memory cache to restore it upon teardown. // Save the global memory cache to restore it upon teardown.
global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
auto factory = [](FakeGLES2Interface* gl, bool* gpu_compositing_disabled) auto factory = [](FakeGLES2Interface* gl, bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> { -> std::unique_ptr<WebGraphicsContext3DProvider> {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/core/css/css_crossfade_value.h" #include "third_party/blink/renderer/core/css/css_crossfade_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h" #include "third_party/blink/renderer/core/css/css_image_value.h"
...@@ -45,8 +46,8 @@ namespace { ...@@ -45,8 +46,8 @@ namespace {
class CSSStyleSheetResourceTest : public PageTestBase { class CSSStyleSheetResourceTest : public PageTestBase {
protected: protected:
CSSStyleSheetResourceTest() { CSSStyleSheetResourceTest() {
original_memory_cache_ = original_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
ReplaceMemoryCacheForTesting(MemoryCache::Create()); blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
} }
~CSSStyleSheetResourceTest() override { ~CSSStyleSheetResourceTest() override {
......
...@@ -231,7 +231,8 @@ void CanvasRenderingContext2DTest::SetUp() { ...@@ -231,7 +231,8 @@ void CanvasRenderingContext2DTest::SetUp() {
StringOrCanvasGradientOrCanvasPattern wrapped_alpha_gradient; StringOrCanvasGradientOrCanvasPattern wrapped_alpha_gradient;
this->AlphaGradient().SetCanvasGradient(alpha_gradient); this->AlphaGradient().SetCanvasGradient(alpha_gradient);
global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
} }
void CanvasRenderingContext2DTest::TearDown() { void CanvasRenderingContext2DTest::TearDown() {
......
...@@ -46,8 +46,10 @@ static const float kCTargetPrunePercentage = .95f; ...@@ -46,8 +46,10 @@ static const float kCTargetPrunePercentage = .95f;
MemoryCache* GetMemoryCache() { MemoryCache* GetMemoryCache() {
DCHECK(WTF::IsMainThread()); DCHECK(WTF::IsMainThread());
if (!g_memory_cache) if (!g_memory_cache) {
g_memory_cache = new Persistent<MemoryCache>(MemoryCache::Create()); g_memory_cache = new Persistent<MemoryCache>(MemoryCache::Create(
Platform::Current()->MainThread()->GetTaskRunner()));
}
return g_memory_cache->Get(); return g_memory_cache->Get();
} }
...@@ -72,7 +74,8 @@ void MemoryCacheEntry::ClearResourceWeak(Visitor* visitor) { ...@@ -72,7 +74,8 @@ void MemoryCacheEntry::ClearResourceWeak(Visitor* visitor) {
resource_.Clear(); resource_.Clear();
} }
inline MemoryCache::MemoryCache() inline MemoryCache::MemoryCache(
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: in_prune_resources_(false), : in_prune_resources_(false),
prune_pending_(false), prune_pending_(false),
max_prune_deferral_delay_(kCMaxPruneDeferralDelay), max_prune_deferral_delay_(kCMaxPruneDeferralDelay),
...@@ -81,20 +84,19 @@ inline MemoryCache::MemoryCache() ...@@ -81,20 +84,19 @@ inline MemoryCache::MemoryCache()
last_frame_paint_time_stamp_(0.0), last_frame_paint_time_stamp_(0.0),
capacity_(kCDefaultCacheCapacity), capacity_(kCDefaultCacheCapacity),
delay_before_live_decoded_prune_(kCMinDelayBeforeLiveDecodedPrune), delay_before_live_decoded_prune_(kCMinDelayBeforeLiveDecodedPrune),
size_(0) { size_(0),
task_runner_(std::move(task_runner)) {
MemoryCacheDumpProvider::Instance()->SetMemoryCache(this); MemoryCacheDumpProvider::Instance()->SetMemoryCache(this);
if (MemoryCoordinator::IsLowEndDevice()) if (MemoryCoordinator::IsLowEndDevice())
MemoryCoordinator::Instance().RegisterClient(this); MemoryCoordinator::Instance().RegisterClient(this);
} }
MemoryCache* MemoryCache::Create() { MemoryCache* MemoryCache::Create(
return new MemoryCache; scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
return new MemoryCache(std::move(task_runner));
} }
MemoryCache::~MemoryCache() { MemoryCache::~MemoryCache() = default;
if (prune_pending_)
Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
}
void MemoryCache::Trace(blink::Visitor* visitor) { void MemoryCache::Trace(blink::Visitor* visitor) {
visitor->Trace(resource_maps_); visitor->Trace(resource_maps_);
...@@ -367,43 +369,33 @@ void MemoryCache::Prune() { ...@@ -367,43 +369,33 @@ void MemoryCache::Prune() {
double current_time = WTF::CurrentTime(); double current_time = WTF::CurrentTime();
if (prune_pending_) { if (prune_pending_) {
if (current_time - prune_time_stamp_ >= max_prune_deferral_delay_) { if (current_time - prune_time_stamp_ >= max_prune_deferral_delay_) {
PruneNow(current_time, kAutomaticPrune); PruneNow(kAutomaticPrune);
} }
} else { } else {
if (current_time - prune_time_stamp_ >= max_prune_deferral_delay_) { if (current_time - prune_time_stamp_ >= max_prune_deferral_delay_) {
PruneNow(current_time, kAutomaticPrune); // Delay exceeded, prune now. PruneNow(kAutomaticPrune); // Delay exceeded, prune now.
} else { } else {
// Defer. // Defer.
Platform::Current()->CurrentThread()->AddTaskObserver(this); task_runner_->PostTask(
FROM_HERE, base::BindOnce(&MemoryCache::PruneNow,
base::Unretained(this), kAutomaticPrune));
prune_pending_ = true; prune_pending_ = true;
} }
} }
} }
void MemoryCache::WillProcessTask() {}
void MemoryCache::DidProcessTask() {
// Perform deferred pruning
DCHECK(prune_pending_);
PruneNow(WTF::CurrentTime(), kAutomaticPrune);
}
void MemoryCache::PruneAll() { void MemoryCache::PruneAll() {
double current_time = WTF::CurrentTime(); PruneNow(kMaximalPrune);
PruneNow(current_time, kMaximalPrune);
} }
void MemoryCache::PruneNow(double current_time, PruneStrategy strategy) { void MemoryCache::PruneNow(PruneStrategy strategy) {
if (prune_pending_) {
prune_pending_ = false; prune_pending_ = false;
Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
}
base::AutoReset<bool> reentrancy_protector(&in_prune_resources_, true); base::AutoReset<bool> reentrancy_protector(&in_prune_resources_, true);
PruneResources(strategy); PruneResources(strategy);
prune_frame_time_stamp_ = last_frame_paint_time_stamp_; prune_frame_time_stamp_ = last_frame_paint_time_stamp_;
prune_time_stamp_ = current_time; prune_time_stamp_ = WTF::CurrentTime();
} }
void MemoryCache::UpdateFramePaintTimestamp() { void MemoryCache::UpdateFramePaintTimestamp() {
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_MEMORY_CACHE_H_
#include "third_party/blink/public/platform/web_thread.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/memory_cache_dump_provider.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/memory_cache_dump_provider.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
#include "third_party/blink/renderer/platform/memory_coordinator.h" #include "third_party/blink/renderer/platform/memory_coordinator.h"
...@@ -72,14 +71,14 @@ WILL_NOT_BE_EAGERLY_TRACED_CLASS(MemoryCacheEntry); ...@@ -72,14 +71,14 @@ WILL_NOT_BE_EAGERLY_TRACED_CLASS(MemoryCacheEntry);
// stylesheets, etc. // stylesheets, etc.
class PLATFORM_EXPORT MemoryCache final class PLATFORM_EXPORT MemoryCache final
: public GarbageCollectedFinalized<MemoryCache>, : public GarbageCollectedFinalized<MemoryCache>,
public WebThread::TaskObserver,
public MemoryCacheDumpClient, public MemoryCacheDumpClient,
public MemoryCoordinatorClient { public MemoryCoordinatorClient {
USING_GARBAGE_COLLECTED_MIXIN(MemoryCache); USING_GARBAGE_COLLECTED_MIXIN(MemoryCache);
WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_NONCOPYABLE(MemoryCache);
public: public:
static MemoryCache* Create(); static MemoryCache* Create(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~MemoryCache() override; ~MemoryCache() override;
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
...@@ -156,10 +155,6 @@ class PLATFORM_EXPORT MemoryCache final ...@@ -156,10 +155,6 @@ class PLATFORM_EXPORT MemoryCache final
size_t Capacity() const { return capacity_; } size_t Capacity() const { return capacity_; }
size_t size() const { return size_; } size_t size() const { return size_; }
// TaskObserver implementation
void WillProcessTask() override;
void DidProcessTask() override;
void PruneAll(); void PruneAll();
void UpdateFramePaintTimestamp(); void UpdateFramePaintTimestamp();
...@@ -186,13 +181,13 @@ class PLATFORM_EXPORT MemoryCache final ...@@ -186,13 +181,13 @@ class PLATFORM_EXPORT MemoryCache final
ResourceMap* EnsureResourceMap(const String& cache_identifier); ResourceMap* EnsureResourceMap(const String& cache_identifier);
ResourceMapIndex resource_maps_; ResourceMapIndex resource_maps_;
MemoryCache(); explicit MemoryCache(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
void AddInternal(ResourceMap*, MemoryCacheEntry*); void AddInternal(ResourceMap*, MemoryCacheEntry*);
void RemoveInternal(ResourceMap*, const ResourceMap::iterator&); void RemoveInternal(ResourceMap*, const ResourceMap::iterator&);
void PruneResources(PruneStrategy); void PruneResources(PruneStrategy);
void PruneNow(double current_time, PruneStrategy); void PruneNow(PruneStrategy);
bool in_prune_resources_; bool in_prune_resources_;
bool prune_pending_; bool prune_pending_;
...@@ -208,6 +203,8 @@ class PLATFORM_EXPORT MemoryCache final ...@@ -208,6 +203,8 @@ class PLATFORM_EXPORT MemoryCache final
// The number of bytes currently consumed by resources in the cache. // The number of bytes currently consumed by resources in the cache.
size_t size_; size_t size_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
friend class MemoryCacheTest; friend class MemoryCacheTest;
}; };
......
...@@ -111,7 +111,8 @@ class MemoryCacheCorrectnessTest : public testing::Test { ...@@ -111,7 +111,8 @@ class MemoryCacheCorrectnessTest : public testing::Test {
// Overrides testing::Test. // Overrides testing::Test.
void SetUp() override { void SetUp() override {
// Save the global memory cache to restore it upon teardown. // Save the global memory cache to restore it upon teardown.
global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); global_memory_cache_ = ReplaceMemoryCacheForTesting(
MemoryCache::Create(platform_->test_task_runner()));
MockFetchContext* context = MockFetchContext* context =
MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource); MockFetchContext::Create(MockFetchContext::kShouldNotLoadNewResource);
......
...@@ -106,7 +106,8 @@ class MemoryCacheTest : public testing::Test { ...@@ -106,7 +106,8 @@ class MemoryCacheTest : public testing::Test {
protected: protected:
void SetUp() override { void SetUp() override {
// Save the global memory cache to restore it upon teardown. // Save the global memory cache to restore it upon teardown.
global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); global_memory_cache_ = ReplaceMemoryCacheForTesting(
MemoryCache::Create(platform_->test_task_runner()));
fetcher_ = ResourceFetcher::Create( fetcher_ = ResourceFetcher::Create(
MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource)); MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource));
} }
...@@ -157,7 +158,7 @@ TEST_F(MemoryCacheTest, MAYBE_VeryLargeResourceAccounting) { ...@@ -157,7 +158,7 @@ TEST_F(MemoryCacheTest, MAYBE_VeryLargeResourceAccounting) {
EXPECT_EQ(cached_resource->size(), GetMemoryCache()->size()); EXPECT_EQ(cached_resource->size(), GetMemoryCache()->size());
} }
static void RunTask1(Resource* resource1, Resource* resource2) { static void RunTask(Resource* resource1, Resource* resource2) {
// The resource size has to be nonzero for this test to be meaningful, but // The resource size has to be nonzero for this test to be meaningful, but
// we do not rely on it having any particular value. // we do not rely on it having any particular value.
EXPECT_GT(resource1->size(), 0u); EXPECT_GT(resource1->size(), 0u);
...@@ -173,23 +174,20 @@ static void RunTask1(Resource* resource1, Resource* resource2) { ...@@ -173,23 +174,20 @@ static void RunTask1(Resource* resource1, Resource* resource2) {
EXPECT_GT(resource1->DecodedSize(), 0u); EXPECT_GT(resource1->DecodedSize(), 0u);
EXPECT_GT(resource2->DecodedSize(), 0u); EXPECT_GT(resource2->DecodedSize(), 0u);
// We expect actual pruning doesn't occur here synchronously but deferred // We expect actual pruning doesn't occur here synchronously but deferred,
// to the end of this task, due to the previous pruning invoked in // due to the previous pruning invoked in TestResourcePruningLater().
// testResourcePruningAtEndOfTask().
GetMemoryCache()->Prune(); GetMemoryCache()->Prune();
EXPECT_EQ(total_size, GetMemoryCache()->size()); EXPECT_EQ(total_size, GetMemoryCache()->size());
EXPECT_GT(resource1->DecodedSize(), 0u); EXPECT_GT(resource1->DecodedSize(), 0u);
EXPECT_GT(resource2->DecodedSize(), 0u); EXPECT_GT(resource2->DecodedSize(), 0u);
} }
static void RunTask2(unsigned size_without_decode) { static void TestResourcePruningLater(ResourceFetcher* fetcher,
// Next task: now, the resources was pruned.
EXPECT_EQ(size_without_decode, GetMemoryCache()->size());
}
static void TestResourcePruningAtEndOfTask(ResourceFetcher* fetcher,
const String& identifier1, const String& identifier1,
const String& identifier2) { const String& identifier2) {
auto* platform = static_cast<TestingPlatformSupportWithMockScheduler*>(
Platform::Current());
GetMemoryCache()->SetDelayBeforeLiveDecodedPrune(0); GetMemoryCache()->SetDelayBeforeLiveDecodedPrune(0);
// Enforce pruning by adding |dummyResource| and then call prune(). // Enforce pruning by adding |dummyResource| and then call prune().
...@@ -221,46 +219,44 @@ static void TestResourcePruningAtEndOfTask(ResourceFetcher* fetcher, ...@@ -221,46 +219,44 @@ static void TestResourcePruningAtEndOfTask(ResourceFetcher* fetcher,
resource2->AppendData(kData, 4u); resource2->AppendData(kData, 4u);
resource2->FinishForTest(); resource2->FinishForTest();
Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( platform->test_task_runner()->PostTask(
FROM_HERE, WTF::Bind(&RunTask1, WrapPersistent(resource1), FROM_HERE, WTF::Bind(&RunTask, WrapPersistent(resource1),
WrapPersistent(resource2))); WrapPersistent(resource2)));
Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( platform->RunUntilIdle();
FROM_HERE,
WTF::Bind(&RunTask2, // Now, the resources was pruned.
unsigned size_without_decode =
resource1->EncodedSize() + resource1->OverheadSize() + resource1->EncodedSize() + resource1->OverheadSize() +
resource2->EncodedSize() + resource2->OverheadSize())); resource2->EncodedSize() + resource2->OverheadSize();
static_cast<TestingPlatformSupportWithMockScheduler*>(Platform::Current()) EXPECT_EQ(size_without_decode, GetMemoryCache()->size());
->RunUntilIdle();
} }
// Verified that when ordering a prune in a runLoop task, the prune // Verified that when ordering a prune in a runLoop task, the prune is deferred.
// is deferred to the end of the task.
// TODO(crbug.com/850788): Reenable this. // TODO(crbug.com/850788): Reenable this.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#define MAYBE_ResourcePruningAtEndOfTask_Basic \ #define MAYBE_ResourcePruningLater_Basic DISABLED_ResourcePruningLater_Basic
DISABLED_ResourcePruningAtEndOfTask_Basic
#else #else
#define MAYBE_ResourcePruningAtEndOfTask_Basic ResourcePruningAtEndOfTask_Basic #define MAYBE_ResourcePruningLater_Basic ResourcePruningLater_Basic
#endif #endif
TEST_F(MemoryCacheTest, MAYBE_ResourcePruningAtEndOfTask_Basic) { TEST_F(MemoryCacheTest, MAYBE_ResourcePruningLater_Basic) {
TestResourcePruningAtEndOfTask(fetcher_, "", ""); TestResourcePruningLater(fetcher_, "", "");
} }
// TODO(crbug.com/850788): Reenable this. // TODO(crbug.com/850788): Reenable this.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#define MAYBE_ResourcePruningAtEndOfTask_MultipleResourceMaps \ #define MAYBE_ResourcePruningLater_MultipleResourceMaps \
DISABLED_ResourcePruningAtEndOfTask_MultipleResourceMaps DISABLED_ResourcePruningLater_MultipleResourceMaps
#else #else
#define MAYBE_ResourcePruningAtEndOfTask_MultipleResourceMaps \ #define MAYBE_ResourcePruningLater_MultipleResourceMaps \
ResourcePruningAtEndOfTask_MultipleResourceMaps ResourcePruningLater_MultipleResourceMaps
#endif #endif
TEST_F(MemoryCacheTest, MAYBE_ResourcePruningAtEndOfTask_MultipleResourceMaps) { TEST_F(MemoryCacheTest, MAYBE_ResourcePruningLater_MultipleResourceMaps) {
{ {
TestResourcePruningAtEndOfTask(fetcher_, "foo", ""); TestResourcePruningLater(fetcher_, "foo", "");
GetMemoryCache()->EvictResources(); GetMemoryCache()->EvictResources();
} }
{ {
TestResourcePruningAtEndOfTask(fetcher_, "foo", "bar"); TestResourcePruningLater(fetcher_, "foo", "bar");
GetMemoryCache()->EvictResources(); GetMemoryCache()->EvictResources();
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment