Skip to content

Commit

Permalink
blink: Add ParkableStringManager, don't track off-main thread strings.
Browse files Browse the repository at this point in the history
ParkableStringManager tracks all the current ParkableStrings. This
replace ParkableStringTable.
Since strings not on the main thread were never parked, don't remember
them at all.

Bug: 877044
Change-Id: I17ad0b4fc38264ddb344776a5b202fa5475bb906
Reviewed-on: https://chromium-review.googlesource.com/1199383
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: Alexander Timin <altimin@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588843}
  • Loading branch information
Benoit Lize authored and Commit Bot committed Sep 5, 2018
1 parent 1677f1e commit 5a1630f
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 139 deletions.
2 changes: 2 additions & 0 deletions third_party/blink/renderer/platform/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ jumbo_component("platform") {
"bindings/origin_trial_features.h",
"bindings/parkable_string.cc",
"bindings/parkable_string.h",
"bindings/parkable_string_manager.cc",
"bindings/parkable_string_manager.h",
"bindings/runtime_call_stats.cc",
"bindings/runtime_call_stats.h",
"bindings/scoped_persistent.h",
Expand Down
75 changes: 7 additions & 68 deletions third_party/blink/renderer/platform/bindings/parkable_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,13 @@
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"

#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
#include "third_party/blink/renderer/platform/wtf/thread_specific.h"

namespace blink {

namespace {

bool IsLargeEnough(const StringImpl* impl) {
// Don't attempt to park strings smaller than this size.
static constexpr unsigned int kSizeThreshold = 10000;
return impl && impl->length() > kSizeThreshold;
}

void RecordParkingAction(ParkableStringImpl::ParkingAction action) {
UMA_HISTOGRAM_ENUMERATION("Memory.MovableStringParkingAction", action);
}
Expand All @@ -29,7 +24,8 @@ ParkableStringImpl::ParkableStringImpl(scoped_refptr<StringImpl>&& impl)
: string_(std::move(impl)), is_parked_(false) {}

ParkableStringImpl::~ParkableStringImpl() {
ParkableStringTable::Instance().Remove(string_.Impl());
if (ParkableStringManager::ShouldPark(string_.Impl()))
ParkableStringManager::Instance().Remove(string_.Impl());
}

bool ParkableStringImpl::Is8Bit() const {
Expand Down Expand Up @@ -62,16 +58,16 @@ void ParkableStringImpl::Unpark() {
if (!is_parked_)
return;

bool backgrounded = ParkableStringTable::Instance().IsRendererBackgrounded();
bool backgrounded =
ParkableStringManager::Instance().IsRendererBackgrounded();
RecordParkingAction(backgrounded ? ParkingAction::kUnparkedInBackground
: ParkingAction::kUnparkedInForeground);
is_parked_ = false;
}

ParkableString::ParkableString(scoped_refptr<StringImpl>&& impl) {
// Don't park small strings.
if (IsLargeEnough(impl.get())) {
impl_ = ParkableStringTable::Instance().Add(std::move(impl));
if (ParkableStringManager::ShouldPark(impl.get())) {
impl_ = ParkableStringManager::Instance().Add(std::move(impl));
} else {
impl_ = base::MakeRefCounted<ParkableStringImpl>(std::move(impl));
}
Expand All @@ -94,61 +90,4 @@ unsigned ParkableString::CharactersSizeInBytes() const {
return impl_->CharactersSizeInBytes();
}

// static
ParkableStringTable& ParkableStringTable::Instance() {
static auto* table = new WTF::ThreadSpecific<ParkableStringTable>();
return **table;
}

ParkableStringTable::ParkableStringTable() = default;
ParkableStringTable::~ParkableStringTable() = default;

scoped_refptr<ParkableStringImpl> ParkableStringTable::Add(
scoped_refptr<StringImpl>&& string) {
StringImpl* raw_ptr = string.get();
auto it = table_.find(raw_ptr);
if (it != table_.end()) {
return it->second;
}
auto new_parkable_string =
base::MakeRefCounted<ParkableStringImpl>(std::move(string));
table_.emplace(raw_ptr, new_parkable_string.get());
return new_parkable_string;
}

void ParkableStringTable::Remove(StringImpl* string) {
if (!IsLargeEnough(string))
return;

auto it = table_.find(string);
DCHECK(it != table_.end());
table_.erase(it);
}

void ParkableStringTable::SetRendererBackgrounded(bool backgrounded) {
backgrounded_ = backgrounded;
}

bool ParkableStringTable::IsRendererBackgrounded() const {
return backgrounded_;
}

void ParkableStringTable::MaybeParkAll() {
if (!IsRendererBackgrounded())
return;

size_t total_size = 0, count = 0;
for (auto& kv : table_) {
ParkableStringImpl* str = kv.second;
str->Park();
total_size += str->CharactersSizeInBytes();
count += 1;
}

size_t total_size_kb = total_size / 1000;
UMA_HISTOGRAM_COUNTS_100000("Memory.MovableStringsTotalSizeKb",
total_size_kb);
UMA_HISTOGRAM_COUNTS_1000("Memory.MovableStringsCount", table_.size());
}

} // namespace blink
33 changes: 0 additions & 33 deletions third_party/blink/renderer/platform/bindings/parkable_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,39 +97,6 @@ class PLATFORM_EXPORT ParkableString final {
scoped_refptr<ParkableStringImpl> impl_;
};

// Per-thread registry of all ParkableString instances. NOT thread-safe.
class PLATFORM_EXPORT ParkableStringTable final {
public:
ParkableStringTable();
~ParkableStringTable();

static ParkableStringTable& Instance();

scoped_refptr<ParkableStringImpl> Add(scoped_refptr<StringImpl>&&);

// This is for ~ParkableStringImpl to unregister a string before
// destruction since the table is holding raw pointers. It should not be used
// directly.
void Remove(StringImpl*);

void SetRendererBackgrounded(bool backgrounded);
bool IsRendererBackgrounded() const;

// Parks all the strings in the table if currently in background.
void MaybeParkAll();

private:
bool backgrounded_;
// Could bet a set where the hashing function is
// ParkableStringImpl::string_.Impl(), but clearer this way.
std::map<StringImpl*, ParkableStringImpl*> table_;

FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableSimple);
FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableMultiple);

DISALLOW_COPY_AND_ASSIGN(ParkableStringTable);
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2018 The Chromium 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 "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"

#include <utility>

#include "base/bind.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_thread.h"
#include "third_party/blink/renderer/platform/bindings/parkable_string.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"

namespace blink {

ParkableStringManager& ParkableStringManager::Instance() {
DCHECK(IsMainThread());
static ParkableStringManager instance;
return instance;
}

ParkableStringManager::~ParkableStringManager() {}

void ParkableStringManager::SetRendererBackgrounded(bool backgrounded) {
backgrounded_ = backgrounded;

if (backgrounded_) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
Platform::Current()->CurrentThread()->GetTaskRunner();
if (task_runner) { // nullptr in tests.
task_runner->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ParkableStringManager::ParkAllIfRendererBackgrounded,
base::Unretained(this)),
base::TimeDelta::FromSeconds(10));
}
}
}

bool ParkableStringManager::IsRendererBackgrounded() const {
return backgrounded_;
}

// static
bool ParkableStringManager::ShouldPark(const StringImpl* string) {
// Don't attempt to park strings smaller than this size.
static constexpr unsigned int kSizeThreshold = 10000;
// TODO(lizeb): Consider parking non-main thread strings.
return string && string->length() > kSizeThreshold && IsMainThread();
}

scoped_refptr<ParkableStringImpl> ParkableStringManager::Add(
scoped_refptr<StringImpl>&& string) {
StringImpl* raw_ptr = string.get();
auto it = table_.find(raw_ptr);
if (it != table_.end())
return it->value;

auto new_parkable_string =
base::MakeRefCounted<ParkableStringImpl>(std::move(string));
table_.insert(raw_ptr, new_parkable_string.get());
return new_parkable_string;
}

void ParkableStringManager::Remove(StringImpl* string) {
DCHECK(ShouldPark(string));
auto it = table_.find(string);
DCHECK(it != table_.end());
table_.erase(it);
}

void ParkableStringManager::ParkAllIfRendererBackgrounded() {
DCHECK(IsMainThread());
if (!IsRendererBackgrounded())
return;

size_t total_size = 0, count = 0;
for (ParkableStringImpl* str : table_.Values()) {
str->Park();
total_size += str->CharactersSizeInBytes();
count += 1;
}

size_t total_size_kb = total_size / 1000;
UMA_HISTOGRAM_COUNTS_100000("Memory.MovableStringsTotalSizeKb",
total_size_kb);
UMA_HISTOGRAM_COUNTS_1000("Memory.MovableStringsCount", table_.size());
}

ParkableStringManager::ParkableStringManager()
: backgrounded_(false), table_() {}

} // namespace blink
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_MANAGER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_MANAGER_H_

#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class ParkableString;
class ParkableStringImpl;

// Manages all the ParkableStrings, and parks eligible strings after the
// renderer has been backgrounded.
// Main Thread only.
class PLATFORM_EXPORT ParkableStringManager {
USING_FAST_MALLOC(ParkableStringManager);

public:
static ParkableStringManager& Instance();
~ParkableStringManager();

void SetRendererBackgrounded(bool backgrounded);
bool IsRendererBackgrounded() const;

// Whether a string is parkable or not. Can be called from any thread.
static bool ShouldPark(const StringImpl* string);

private:
friend class ParkableString;
friend class ParkableStringImpl;

scoped_refptr<ParkableStringImpl> Add(scoped_refptr<StringImpl>&&);
void Remove(StringImpl*);

void ParkAllIfRendererBackgrounded();

ParkableStringManager();

bool backgrounded_;
HashMap<StringImpl*, ParkableStringImpl*, PtrHash<StringImpl>> table_;

FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableSimple);
FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableMultiple);
DISALLOW_COPY_AND_ASSIGN(ParkableStringManager);
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_MANAGER_H_
Loading

0 comments on commit 5a1630f

Please sign in to comment.