Commit a92dc8d7 authored by Bartek Nowierski's avatar Bartek Nowierski Committed by Commit Bot

Implement a hint to aid finding a free chunk

The hint points to a bit in the bitmap before which we know for sure
all bits are 1s, so no need to scan those.

Bug: 1086388
Change-Id: If1ff5dfb7a8faa2fd47937e44bb811af67bda7f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2230149
Commit-Queue: Bartek Nowierski <bartekn@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#776531}
parent d4b77064
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/allocator/partition_allocator/page_allocator.h" #include "base/allocator/partition_allocator/page_allocator.h"
#include "base/allocator/partition_allocator/page_allocator_internal.h" #include "base/allocator/partition_allocator/page_allocator_internal.h"
#include "base/bits.h" #include "base/bits.h"
#include "base/notreached.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include <limits> #include <limits>
...@@ -66,12 +67,11 @@ void AddressPoolManager::Free(pool_handle handle, void* ptr, size_t length) { ...@@ -66,12 +67,11 @@ void AddressPoolManager::Free(pool_handle handle, void* ptr, size_t length) {
AddressPoolManager::Pool::Pool(uintptr_t ptr, size_t length) AddressPoolManager::Pool::Pool(uintptr_t ptr, size_t length)
: total_bits_(length / kSuperPageSize), : total_bits_(length / kSuperPageSize),
address_begin_(ptr) address_begin_(ptr),
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
, address_end_(ptr + length),
address_end_(ptr + length)
#endif #endif
{ bit_hint_(0) {
CHECK_LE(total_bits_, kMaxBits); CHECK_LE(total_bits_, kMaxBits);
CHECK(!(ptr & kSuperPageOffsetMask)); CHECK(!(ptr & kSuperPageOffsetMask));
CHECK(!(length & kSuperPageOffsetMask)); CHECK(!(length & kSuperPageOffsetMask));
...@@ -88,8 +88,9 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) { ...@@ -88,8 +88,9 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) {
const size_t need_bits = required_size >> kSuperPageShift; const size_t need_bits = required_size >> kSuperPageShift;
// Use first fit policy to find an available chunk from free chunks. // Use first fit policy to find an available chunk from free chunks.
size_t beg_bit = 0; // Start from |bit_hint_|, because we know there is no free chunks before.
size_t curr_bit = 0; size_t beg_bit = bit_hint_;
size_t curr_bit = bit_hint_;
while (true) { while (true) {
// |end_bit| points 1 past the last bit that needs to be 0. If it goes past // |end_bit| points 1 past the last bit that needs to be 0. If it goes past
// |total_bits_|, return |nullptr| to signal no free chunk was found. // |total_bits_|, return |nullptr| to signal no free chunk was found.
...@@ -107,6 +108,8 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) { ...@@ -107,6 +108,8 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) {
// next outer loop pass from checking the same bits. // next outer loop pass from checking the same bits.
beg_bit = curr_bit + 1; beg_bit = curr_bit + 1;
found = false; found = false;
if (bit_hint_ == curr_bit)
++bit_hint_;
} }
} }
...@@ -117,6 +120,9 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) { ...@@ -117,6 +120,9 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) {
DCHECK(!alloc_bitset_.test(i)); DCHECK(!alloc_bitset_.test(i));
alloc_bitset_.set(i); alloc_bitset_.set(i);
} }
if (bit_hint_ == beg_bit) {
bit_hint_ = end_bit;
}
uintptr_t address = address_begin_ + beg_bit * kSuperPageSize; uintptr_t address = address_begin_ + beg_bit * kSuperPageSize;
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK_LE(address + required_size, address_end_); DCHECK_LE(address + required_size, address_end_);
...@@ -125,6 +131,7 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) { ...@@ -125,6 +131,7 @@ uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) {
} }
} }
NOTREACHED();
return 0; return 0;
} }
...@@ -145,6 +152,7 @@ void AddressPoolManager::Pool::FreeChunk(uintptr_t address, size_t free_size) { ...@@ -145,6 +152,7 @@ void AddressPoolManager::Pool::FreeChunk(uintptr_t address, size_t free_size) {
DCHECK(alloc_bitset_.test(i)); DCHECK(alloc_bitset_.test(i));
alloc_bitset_.reset(i); alloc_bitset_.reset(i);
} }
bit_hint_ = std::min(bit_hint_, beg_bit);
} }
AddressPoolManager::Pool::~Pool() = default; AddressPoolManager::Pool::~Pool() = default;
......
...@@ -69,6 +69,12 @@ class BASE_EXPORT AddressPoolManager { ...@@ -69,6 +69,12 @@ class BASE_EXPORT AddressPoolManager {
const uintptr_t address_end_; const uintptr_t address_end_;
#endif #endif
// A number of a bit before which we know for sure there all 1s. This is
// a best effort hint in the sense that there still may be lots of 1s after
// this bit, but at least we know there is no point in starting the search
// before it.
size_t bit_hint_;
DISALLOW_COPY_AND_ASSIGN(Pool); DISALLOW_COPY_AND_ASSIGN(Pool);
}; };
......
...@@ -78,6 +78,8 @@ TEST(AddressPoolManager, PagesFragmented) { ...@@ -78,6 +78,8 @@ TEST(AddressPoolManager, PagesFragmented) {
addrs[i] = AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize); addrs[i] = AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize);
EXPECT_EQ(addrs[i], base_ptr + i * kSuperPageSize); EXPECT_EQ(addrs[i], base_ptr + i * kSuperPageSize);
} }
EXPECT_EQ(AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize),
nullptr);
for (size_t i = 1; i < kPageCnt; i += 2) { for (size_t i = 1; i < kPageCnt; i += 2) {
AddressPoolManager::GetInstance()->Free(pool, addrs[i], kSuperPageSize); AddressPoolManager::GetInstance()->Free(pool, addrs[i], kSuperPageSize);
} }
...@@ -87,6 +89,8 @@ TEST(AddressPoolManager, PagesFragmented) { ...@@ -87,6 +89,8 @@ TEST(AddressPoolManager, PagesFragmented) {
addrs[i] = AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize); addrs[i] = AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize);
EXPECT_EQ(addrs[i], base_ptr + i * kSuperPageSize); EXPECT_EQ(addrs[i], base_ptr + i * kSuperPageSize);
} }
EXPECT_EQ(AddressPoolManager::GetInstance()->Alloc(pool, kSuperPageSize),
nullptr);
} }
TEST(AddressPoolManager, IrregularPattern) { TEST(AddressPoolManager, IrregularPattern) {
......
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