mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8274178: G1: Occupancy value in IHOP logging and JFR event is inaccurate
8371635: G1: Young gen allocations should never be considered when comparing against IHOP threshold Reviewed-by: ayang, iwalulya
This commit is contained in:
parent
bbc0f9ef30
commit
7d78818ae6
@ -353,6 +353,14 @@ size_t G1CollectedHeap::humongous_obj_size_in_regions(size_t word_size) {
|
||||
return align_up(word_size, G1HeapRegion::GrainWords) / G1HeapRegion::GrainWords;
|
||||
}
|
||||
|
||||
size_t G1CollectedHeap::allocation_used_bytes(size_t allocation_word_size) {
|
||||
if (is_humongous(allocation_word_size)) {
|
||||
return humongous_obj_size_in_regions(allocation_word_size) * G1HeapRegion::GrainBytes;
|
||||
} else {
|
||||
return allocation_word_size * HeapWordSize;
|
||||
}
|
||||
}
|
||||
|
||||
// If could fit into free regions w/o expansion, try.
|
||||
// Otherwise, if can expand, do so.
|
||||
// Otherwise, if using ex regions might help, try with ex given back.
|
||||
@ -2955,6 +2963,15 @@ void G1CollectedHeap::abandon_collection_set() {
|
||||
collection_set()->abandon();
|
||||
}
|
||||
|
||||
size_t G1CollectedHeap::non_young_occupancy_after_allocation(size_t allocation_word_size) {
|
||||
// For simplicity, just count whole regions.
|
||||
const size_t cur_occupancy = (old_regions_count() + humongous_regions_count()) * G1HeapRegion::GrainBytes;
|
||||
// Humongous allocations will always be assigned to non-young heap, so consider
|
||||
// that allocation in the result as well. Otherwise the allocation will always
|
||||
// be in young gen, so there is no need to account it here.
|
||||
return cur_occupancy + (is_humongous(allocation_word_size) ? allocation_used_bytes(allocation_word_size) : 0);
|
||||
}
|
||||
|
||||
bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) {
|
||||
return _allocator->is_retained_old_region(hr);
|
||||
}
|
||||
|
||||
@ -1032,9 +1032,10 @@ public:
|
||||
inline void old_set_add(G1HeapRegion* hr);
|
||||
inline void old_set_remove(G1HeapRegion* hr);
|
||||
|
||||
size_t non_young_capacity_bytes() {
|
||||
return (old_regions_count() + humongous_regions_count()) * G1HeapRegion::GrainBytes;
|
||||
}
|
||||
// Returns how much memory there is assigned to non-young heap that can not be
|
||||
// allocated into any more without garbage collection after a hypothetical
|
||||
// allocation of allocation_word_size.
|
||||
size_t non_young_occupancy_after_allocation(size_t allocation_word_size);
|
||||
|
||||
// Determine whether the given region is one that we are using as an
|
||||
// old GC alloc region.
|
||||
@ -1226,6 +1227,10 @@ public:
|
||||
// requires.
|
||||
static size_t humongous_obj_size_in_regions(size_t word_size);
|
||||
|
||||
// Returns how much space in bytes an allocation of word_size will use up in the
|
||||
// heap.
|
||||
static size_t allocation_used_bytes(size_t word_size);
|
||||
|
||||
// Print the maximum heap capacity.
|
||||
size_t max_capacity() const override;
|
||||
size_t min_capacity() const;
|
||||
|
||||
@ -366,28 +366,24 @@ static size_t target_heap_capacity(size_t used_bytes, uintx free_ratio) {
|
||||
}
|
||||
|
||||
size_t G1HeapSizingPolicy::full_collection_resize_amount(bool& expand, size_t allocation_word_size) {
|
||||
// If the full collection was triggered by an allocation failure, we should account
|
||||
// for the bytes required for this allocation under used_after_gc. This prevents
|
||||
// unnecessary shrinking that would be followed by an expand call to satisfy the
|
||||
// allocation.
|
||||
size_t allocation_bytes = allocation_word_size * HeapWordSize;
|
||||
if (_g1h->is_humongous(allocation_word_size)) {
|
||||
// Humongous objects are allocated in entire regions, we must calculate
|
||||
// required space in terms of full regions, not just the object size.
|
||||
allocation_bytes = G1HeapRegion::align_up_to_region_byte_size(allocation_bytes);
|
||||
}
|
||||
|
||||
const size_t capacity_after_gc = _g1h->capacity();
|
||||
// Capacity, free and used after the GC counted as full regions to
|
||||
// include the waste in the following calculations.
|
||||
const size_t capacity_after_gc = _g1h->capacity();
|
||||
const size_t used_after_gc = capacity_after_gc + allocation_bytes -
|
||||
_g1h->unused_committed_regions_in_bytes() -
|
||||
// Discount space used by current Eden to establish a
|
||||
// situation during Remark similar to at the end of full
|
||||
// GC where eden is empty. During Remark there can be an
|
||||
// arbitrary number of eden regions which would skew the
|
||||
// results.
|
||||
_g1h->eden_regions_count() * G1HeapRegion::GrainBytes;
|
||||
const size_t current_used_after_gc = capacity_after_gc -
|
||||
_g1h->unused_committed_regions_in_bytes() -
|
||||
// Discount space used by current Eden to establish a
|
||||
// situation during Remark similar to at the end of full
|
||||
// GC where eden is empty. During Remark there can be an
|
||||
// arbitrary number of eden regions which would skew the
|
||||
// results.
|
||||
_g1h->eden_regions_count() * G1HeapRegion::GrainBytes;
|
||||
|
||||
// Add pending allocation;
|
||||
const size_t used_after_gc = current_used_after_gc +
|
||||
// If the full collection was triggered by an allocation failure,
|
||||
// account that allocation too. Otherwise we could shrink and then
|
||||
// expand immediately to satisfy the allocation.
|
||||
_g1h->allocation_used_bytes(allocation_word_size);
|
||||
|
||||
size_t minimum_desired_capacity = target_heap_capacity(used_after_gc, MinHeapFreeRatio);
|
||||
size_t maximum_desired_capacity = target_heap_capacity(used_after_gc, MaxHeapFreeRatio);
|
||||
|
||||
@ -44,32 +44,37 @@ void G1IHOPControl::update_target_occupancy(size_t new_target_occupancy) {
|
||||
_target_occupancy = new_target_occupancy;
|
||||
}
|
||||
|
||||
void G1IHOPControl::report_statistics(G1NewTracer* new_tracer, size_t non_young_occupancy) {
|
||||
print_log(non_young_occupancy);
|
||||
send_trace_event(new_tracer, non_young_occupancy);
|
||||
}
|
||||
|
||||
void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t additional_buffer_size) {
|
||||
assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s);
|
||||
|
||||
_last_allocation_time_s = allocation_time_s;
|
||||
}
|
||||
|
||||
void G1IHOPControl::print() {
|
||||
void G1IHOPControl::print_log(size_t non_young_occupancy) {
|
||||
assert(_target_occupancy > 0, "Target occupancy still not updated yet.");
|
||||
size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold();
|
||||
log_debug(gc, ihop)("Basic information (value update), threshold: %zuB (%1.2f), target occupancy: %zuB, current occupancy: %zuB, "
|
||||
log_debug(gc, ihop)("Basic information (value update), threshold: %zuB (%1.2f), target occupancy: %zuB, non-young occupancy: %zuB, "
|
||||
"recent allocation size: %zuB, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms",
|
||||
cur_conc_mark_start_threshold,
|
||||
percent_of(cur_conc_mark_start_threshold, _target_occupancy),
|
||||
_target_occupancy,
|
||||
G1CollectedHeap::heap()->used(),
|
||||
non_young_occupancy,
|
||||
_old_gen_alloc_tracker->last_period_old_gen_bytes(),
|
||||
_last_allocation_time_s * 1000.0,
|
||||
_last_allocation_time_s > 0.0 ? _old_gen_alloc_tracker->last_period_old_gen_bytes() / _last_allocation_time_s : 0.0,
|
||||
last_marking_length_s() * 1000.0);
|
||||
}
|
||||
|
||||
void G1IHOPControl::send_trace_event(G1NewTracer* tracer) {
|
||||
void G1IHOPControl::send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy) {
|
||||
assert(_target_occupancy > 0, "Target occupancy still not updated yet.");
|
||||
tracer->report_basic_ihop_statistics(get_conc_mark_start_threshold(),
|
||||
_target_occupancy,
|
||||
G1CollectedHeap::heap()->used(),
|
||||
non_young_occupancy,
|
||||
_old_gen_alloc_tracker->last_period_old_gen_bytes(),
|
||||
_last_allocation_time_s,
|
||||
last_marking_length_s());
|
||||
@ -165,27 +170,27 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) {
|
||||
_marking_times_s.add(marking_length_s);
|
||||
}
|
||||
|
||||
void G1AdaptiveIHOPControl::print() {
|
||||
G1IHOPControl::print();
|
||||
size_t actual_target = actual_target_threshold();
|
||||
log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: %zuB (%1.2f), internal target occupancy: %zuB, "
|
||||
"occupancy: %zuB, additional buffer size: %zuB, predicted old gen allocation rate: %1.2fB/s, "
|
||||
void G1AdaptiveIHOPControl::print_log(size_t non_young_occupancy) {
|
||||
G1IHOPControl::print_log(non_young_occupancy);
|
||||
size_t actual_threshold = actual_target_threshold();
|
||||
log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: %zuB (%1.2f), internal target threshold: %zuB, "
|
||||
"non-young occupancy: %zuB, additional buffer size: %zuB, predicted old gen allocation rate: %1.2fB/s, "
|
||||
"predicted marking phase length: %1.2fms, prediction active: %s",
|
||||
get_conc_mark_start_threshold(),
|
||||
percent_of(get_conc_mark_start_threshold(), actual_target),
|
||||
actual_target,
|
||||
G1CollectedHeap::heap()->used(),
|
||||
percent_of(get_conc_mark_start_threshold(), actual_threshold),
|
||||
actual_threshold,
|
||||
non_young_occupancy,
|
||||
_last_unrestrained_young_size,
|
||||
predict(&_allocation_rate_s),
|
||||
predict(&_marking_times_s) * 1000.0,
|
||||
have_enough_data_for_prediction() ? "true" : "false");
|
||||
}
|
||||
|
||||
void G1AdaptiveIHOPControl::send_trace_event(G1NewTracer* tracer) {
|
||||
G1IHOPControl::send_trace_event(tracer);
|
||||
void G1AdaptiveIHOPControl::send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy) {
|
||||
G1IHOPControl::send_trace_event(tracer, non_young_occupancy);
|
||||
tracer->report_adaptive_ihop_statistics(get_conc_mark_start_threshold(),
|
||||
actual_target_threshold(),
|
||||
G1CollectedHeap::heap()->used(),
|
||||
non_young_occupancy,
|
||||
_last_unrestrained_young_size,
|
||||
predict(&_allocation_rate_s),
|
||||
predict(&_marking_times_s),
|
||||
|
||||
@ -55,7 +55,11 @@ class G1IHOPControl : public CHeapObj<mtGC> {
|
||||
// Most recent time from the end of the concurrent start to the start of the first
|
||||
// mixed gc.
|
||||
virtual double last_marking_length_s() const = 0;
|
||||
public:
|
||||
|
||||
virtual void print_log(size_t non_young_occupancy);
|
||||
virtual void send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy);
|
||||
|
||||
public:
|
||||
virtual ~G1IHOPControl() { }
|
||||
|
||||
// Get the current non-young occupancy at which concurrent marking should start.
|
||||
@ -76,8 +80,7 @@ class G1IHOPControl : public CHeapObj<mtGC> {
|
||||
// the first mixed gc.
|
||||
virtual void update_marking_length(double marking_length_s) = 0;
|
||||
|
||||
virtual void print();
|
||||
virtual void send_trace_event(G1NewTracer* tracer);
|
||||
void report_statistics(G1NewTracer* tracer, size_t non_young_occupancy);
|
||||
};
|
||||
|
||||
// The returned concurrent mark starting occupancy threshold is a fixed value
|
||||
@ -139,6 +142,10 @@ class G1AdaptiveIHOPControl : public G1IHOPControl {
|
||||
double last_mutator_period_old_allocation_rate() const;
|
||||
protected:
|
||||
virtual double last_marking_length_s() const { return _marking_times_s.last(); }
|
||||
|
||||
virtual void print_log(size_t non_young_occupancy);
|
||||
virtual void send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy);
|
||||
|
||||
public:
|
||||
G1AdaptiveIHOPControl(double ihop_percent,
|
||||
G1OldGenAllocationTracker const* old_gen_alloc_tracker,
|
||||
@ -150,9 +157,6 @@ class G1AdaptiveIHOPControl : public G1IHOPControl {
|
||||
|
||||
virtual void update_allocation_info(double allocation_time_s, size_t additional_buffer_size);
|
||||
virtual void update_marking_length(double marking_length_s);
|
||||
|
||||
virtual void print();
|
||||
virtual void send_trace_event(G1NewTracer* tracer);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_G1_G1IHOPCONTROL_HPP
|
||||
|
||||
@ -749,22 +749,14 @@ bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_wor
|
||||
}
|
||||
|
||||
size_t marking_initiating_used_threshold = _ihop_control->get_conc_mark_start_threshold();
|
||||
|
||||
size_t cur_used_bytes = _g1h->non_young_capacity_bytes();
|
||||
size_t allocation_byte_size = allocation_word_size * HeapWordSize;
|
||||
// For humongous allocations, we need to consider that we actually use full regions
|
||||
// for allocations. So compare the threshold to this size.
|
||||
if (_g1h->is_humongous(allocation_word_size)) {
|
||||
allocation_byte_size = G1HeapRegion::align_up_to_region_byte_size(allocation_byte_size);
|
||||
}
|
||||
size_t marking_request_bytes = cur_used_bytes + allocation_byte_size;
|
||||
size_t non_young_occupancy = _g1h->non_young_occupancy_after_allocation(allocation_word_size);
|
||||
|
||||
bool result = false;
|
||||
if (marking_request_bytes > marking_initiating_used_threshold) {
|
||||
if (non_young_occupancy > marking_initiating_used_threshold) {
|
||||
result = collector_state()->in_young_only_phase();
|
||||
log_debug(gc, ergo, ihop)("%s occupancy: %zuB allocation request: %zuB threshold: %zuB (%1.2f) source: %s",
|
||||
log_debug(gc, ergo, ihop)("%s non-young occupancy: %zuB allocation request: %zuB threshold: %zuB (%1.2f) source: %s",
|
||||
result ? "Request concurrent cycle initiation (occupancy higher than threshold)" : "Do not request concurrent cycle initiation (still doing mixed collections)",
|
||||
cur_used_bytes, allocation_byte_size, marking_initiating_used_threshold, (double) marking_initiating_used_threshold / _g1h->capacity() * 100, source);
|
||||
non_young_occupancy, allocation_word_size * HeapWordSize, marking_initiating_used_threshold, (double) marking_initiating_used_threshold / _g1h->capacity() * 100, source);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -995,10 +987,10 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar
|
||||
update_young_length_bounds();
|
||||
|
||||
_old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes);
|
||||
update_ihop_prediction(app_time_ms / 1000.0,
|
||||
G1GCPauseTypeHelper::is_young_only_pause(this_pause));
|
||||
|
||||
_ihop_control->send_trace_event(_g1h->gc_tracer_stw());
|
||||
if (update_ihop_prediction(app_time_ms / 1000.0,
|
||||
G1GCPauseTypeHelper::is_young_only_pause(this_pause))) {
|
||||
_ihop_control->report_statistics(_g1h->gc_tracer_stw(), _g1h->non_young_occupancy_after_allocation(allocation_word_size));
|
||||
}
|
||||
} else {
|
||||
// Any garbage collection triggered as periodic collection resets the time-to-mixed
|
||||
// measurement. Periodic collection typically means that the application is "inactive", i.e.
|
||||
@ -1045,7 +1037,7 @@ G1IHOPControl* G1Policy::create_ihop_control(const G1OldGenAllocationTracker* ol
|
||||
}
|
||||
}
|
||||
|
||||
void G1Policy::update_ihop_prediction(double mutator_time_s,
|
||||
bool G1Policy::update_ihop_prediction(double mutator_time_s,
|
||||
bool this_gc_was_young_only) {
|
||||
// Always try to update IHOP prediction. Even evacuation failures give information
|
||||
// about e.g. whether to start IHOP earlier next time.
|
||||
@ -1082,13 +1074,7 @@ void G1Policy::update_ihop_prediction(double mutator_time_s,
|
||||
report = true;
|
||||
}
|
||||
|
||||
if (report) {
|
||||
report_ihop_statistics();
|
||||
}
|
||||
}
|
||||
|
||||
void G1Policy::report_ihop_statistics() {
|
||||
_ihop_control->print();
|
||||
return report;
|
||||
}
|
||||
|
||||
void G1Policy::record_young_gc_pause_end(bool evacuation_failed) {
|
||||
|
||||
@ -60,10 +60,10 @@ class G1Policy: public CHeapObj<mtGC> {
|
||||
|
||||
static G1IHOPControl* create_ihop_control(const G1OldGenAllocationTracker* old_gen_alloc_tracker,
|
||||
const G1Predictions* predictor);
|
||||
// Update the IHOP control with necessary statistics.
|
||||
void update_ihop_prediction(double mutator_time_s,
|
||||
// Update the IHOP control with the necessary statistics. Returns true if there
|
||||
// has been a significant update to the prediction.
|
||||
bool update_ihop_prediction(double mutator_time_s,
|
||||
bool this_gc_was_young_only);
|
||||
void report_ihop_statistics();
|
||||
|
||||
G1Predictions _predictor;
|
||||
G1Analytics* _analytics;
|
||||
|
||||
@ -98,13 +98,13 @@ void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summar
|
||||
|
||||
void G1NewTracer::report_basic_ihop_statistics(size_t threshold,
|
||||
size_t target_ccupancy,
|
||||
size_t current_occupancy,
|
||||
size_t non_young_occupancy,
|
||||
size_t last_allocation_size,
|
||||
double last_allocation_duration,
|
||||
double last_marking_length) {
|
||||
send_basic_ihop_statistics(threshold,
|
||||
target_ccupancy,
|
||||
current_occupancy,
|
||||
non_young_occupancy,
|
||||
last_allocation_size,
|
||||
last_allocation_duration,
|
||||
last_marking_length);
|
||||
@ -206,7 +206,7 @@ void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) c
|
||||
|
||||
void G1NewTracer::send_basic_ihop_statistics(size_t threshold,
|
||||
size_t target_occupancy,
|
||||
size_t current_occupancy,
|
||||
size_t non_young_occupancy,
|
||||
size_t last_allocation_size,
|
||||
double last_allocation_duration,
|
||||
double last_marking_length) {
|
||||
@ -216,7 +216,7 @@ void G1NewTracer::send_basic_ihop_statistics(size_t threshold,
|
||||
evt.set_threshold(threshold);
|
||||
evt.set_targetOccupancy(target_occupancy);
|
||||
evt.set_thresholdPercentage(target_occupancy > 0 ? ((double)threshold / target_occupancy) : 0.0);
|
||||
evt.set_currentOccupancy(current_occupancy);
|
||||
evt.set_currentOccupancy(non_young_occupancy);
|
||||
evt.set_recentMutatorAllocationSize(last_allocation_size);
|
||||
evt.set_recentMutatorDuration(last_allocation_duration * MILLIUNITS);
|
||||
evt.set_recentAllocationRate(last_allocation_duration != 0.0 ? last_allocation_size / last_allocation_duration : 0.0);
|
||||
|
||||
@ -73,13 +73,13 @@ private:
|
||||
|
||||
void send_basic_ihop_statistics(size_t threshold,
|
||||
size_t target_occupancy,
|
||||
size_t current_occupancy,
|
||||
size_t non_young_occupancy,
|
||||
size_t last_allocation_size,
|
||||
double last_allocation_duration,
|
||||
double last_marking_length);
|
||||
void send_adaptive_ihop_statistics(size_t threshold,
|
||||
size_t internal_target_occupancy,
|
||||
size_t current_occupancy,
|
||||
size_t non_young_occupancy,
|
||||
size_t additional_buffer_size,
|
||||
double predicted_allocation_rate,
|
||||
double predicted_marking_length,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user