Commit 96baac4e authored by Benoit Lize's avatar Benoit Lize Committed by Commit Bot

[PartitionAlloc] Add more threading annotations to PartitionRoot.

Bug: 1013082, 998048
Change-Id: I9b44c0da86f9fd93046a57fdd7f397122b90e3f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2424218
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810009}
parent b9b346b3
...@@ -73,31 +73,33 @@ TEST_F(PartitionAllocMemoryReclaimerTest, Simple) { ...@@ -73,31 +73,33 @@ TEST_F(PartitionAllocMemoryReclaimerTest, Simple) {
TEST_F(PartitionAllocMemoryReclaimerTest, FreesMemory) { TEST_F(PartitionAllocMemoryReclaimerTest, FreesMemory) {
PartitionRoot<internal::ThreadSafe>* root = allocator_->root(); PartitionRoot<internal::ThreadSafe>* root = allocator_->root();
size_t committed_initially = root->total_size_of_committed_pages; size_t committed_initially =
root->total_size_of_committed_pages_for_testing();
AllocateAndFree(); AllocateAndFree();
size_t committed_before = root->total_size_of_committed_pages; size_t committed_before = root->total_size_of_committed_pages_for_testing();
EXPECT_GT(committed_before, committed_initially); EXPECT_GT(committed_before, committed_initially);
StartReclaimer(); StartReclaimer();
task_environment_.FastForwardBy( task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay()); task_environment_.NextMainThreadPendingTaskDelay());
size_t committed_after = root->total_size_of_committed_pages; size_t committed_after = root->total_size_of_committed_pages_for_testing();
EXPECT_LT(committed_after, committed_before); EXPECT_LT(committed_after, committed_before);
EXPECT_LE(committed_initially, committed_after); EXPECT_LE(committed_initially, committed_after);
} }
TEST_F(PartitionAllocMemoryReclaimerTest, Reclaim) { TEST_F(PartitionAllocMemoryReclaimerTest, Reclaim) {
PartitionRoot<internal::ThreadSafe>* root = allocator_->root(); PartitionRoot<internal::ThreadSafe>* root = allocator_->root();
size_t committed_initially = root->total_size_of_committed_pages; size_t committed_initially =
root->total_size_of_committed_pages_for_testing();
{ {
AllocateAndFree(); AllocateAndFree();
size_t committed_before = root->total_size_of_committed_pages; size_t committed_before = root->total_size_of_committed_pages_for_testing();
EXPECT_GT(committed_before, committed_initially); EXPECT_GT(committed_before, committed_initially);
PartitionAllocMemoryReclaimer::Instance()->Reclaim(); PartitionAllocMemoryReclaimer::Instance()->Reclaim();
size_t committed_after = root->total_size_of_committed_pages; size_t committed_after = root->total_size_of_committed_pages_for_testing();
EXPECT_LT(committed_after, committed_before); EXPECT_LT(committed_after, committed_before);
EXPECT_LE(committed_initially, committed_after); EXPECT_LE(committed_initially, committed_after);
......
...@@ -28,8 +28,13 @@ NOINLINE void PartitionRoot<thread_safe>::OutOfMemory(size_t size) { ...@@ -28,8 +28,13 @@ NOINLINE void PartitionRoot<thread_safe>::OutOfMemory(size_t size) {
#if !defined(ARCH_CPU_64_BITS) #if !defined(ARCH_CPU_64_BITS)
// Check whether this OOM is due to a lot of super pages that are allocated // Check whether this OOM is due to a lot of super pages that are allocated
// but not committed, probably due to http://crbug.com/421387. // but not committed, probably due to http://crbug.com/421387.
if (total_size_of_super_pages + total_size_of_direct_mapped_pages - //
total_size_of_committed_pages > // Reading values without locking is fine here, we are going to crash anyway,
// this is used for reporting only, and concurrent successful allocations are
// unlikely.
if (TS_UNCHECKED_READ(total_size_of_super_pages) +
TS_UNCHECKED_READ(total_size_of_direct_mapped_pages) -
TS_UNCHECKED_READ(total_size_of_committed_pages) >
kReasonableSizeOfUnusedPages) { kReasonableSizeOfUnusedPages) {
internal::PartitionOutOfMemoryWithLotsOfUncommitedPages(size); internal::PartitionOutOfMemoryWithLotsOfUncommitedPages(size);
} }
......
...@@ -384,9 +384,9 @@ struct BASE_EXPORT PartitionRoot { ...@@ -384,9 +384,9 @@ struct BASE_EXPORT PartitionRoot {
// Invariant: total_size_of_committed_pages <= // Invariant: total_size_of_committed_pages <=
// total_size_of_super_pages + // total_size_of_super_pages +
// total_size_of_direct_mapped_pages. // total_size_of_direct_mapped_pages.
size_t total_size_of_committed_pages = 0; size_t total_size_of_committed_pages GUARDED_BY(lock_) = 0;
size_t total_size_of_super_pages = 0; size_t total_size_of_super_pages GUARDED_BY(lock_) = 0;
size_t total_size_of_direct_mapped_pages = 0; size_t total_size_of_direct_mapped_pages GUARDED_BY(lock_) = 0;
bool is_thread_safe = thread_safe; bool is_thread_safe = thread_safe;
// TODO(bartekn): Consider size of added extras (cookies and/or tag, or // TODO(bartekn): Consider size of added extras (cookies and/or tag, or
// nothing) instead of true|false, so that we can just add or subtract the // nothing) instead of true|false, so that we can just add or subtract the
...@@ -440,8 +440,10 @@ struct BASE_EXPORT PartitionRoot { ...@@ -440,8 +440,10 @@ struct BASE_EXPORT PartitionRoot {
ALWAYS_INLINE static bool IsValidPage(Page* page); ALWAYS_INLINE static bool IsValidPage(Page* page);
ALWAYS_INLINE static PartitionRoot* FromPage(Page* page); ALWAYS_INLINE static PartitionRoot* FromPage(Page* page);
ALWAYS_INLINE void IncreaseCommittedPages(size_t len); ALWAYS_INLINE void IncreaseCommittedPages(size_t len)
ALWAYS_INLINE void DecreaseCommittedPages(size_t len); EXCLUSIVE_LOCKS_REQUIRED(lock_);
ALWAYS_INLINE void DecreaseCommittedPages(size_t len)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
ALWAYS_INLINE void DecommitSystemPages(void* address, size_t length) ALWAYS_INLINE void DecommitSystemPages(void* address, size_t length)
EXCLUSIVE_LOCKS_REQUIRED(lock_); EXCLUSIVE_LOCKS_REQUIRED(lock_);
ALWAYS_INLINE void RecommitSystemPages(void* address, size_t length) ALWAYS_INLINE void RecommitSystemPages(void* address, size_t length)
...@@ -508,6 +510,10 @@ struct BASE_EXPORT PartitionRoot { ...@@ -508,6 +510,10 @@ struct BASE_EXPORT PartitionRoot {
internal::ThreadCache* thread_cache_for_testing() const { internal::ThreadCache* thread_cache_for_testing() const {
return with_thread_cache ? internal::ThreadCache::Get() : nullptr; return with_thread_cache ? internal::ThreadCache::Get() : nullptr;
} }
size_t total_size_of_committed_pages_for_testing() {
ScopedGuard guard{lock_};
return total_size_of_committed_pages;
}
private: private:
// Allocates memory, without any cookies / tags. // Allocates memory, without any cookies / tags.
......
...@@ -1357,7 +1357,7 @@ TEST_F(PartitionAllocTest, MappingCollision) { ...@@ -1357,7 +1357,7 @@ TEST_F(PartitionAllocTest, MappingCollision) {
// Tests that pages in the free page cache do get freed as appropriate. // Tests that pages in the free page cache do get freed as appropriate.
TEST_F(PartitionAllocTest, FreeCache) { TEST_F(PartitionAllocTest, FreeCache) {
EXPECT_EQ(0U, allocator.root()->total_size_of_committed_pages); EXPECT_EQ(0U, allocator.root()->total_size_of_committed_pages_for_testing());
size_t big_size = 1000 - kExtraAllocSize; size_t big_size = 1000 - kExtraAllocSize;
size_t bucket_index = SizeToIndex(big_size + kExtraAllocSize); size_t bucket_index = SizeToIndex(big_size + kExtraAllocSize);
...@@ -1373,7 +1373,7 @@ TEST_F(PartitionAllocTest, FreeCache) { ...@@ -1373,7 +1373,7 @@ TEST_F(PartitionAllocTest, FreeCache) {
EXPECT_EQ(1, page->num_allocated_slots); EXPECT_EQ(1, page->num_allocated_slots);
size_t expected_committed_size = PartitionPageSize(); size_t expected_committed_size = PartitionPageSize();
EXPECT_EQ(expected_committed_size, EXPECT_EQ(expected_committed_size,
allocator.root()->total_size_of_committed_pages); allocator.root()->total_size_of_committed_pages_for_testing());
allocator.root()->Free(ptr); allocator.root()->Free(ptr);
EXPECT_EQ(0, page->num_allocated_slots); EXPECT_EQ(0, page->num_allocated_slots);
EXPECT_NE(-1, page->empty_cache_index); EXPECT_NE(-1, page->empty_cache_index);
...@@ -1390,7 +1390,8 @@ TEST_F(PartitionAllocTest, FreeCache) { ...@@ -1390,7 +1390,8 @@ TEST_F(PartitionAllocTest, FreeCache) {
size_t expected_size = size_t expected_size =
cycle_free_cache_bucket->num_system_pages_per_slot_span * cycle_free_cache_bucket->num_system_pages_per_slot_span *
SystemPageSize(); SystemPageSize();
EXPECT_EQ(expected_size, allocator.root()->total_size_of_committed_pages); EXPECT_EQ(expected_size,
allocator.root()->total_size_of_committed_pages_for_testing());
// Check that an allocation works ok whilst in this state (a free'd page // Check that an allocation works ok whilst in this state (a free'd page
// as the active pages head). // as the active pages head).
...@@ -1407,7 +1408,7 @@ TEST_F(PartitionAllocTest, FreeCache) { ...@@ -1407,7 +1408,7 @@ TEST_F(PartitionAllocTest, FreeCache) {
EXPECT_TRUE(page->freelist_head); EXPECT_TRUE(page->freelist_head);
} }
EXPECT_EQ(expected_committed_size, EXPECT_EQ(expected_committed_size,
allocator.root()->total_size_of_committed_pages); allocator.root()->total_size_of_committed_pages_for_testing());
} }
// Tests for a bug we had with losing references to free pages. // Tests for a bug we had with losing references to free pages.
......
...@@ -25,10 +25,9 @@ namespace internal { ...@@ -25,10 +25,9 @@ namespace internal {
namespace { namespace {
template <bool thread_safe> template <bool thread_safe>
ALWAYS_INLINE PartitionPage<thread_safe>* PartitionDirectMap( ALWAYS_INLINE PartitionPage<thread_safe>*
PartitionRoot<thread_safe>* root, PartitionDirectMap(PartitionRoot<thread_safe>* root, int flags, size_t raw_size)
int flags, EXCLUSIVE_LOCKS_REQUIRED(root->lock_) {
size_t raw_size) {
size_t size = PartitionBucket<thread_safe>::get_direct_map_size(raw_size); size_t size = PartitionBucket<thread_safe>::get_direct_map_size(raw_size);
// Because we need to fake looking like a super page, we need to allocate // Because we need to fake looking like a super page, we need to allocate
......
...@@ -24,6 +24,7 @@ template <bool thread_safe> ...@@ -24,6 +24,7 @@ template <bool thread_safe>
ALWAYS_INLINE DeferredUnmap ALWAYS_INLINE DeferredUnmap
PartitionDirectUnmap(PartitionPage<thread_safe>* page) { PartitionDirectUnmap(PartitionPage<thread_safe>* page) {
PartitionRoot<thread_safe>* root = PartitionRoot<thread_safe>::FromPage(page); PartitionRoot<thread_safe>* root = PartitionRoot<thread_safe>::FromPage(page);
root->lock_.AssertAcquired();
const PartitionDirectMapExtent<thread_safe>* extent = const PartitionDirectMapExtent<thread_safe>* extent =
PartitionDirectMapExtent<thread_safe>::FromPage(page); PartitionDirectMapExtent<thread_safe>::FromPage(page);
size_t unmap_size = extent->map_size; size_t unmap_size = extent->map_size;
...@@ -109,6 +110,10 @@ PartitionPage<thread_safe>* PartitionPage<thread_safe>::get_sentinel_page() { ...@@ -109,6 +110,10 @@ PartitionPage<thread_safe>* PartitionPage<thread_safe>::get_sentinel_page() {
template <bool thread_safe> template <bool thread_safe>
DeferredUnmap PartitionPage<thread_safe>::FreeSlowPath() { DeferredUnmap PartitionPage<thread_safe>::FreeSlowPath() {
#if DCHECK_IS_ON()
auto* root = PartitionRoot<thread_safe>::FromPage(this);
root->lock_.AssertAcquired();
#endif
PA_DCHECK(this != get_sentinel_page()); PA_DCHECK(this != get_sentinel_page());
if (LIKELY(num_allocated_slots == 0)) { if (LIKELY(num_allocated_slots == 0)) {
// Page became fully unused. // Page became fully unused.
......
...@@ -23,6 +23,7 @@ include_rules = [ ...@@ -23,6 +23,7 @@ include_rules = [
"+base/third_party/double_conversion", "+base/third_party/double_conversion",
"+base/template_util.h", "+base/template_util.h",
"+base/test/metrics/histogram_tester.h", "+base/test/metrics/histogram_tester.h",
"+base/thread_annotations.h",
"+base/threading", "+base/threading",
"+base/time/time.h", "+base/time/time.h",
"+base/tuple.h", "+base/tuple.h",
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "base/allocator/partition_allocator/page_allocator.h" #include "base/allocator/partition_allocator/page_allocator.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/strings/safe_sprintf.h" #include "base/strings/safe_sprintf.h"
#include "base/thread_annotations.h"
#include "components/crash/core/common/crash_key.h" #include "components/crash/core/common/crash_key.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h" #include "third_party/blink/renderer/platform/wtf/wtf.h"
...@@ -145,10 +146,15 @@ class LightPartitionStatsDumperImpl : public base::PartitionStatsDumper { ...@@ -145,10 +146,15 @@ class LightPartitionStatsDumperImpl : public base::PartitionStatsDumper {
size_t Partitions::TotalSizeOfCommittedPages() { size_t Partitions::TotalSizeOfCommittedPages() {
DCHECK(initialized_); DCHECK(initialized_);
size_t total_size = 0; size_t total_size = 0;
total_size += FastMallocPartition()->total_size_of_committed_pages; // Racy reads below: this is fine to collect statistics.
total_size += ArrayBufferPartition()->total_size_of_committed_pages; total_size +=
total_size += BufferPartition()->total_size_of_committed_pages; TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages);
total_size += LayoutPartition()->total_size_of_committed_pages; total_size +=
TS_UNCHECKED_READ(ArrayBufferPartition()->total_size_of_committed_pages);
total_size +=
TS_UNCHECKED_READ(BufferPartition()->total_size_of_committed_pages);
total_size +=
TS_UNCHECKED_READ(LayoutPartition()->total_size_of_committed_pages);
return total_size; return total_size;
} }
......
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