Skip to content

Commit

Permalink
8291912: Introduce per-allocation target struct for members in G1PLAB…
Browse files Browse the repository at this point in the history
…Allocator

Reviewed-by: iwalulya, sjohanss
  • Loading branch information
Thomas Schatzl committed Sep 13, 2022
1 parent 1e1db5d commit 37234c8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 56 deletions.
101 changes: 58 additions & 43 deletions src/hotspot/share/gc/g1/g1Allocator.cpp
Expand Up @@ -293,6 +293,46 @@ HeapWord* G1Allocator::old_attempt_allocation(size_t min_word_size,
return result;
}

G1PLABAllocator::PLABData::PLABData() :
_alloc_buffer(nullptr),
_direct_allocated(0),
_num_plab_fills(0),
_num_direct_allocations(0),
_plab_fill_counter(0),
_cur_desired_plab_size(0),
_num_alloc_buffers(0) { }

G1PLABAllocator::PLABData::~PLABData() {
if (_alloc_buffer == nullptr) {
return;
}
for (uint node_index = 0; node_index < _num_alloc_buffers; node_index++) {
delete _alloc_buffer[node_index];
}
}

void G1PLABAllocator::PLABData::initialize(uint num_alloc_buffers, size_t desired_plab_size, size_t tolerated_refills) {
_num_alloc_buffers = num_alloc_buffers;
_alloc_buffer = NEW_C_HEAP_ARRAY(PLAB*, _num_alloc_buffers, mtGC);

for (uint node_index = 0; node_index < _num_alloc_buffers; node_index++) {
_alloc_buffer[node_index] = new PLAB(desired_plab_size);
}

_plab_fill_counter = tolerated_refills;
_cur_desired_plab_size = desired_plab_size;
}

void G1PLABAllocator::PLABData::notify_plab_refill(size_t tolerated_refills, size_t next_plab_size) {
_num_plab_fills++;
if (should_boost()) {
_plab_fill_counter = tolerated_refills;
_cur_desired_plab_size = next_plab_size;
} else {
_plab_fill_counter--;
}
}

G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator) {
Expand All @@ -309,34 +349,13 @@ G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
double const PadFactor = 1.5;
_tolerated_refills = MAX2(ExpectedNumberOfRefills, 1.0) * PadFactor;
} else {
// Make the tolerated refills a huge number; -1 because we add one to this
// value later and it would overflow otherwise.
_tolerated_refills = SIZE_MAX - 1;
}

for (region_type_t state = 0; state < G1HeapRegionAttr::Num; state++) {
_direct_allocated[state] = 0;
uint length = alloc_buffers_length(state);
_alloc_buffers[state] = NEW_C_HEAP_ARRAY(PLAB*, length, mtGC);
size_t word_sz = _g1h->desired_plab_sz(state);
for (uint node_index = 0; node_index < length; node_index++) {
_alloc_buffers[state][node_index] = new PLAB(word_sz);
}
_num_plab_fills[state] = 0;
// The initial PLAB refill should not count, hence the +1 for the first boost.
_plab_fill_counter[state] = _tolerated_refills + 1;
_num_direct_allocations[state] = 0;
_cur_desired_plab_size[state] = word_sz;
// Make the tolerated refills a huge number.
_tolerated_refills = SIZE_MAX;
}
}

G1PLABAllocator::~G1PLABAllocator() {
// The initial PLAB refill should not count, hence the +1 for the first boost.
size_t initial_tolerated_refills = ResizePLAB ? _tolerated_refills + 1 : _tolerated_refills;
for (region_type_t state = 0; state < G1HeapRegionAttr::Num; state++) {
uint length = alloc_buffers_length(state);
for (uint node_index = 0; node_index < length; node_index++) {
delete _alloc_buffers[state][node_index];
}
FREE_C_HEAP_ARRAY(PLAB*, _alloc_buffers[state]);
_dest_data[state].initialize(alloc_buffers_length(state), _g1h->desired_plab_sz(state), initial_tolerated_refills);
}
}

Expand All @@ -351,8 +370,9 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
size_t plab_word_size = plab_size(dest.type());
size_t next_plab_word_size = plab_word_size;

bool const should_boost_plab = _plab_fill_counter[dest.type()] == 0;
if (should_boost_plab) {
PLABData* plab_data = &_dest_data[dest.type()];

if (plab_data->should_boost()) {
next_plab_word_size = _g1h->clamp_plab_size(next_plab_word_size * 2);
}

Expand All @@ -367,16 +387,10 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
PLAB* alloc_buf = alloc_buffer(dest, node_index);
guarantee(alloc_buf->words_remaining() <= required_in_plab, "must be");

_num_plab_fills[dest.type()]++;
alloc_buf->retire();

if (should_boost_plab) {
_plab_fill_counter[dest.type()] = _tolerated_refills;
} else {
_plab_fill_counter[dest.type()]--;
}
plab_data->notify_plab_refill(_tolerated_refills, next_plab_word_size);
plab_word_size = next_plab_word_size;
_cur_desired_plab_size[dest.type()] = plab_word_size;

size_t actual_plab_size = 0;
HeapWord* buf = _allocator->par_allocate_during_gc(dest,
Expand Down Expand Up @@ -404,8 +418,8 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest,
// Try direct allocation.
HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz, node_index);
if (result != NULL) {
_direct_allocated[dest.type()] += word_sz;
_num_direct_allocations[dest.type()]++;
plab_data->_direct_allocated += word_sz;
plab_data->_num_direct_allocations++;
}
return result;
}
Expand All @@ -423,19 +437,20 @@ void G1PLABAllocator::flush_and_retire_stats(uint num_workers) {
buf->flush_and_retire_stats(stats);
}
}
stats->add_num_plab_filled(_num_plab_fills[state]);
stats->add_direct_allocated(_direct_allocated[state]);
stats->add_num_direct_allocated(_num_direct_allocations[state]);
PLABData* plab_data = &_dest_data[state];
stats->add_num_plab_filled(plab_data->_num_plab_fills);
stats->add_direct_allocated(plab_data->_direct_allocated);
stats->add_num_direct_allocated(plab_data->_num_direct_allocations);
}

log_trace(gc, plab)("PLAB boost: Young %zu -> %zu refills %zu (tolerated %zu) Old %zu -> %zu refills %zu (tolerated %zu)",
_g1h->alloc_buffer_stats(G1HeapRegionAttr::Young)->desired_plab_size(num_workers),
plab_size(G1HeapRegionAttr::Young),
_num_plab_fills[G1HeapRegionAttr::Young],
_dest_data[G1HeapRegionAttr::Young]._num_plab_fills,
_tolerated_refills,
_g1h->alloc_buffer_stats(G1HeapRegionAttr::Old)->desired_plab_size(num_workers),
plab_size(G1HeapRegionAttr::Old),
_num_plab_fills[G1HeapRegionAttr::Old],
_dest_data[G1HeapRegionAttr::Old]._num_plab_fills,
_tolerated_refills);
}

Expand All @@ -453,7 +468,7 @@ size_t G1PLABAllocator::waste() const {
}

size_t G1PLABAllocator::plab_size(G1HeapRegionAttr which) const {
return _cur_desired_plab_size[which.type()];
return _dest_data[which.type()]._cur_desired_plab_size;
}

size_t G1PLABAllocator::undo_waste() const {
Expand Down
34 changes: 24 additions & 10 deletions src/hotspot/share/gc/g1/g1Allocator.hpp
Expand Up @@ -156,18 +156,33 @@ class G1PLABAllocator : public CHeapObj<mtGC> {
G1CollectedHeap* _g1h;
G1Allocator* _allocator;

PLAB** _alloc_buffers[G1HeapRegionAttr::Num];
// Collects per-destination information (e.g. young, old gen) about current PLAB
// and statistics about it.
struct PLABData {
PLAB** _alloc_buffer;

// Number of words allocated directly (not counting PLAB allocation).
size_t _direct_allocated[G1HeapRegionAttr::Num];
size_t _direct_allocated; // Number of words allocated directly (not counting PLAB allocation).
size_t _num_plab_fills; // Number of PLAB refills experienced so far.
size_t _num_direct_allocations; // Number of direct allocations experienced so far.

// Number of PLAB refills experienced so far.
size_t _num_plab_fills[G1HeapRegionAttr::Num];
size_t _num_direct_allocations[G1HeapRegionAttr::Num];
size_t _plab_fill_counter; // How many PLAB refills left until boosting.
size_t _cur_desired_plab_size; // Current desired PLAB size incorporating eventual boosting.

size_t _plab_fill_counter[G1HeapRegionAttr::Num];
// Current desired PLAB size incorporating eventual boosting.
size_t _cur_desired_plab_size[G1HeapRegionAttr::Num];
uint _num_alloc_buffers; // The number of PLABs for this destination.

PLABData();
~PLABData();

void initialize(uint num_alloc_buffers, size_t desired_plab_size, size_t tolerated_refills);

// Should we actually boost the PLAB size?
// The _plab_refill_counter reset value encodes the ResizePLAB flag value already, so no
// need to check here.
bool should_boost() const { return _plab_fill_counter == 0; }

void notify_plab_refill(size_t tolerated_refills, size_t next_plab_size);

} _dest_data[G1HeapRegionAttr::Num];

// The amount of PLAB refills tolerated until boosting PLAB size.
// This value is the same for all generations because they all use the same
Expand All @@ -186,7 +201,6 @@ class G1PLABAllocator : public CHeapObj<mtGC> {
bool may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const;
public:
G1PLABAllocator(G1Allocator* allocator);
~G1PLABAllocator();

size_t waste() const;
size_t undo_waste() const;
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/gc/g1/g1Allocator.inline.hpp
Expand Up @@ -89,7 +89,7 @@ inline HeapWord* G1Allocator::attempt_allocation_force(size_t word_size) {
inline PLAB* G1PLABAllocator::alloc_buffer(G1HeapRegionAttr dest, uint node_index) const {
assert(dest.is_valid(),
"Allocation buffer index out of bounds: %s", dest.get_type_str());
assert(_alloc_buffers[dest.type()] != NULL,
assert(_dest_data[dest.type()]._alloc_buffer != nullptr,
"Allocation buffer is NULL: %s", dest.get_type_str());
return alloc_buffer(dest.type(), node_index);
}
Expand All @@ -101,9 +101,9 @@ inline PLAB* G1PLABAllocator::alloc_buffer(region_type_t dest, uint node_index)
if (dest == G1HeapRegionAttr::Young) {
assert(node_index < alloc_buffers_length(dest),
"Allocation buffer index out of bounds: %u, %u", dest, node_index);
return _alloc_buffers[dest][node_index];
return _dest_data[dest]._alloc_buffer[node_index];
} else {
return _alloc_buffers[dest][0];
return _dest_data[dest]._alloc_buffer[0];
}
}

Expand Down

1 comment on commit 37234c8

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.