Commit bea2651b authored by Darius Mercadier's avatar Darius Mercadier Committed by Commit Bot

[heap] Sort map space freelist to reduce fragmentation

Sorting the pages by least free bytes should reduce fragmentation:
since map space is never compacted, it makes sense to first fill
pages that are the most full already rather than to start with the
most empty pages (which is what was more or less going on until this
CL).

Bug: v8:9329
Change-Id: I2157e3b4706c53da80220da5e4a26c00ee4c592f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1735325Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@google.com>
Cr-Commit-Position: refs/heads/master@{#63090}
parent f665d89f
......@@ -576,6 +576,7 @@ void MarkCompactCollector::EnsureSweepingCompleted() {
heap()->old_space()->RefillFreeList();
heap()->code_space()->RefillFreeList();
heap()->map_space()->RefillFreeList();
heap()->map_space()->SortFreeList();
heap()->tracer()->NotifySweepingCompleted();
......
......@@ -3562,10 +3562,45 @@ bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes) {
// -----------------------------------------------------------------------------
// MapSpace implementation
// TODO(dmercadier): use a heap instead of sorting like that.
// Using a heap will have multiple benefits:
// - for now, SortFreeList is only called after sweeping, which is somewhat
// late. Using a heap, sorting could be done online: FreeListCategories would
// be inserted in a heap (ie, in a sorted manner).
// - SortFreeList is a bit fragile: any change to FreeListMap (or to
// MapSpace::free_list_) could break it.
void MapSpace::SortFreeList() {
using LiveBytesPagePair = std::pair<size_t, Page*>;
std::vector<LiveBytesPagePair> pages;
pages.reserve(CountTotalPages());
for (Page* p : *this) {
free_list()->RemoveCategory(p->free_list_category(kFirstCategory));
pages.push_back(std::make_pair(p->allocated_bytes(), p));
}
// Sorting by least-allocated-bytes first.
std::sort(pages.begin(), pages.end(),
[](const LiveBytesPagePair& a, const LiveBytesPagePair& b) {
return a.first < b.first;
});
for (LiveBytesPagePair const& p : pages) {
// Since AddCategory inserts in head position, it reverts the order produced
// by the sort above: least-allocated-bytes will be Added first, and will
// therefore be the last element (and the first one will be
// most-allocated-bytes).
free_list()->AddCategory(p.second->free_list_category(kFirstCategory));
}
}
#ifdef VERIFY_HEAP
void MapSpace::VerifyObject(HeapObject object) { CHECK(object.IsMap()); }
#endif
// -----------------------------------------------------------------------------
// ReadOnlySpace implementation
ReadOnlySpace::ReadOnlySpace(Heap* heap)
: PagedSpace(heap, RO_SPACE, NOT_EXECUTABLE, FreeList::CreateFreeList()),
is_string_padding_cleared_(heap->isolate()->initialized_from_snapshot()) {
......
......@@ -221,6 +221,7 @@ class FreeListCategory {
friend class FreeList;
friend class PagedSpace;
friend class MapSpace;
DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListCategory);
};
......@@ -370,6 +371,7 @@ class FreeList {
friend class Page;
friend class MemoryChunk;
friend class ReadOnlyPage;
friend class MapSpace;
};
// FreeList used for spaces that don't have freelists
......@@ -3010,6 +3012,8 @@ class MapSpace : public PagedSpace {
}
}
void SortFreeList();
#ifdef VERIFY_HEAP
void VerifyObject(HeapObject obj) override;
#endif
......
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