8291912: Introduce per-allocation target struct for members in G1PLABAllocator
Reviewed-by: iwalulya, sjohanss
This commit is contained in:
parent
1e1db5debd
commit
37234c856d
src/hotspot/share/gc/g1
@ -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) {
|
||||
@ -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;
|
||||
// Make the tolerated refills a huge number.
|
||||
_tolerated_refills = SIZE_MAX;
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
G1PLABAllocator::~G1PLABAllocator() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
@ -156,18 +156,33 @@ private:
|
||||
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
|
||||
@ -186,7 +201,6 @@ private:
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user