Commit 1d4628fb authored by hpayer's avatar hpayer Committed by Commit bot

[heap] Refactor free list counters in Page.

BUG=chromium:587026
LOG=n

Review URL: https://codereview.chromium.org/1696413002

Cr-Commit-Position: refs/heads/master@{#34041}
parent c0c5d131
...@@ -488,11 +488,8 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size, ...@@ -488,11 +488,8 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
chunk->concurrent_sweeping_state().SetValue(kSweepingDone); chunk->concurrent_sweeping_state().SetValue(kSweepingDone);
chunk->parallel_compaction_state().SetValue(kCompactingDone); chunk->parallel_compaction_state().SetValue(kCompactingDone);
chunk->mutex_ = nullptr; chunk->mutex_ = nullptr;
chunk->available_in_small_free_list_ = 0; chunk->available_in_free_list_ = 0;
chunk->available_in_medium_free_list_ = 0; chunk->wasted_memory_ = 0;
chunk->available_in_large_free_list_ = 0;
chunk->available_in_huge_free_list_ = 0;
chunk->non_available_small_blocks_ = 0;
chunk->ResetLiveBytes(); chunk->ResetLiveBytes();
Bitmap::Clear(chunk); Bitmap::Clear(chunk);
chunk->set_next_chunk(nullptr); chunk->set_next_chunk(nullptr);
...@@ -716,11 +713,8 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t reserve_area_size, ...@@ -716,11 +713,8 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t reserve_area_size,
void Page::ResetFreeListStatistics() { void Page::ResetFreeListStatistics() {
non_available_small_blocks_ = 0; wasted_memory_ = 0;
available_in_small_free_list_ = 0; available_in_free_list_ = 0;
available_in_medium_free_list_ = 0;
available_in_large_free_list_ = 0;
available_in_huge_free_list_ = 0;
} }
...@@ -2208,8 +2202,7 @@ intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) { ...@@ -2208,8 +2202,7 @@ intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) {
} }
prev_node = cur_node; prev_node = cur_node;
} }
DCHECK_EQ(p->available_in_free_list(type_), sum); p->add_available_in_free_list(-sum);
p->add_available_in_free_list(type_, -sum);
available_ -= sum; available_ -= sum;
return sum; return sum;
} }
...@@ -2232,7 +2225,7 @@ FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) { ...@@ -2232,7 +2225,7 @@ FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) {
Page* page = Page::FromAddress(node->address()); Page* page = Page::FromAddress(node->address());
while ((node != nullptr) && !page->CanAllocate()) { while ((node != nullptr) && !page->CanAllocate()) {
available_ -= node->size(); available_ -= node->size();
page->add_available_in_free_list(type_, -(node->Size())); page->add_available_in_free_list(-(node->Size()));
node = node->next(); node = node->next();
} }
...@@ -2287,7 +2280,7 @@ FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes, ...@@ -2287,7 +2280,7 @@ FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes,
} }
// For evacuation candidates we continue. // For evacuation candidates we continue.
if (!page_for_node->CanAllocate()) { if (!page_for_node->CanAllocate()) {
page_for_node->add_available_in_free_list(type_, -size); page_for_node->add_available_in_free_list(-size);
continue; continue;
} }
// Otherwise we have a large enough node and can return. // Otherwise we have a large enough node and can return.
...@@ -2375,7 +2368,7 @@ int FreeList::Free(Address start, int size_in_bytes) { ...@@ -2375,7 +2368,7 @@ int FreeList::Free(Address start, int size_in_bytes) {
// Early return to drop too-small blocks on the floor. // Early return to drop too-small blocks on the floor.
if (size_in_bytes <= kSmallListMin) { if (size_in_bytes <= kSmallListMin) {
page->add_non_available_small_blocks(size_in_bytes); page->add_wasted_memory(size_in_bytes);
wasted_bytes_ += size_in_bytes; wasted_bytes_ += size_in_bytes;
return size_in_bytes; return size_in_bytes;
} }
...@@ -2383,19 +2376,9 @@ int FreeList::Free(Address start, int size_in_bytes) { ...@@ -2383,19 +2376,9 @@ int FreeList::Free(Address start, int size_in_bytes) {
FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start)); FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start));
// Insert other blocks at the head of a free list of the appropriate // Insert other blocks at the head of a free list of the appropriate
// magnitude. // magnitude.
if (size_in_bytes <= kSmallListMax) { FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
category_[kSmall].Free(free_space, size_in_bytes); category_[type].Free(free_space, size_in_bytes);
page->add_available_in_small_free_list(size_in_bytes); page->add_available_in_free_list(size_in_bytes);
} else if (size_in_bytes <= kMediumListMax) {
category_[kMedium].Free(free_space, size_in_bytes);
page->add_available_in_medium_free_list(size_in_bytes);
} else if (size_in_bytes <= kLargeListMax) {
category_[kLarge].Free(free_space, size_in_bytes);
page->add_available_in_large_free_list(size_in_bytes);
} else {
category_[kHuge].Free(free_space, size_in_bytes);
page->add_available_in_huge_free_list(size_in_bytes);
}
DCHECK(IsVeryLong() || Available() == SumFreeLists()); DCHECK(IsVeryLong() || Available() == SumFreeLists());
return 0; return 0;
...@@ -2406,7 +2389,7 @@ FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { ...@@ -2406,7 +2389,7 @@ FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) {
FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size); FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size);
if (node != nullptr) { if (node != nullptr) {
Page::FromAddress(node->address()) Page::FromAddress(node->address())
->add_available_in_free_list(category, -(*node_size)); ->add_available_in_free_list(-(*node_size));
DCHECK(IsVeryLong() || Available() == SumFreeLists()); DCHECK(IsVeryLong() || Available() == SumFreeLists());
} }
return node; return node;
...@@ -2417,50 +2400,37 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { ...@@ -2417,50 +2400,37 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
FreeSpace* node = nullptr; FreeSpace* node = nullptr;
Page* page = nullptr; Page* page = nullptr;
if (size_in_bytes <= kSmallAllocationMax) { // First try the allocation fast path: try to allocate the minimum element
node = FindNodeIn(kSmall, node_size); // size of a free list category. This operation is constant time.
if (node != nullptr) return node; FreeListCategoryType type =
} SelectFastAllocationFreeListCategoryType(size_in_bytes);
for (int i = type; i < kHuge; i++) {
if (size_in_bytes <= kMediumAllocationMax) { node = FindNodeIn(static_cast<FreeListCategoryType>(i), node_size);
node = FindNodeIn(kMedium, node_size);
if (node != nullptr) return node;
}
if (size_in_bytes <= kLargeAllocationMax) {
node = FindNodeIn(kLarge, node_size);
if (node != nullptr) return node; if (node != nullptr) return node;
} }
// Next search the huge list for free list nodes. This takes linear time in
// the number of huge elements.
node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size); node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size);
if (node != nullptr) { if (node != nullptr) {
page = Page::FromAddress(node->address()); page = Page::FromAddress(node->address());
page->add_available_in_large_free_list(-(*node_size)); page->add_available_in_free_list(-(*node_size));
DCHECK(IsVeryLong() || Available() == SumFreeLists()); DCHECK(IsVeryLong() || Available() == SumFreeLists());
return node; return node;
} }
if (size_in_bytes <= kSmallListMax) { // We need a huge block of memory, but we didn't find anything in the huge
node = category_[kSmall].PickNodeFromList(size_in_bytes, node_size); // list.
if (node != NULL) { if (type == kHuge) return nullptr;
DCHECK(size_in_bytes <= *node_size);
page = Page::FromAddress(node->address()); // Now search the best fitting free list for a node that has at least the
page->add_available_in_small_free_list(-(*node_size)); // requested size. This takes linear time in the number of elements.
} type = SelectFreeListCategoryType(size_in_bytes);
} else if (size_in_bytes <= kMediumListMax) { node = category_[type].PickNodeFromList(size_in_bytes, node_size);
node = category_[kMedium].PickNodeFromList(size_in_bytes, node_size); if (node != nullptr) {
if (node != NULL) { DCHECK(size_in_bytes <= *node_size);
DCHECK(size_in_bytes <= *node_size); page = Page::FromAddress(node->address());
page = Page::FromAddress(node->address()); page->add_available_in_free_list(-(*node_size));
page->add_available_in_medium_free_list(-(*node_size));
}
} else if (size_in_bytes <= kLargeListMax) {
node = category_[kLarge].PickNodeFromList(size_in_bytes, node_size);
if (node != NULL) {
DCHECK(size_in_bytes <= *node_size);
page = Page::FromAddress(node->address());
page->add_available_in_large_free_list(-(*node_size));
}
} }
DCHECK(IsVeryLong() || Available() == SumFreeLists()); DCHECK(IsVeryLong() || Available() == SumFreeLists());
...@@ -2687,7 +2657,7 @@ void PagedSpace::RepairFreeListsAfterDeserialization() { ...@@ -2687,7 +2657,7 @@ void PagedSpace::RepairFreeListsAfterDeserialization() {
PageIterator iterator(this); PageIterator iterator(this);
while (iterator.has_next()) { while (iterator.has_next()) {
Page* page = iterator.next(); Page* page = iterator.next();
int size = static_cast<int>(page->non_available_small_blocks()); int size = static_cast<int>(page->wasted_memory());
if (size == 0) continue; if (size == 0) continue;
Address address = page->OffsetToAddress(Page::kPageSize - size); Address address = page->OffsetToAddress(Page::kPageSize - size);
heap()->CreateFillerObjectAt(address, size); heap()->CreateFillerObjectAt(address, size);
......
...@@ -408,7 +408,7 @@ class MemoryChunk { ...@@ -408,7 +408,7 @@ class MemoryChunk {
+ kPointerSize // base::Mutex* mutex_ + kPointerSize // base::Mutex* mutex_
+ kPointerSize // base::AtomicWord parallel_sweeping_ + kPointerSize // base::AtomicWord parallel_sweeping_
+ kPointerSize // AtomicValue parallel_compaction_ + kPointerSize // AtomicValue parallel_compaction_
+ 5 * kPointerSize // AtomicNumber free-list statistics + 2 * kPointerSize // AtomicNumber free-list statistics
+ kPointerSize // AtomicValue next_chunk_ + kPointerSize // AtomicValue next_chunk_
+ kPointerSize; // AtomicValue prev_chunk_ + kPointerSize; // AtomicValue prev_chunk_
...@@ -705,11 +705,8 @@ class MemoryChunk { ...@@ -705,11 +705,8 @@ class MemoryChunk {
AtomicValue<ParallelCompactingState> parallel_compaction_; AtomicValue<ParallelCompactingState> parallel_compaction_;
// PagedSpace free-list statistics. // PagedSpace free-list statistics.
AtomicNumber<intptr_t> available_in_small_free_list_; AtomicNumber<intptr_t> available_in_free_list_;
AtomicNumber<intptr_t> available_in_medium_free_list_; AtomicNumber<intptr_t> wasted_memory_;
AtomicNumber<intptr_t> available_in_large_free_list_;
AtomicNumber<intptr_t> available_in_huge_free_list_;
AtomicNumber<intptr_t> non_available_small_blocks_;
// next_chunk_ holds a pointer of type MemoryChunk // next_chunk_ holds a pointer of type MemoryChunk
AtomicValue<MemoryChunk*> next_chunk_; AtomicValue<MemoryChunk*> next_chunk_;
...@@ -833,10 +830,8 @@ class Page : public MemoryChunk { ...@@ -833,10 +830,8 @@ class Page : public MemoryChunk {
void ResetFreeListStatistics(); void ResetFreeListStatistics();
int LiveBytesFromFreeList() { int LiveBytesFromFreeList() {
return static_cast<int>( return static_cast<int>(area_size() - wasted_memory() -
area_size() - non_available_small_blocks() - available_in_free_list());
available_in_small_free_list() - available_in_medium_free_list() -
available_in_large_free_list() - available_in_huge_free_list());
} }
#define FRAGMENTATION_STATS_ACCESSORS(type, name) \ #define FRAGMENTATION_STATS_ACCESSORS(type, name) \
...@@ -844,50 +839,11 @@ class Page : public MemoryChunk { ...@@ -844,50 +839,11 @@ class Page : public MemoryChunk {
void set_##name(type name) { name##_.SetValue(name); } \ void set_##name(type name) { name##_.SetValue(name); } \
void add_##name(type name) { name##_.Increment(name); } void add_##name(type name) { name##_.Increment(name); }
FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks) FRAGMENTATION_STATS_ACCESSORS(intptr_t, wasted_memory)
FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list) FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_free_list)
FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list)
FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list)
FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list)
#undef FRAGMENTATION_STATS_ACCESSORS #undef FRAGMENTATION_STATS_ACCESSORS
void add_available_in_free_list(FreeListCategoryType type, intptr_t bytes) {
switch (type) {
case kSmall:
add_available_in_small_free_list(bytes);
break;
case kMedium:
add_available_in_medium_free_list(bytes);
break;
case kLarge:
add_available_in_large_free_list(bytes);
break;
case kHuge:
add_available_in_huge_free_list(bytes);
break;
default:
UNREACHABLE();
}
}
intptr_t available_in_free_list(FreeListCategoryType type) {
switch (type) {
case kSmall:
return available_in_small_free_list();
case kMedium:
return available_in_medium_free_list();
case kLarge:
return available_in_large_free_list();
case kHuge:
return available_in_huge_free_list();
default:
UNREACHABLE();
}
UNREACHABLE();
return 0;
}
#ifdef DEBUG #ifdef DEBUG
void Print(); void Print();
#endif // DEBUG #endif // DEBUG
...@@ -1799,6 +1755,29 @@ class FreeList { ...@@ -1799,6 +1755,29 @@ class FreeList {
return &category_[category]; return &category_[category];
} }
FreeListCategoryType SelectFreeListCategoryType(size_t size_in_bytes) {
if (size_in_bytes <= kSmallListMax) {
return kSmall;
} else if (size_in_bytes <= kMediumListMax) {
return kMedium;
} else if (size_in_bytes <= kLargeListMax) {
return kLarge;
}
return kHuge;
}
FreeListCategoryType SelectFastAllocationFreeListCategoryType(
size_t size_in_bytes) {
if (size_in_bytes <= kSmallAllocationMax) {
return kSmall;
} else if (size_in_bytes <= kMediumAllocationMax) {
return kMedium;
} else if (size_in_bytes <= kLargeAllocationMax) {
return kLarge;
}
return kHuge;
}
PagedSpace* owner_; PagedSpace* owner_;
base::Mutex mutex_; base::Mutex mutex_;
intptr_t wasted_bytes_; intptr_t wasted_bytes_;
......
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