mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-10 02:18:46 +00:00
8343782: G1: Use one G1CardSet instance for multiple old gen regions
Reviewed-by: ayang, tschatzl
This commit is contained in:
parent
006ed5c02b
commit
86cec4ea2c
@ -779,6 +779,15 @@ G1AddCardResult G1CardSet::add_card(uintptr_t card) {
|
||||
uint card_within_region;
|
||||
split_card(card, card_region, card_within_region);
|
||||
|
||||
#ifdef ASSERT
|
||||
{
|
||||
uint region_idx = card_region >> config()->log2_card_regions_per_heap_region();
|
||||
G1HeapRegion* r = G1CollectedHeap::heap()->region_at(region_idx);
|
||||
assert(!r->rem_set()->is_added_to_cset_group() ||
|
||||
r->rem_set()->cset_group()->card_set() != this, "Should not be sharing a cardset");
|
||||
}
|
||||
#endif
|
||||
|
||||
return add_card(card_region, card_within_region, true /* increment_total */);
|
||||
}
|
||||
|
||||
|
||||
@ -1159,8 +1159,7 @@ G1CollectedHeap::G1CollectedHeap() :
|
||||
_rem_set(nullptr),
|
||||
_card_set_config(),
|
||||
_card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()),
|
||||
_young_regions_cardset_mm(card_set_config(), card_set_freelist_pool()),
|
||||
_young_regions_cardset(card_set_config(), &_young_regions_cardset_mm),
|
||||
_young_regions_cset_group(card_set_config(), &_card_set_freelist_pool, 1u /* group_id */),
|
||||
_cm(nullptr),
|
||||
_cm_thread(nullptr),
|
||||
_cr(nullptr),
|
||||
@ -2716,7 +2715,7 @@ bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) {
|
||||
void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) {
|
||||
_eden.add(hr);
|
||||
_policy->set_region_eden(hr);
|
||||
hr->install_group_cardset(young_regions_cardset());
|
||||
young_regions_cset_group()->add(hr);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -2927,7 +2926,7 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio
|
||||
_survivor.add(new_alloc_region);
|
||||
register_new_survivor_region_with_region_attr(new_alloc_region);
|
||||
// Install the group cardset.
|
||||
new_alloc_region->install_group_cardset(young_regions_cardset());
|
||||
young_regions_cset_group()->add(new_alloc_region);
|
||||
} else {
|
||||
new_alloc_region->set_old();
|
||||
}
|
||||
@ -3070,6 +3069,8 @@ void G1CollectedHeap::finish_codecache_marking_cycle() {
|
||||
CodeCache::arm_all_nmethods();
|
||||
}
|
||||
|
||||
void G1CollectedHeap::prepare_group_cardsets_for_scan () {
|
||||
_young_regions_cardset.reset_table_scanner_for_groups();
|
||||
void G1CollectedHeap::prepare_group_cardsets_for_scan() {
|
||||
young_regions_cardset()->reset_table_scanner_for_groups();
|
||||
|
||||
collection_set()->prepare_groups_for_scan();
|
||||
}
|
||||
|
||||
@ -781,15 +781,15 @@ private:
|
||||
G1MonotonicArenaFreePool _card_set_freelist_pool;
|
||||
|
||||
// Group cardsets
|
||||
G1CardSetMemoryManager _young_regions_cardset_mm;
|
||||
G1CardSet _young_regions_cardset;
|
||||
G1CSetCandidateGroup _young_regions_cset_group;
|
||||
|
||||
public:
|
||||
G1CardSetConfiguration* card_set_config() { return &_card_set_config; }
|
||||
|
||||
G1CardSet* young_regions_cardset() { return &_young_regions_cardset; };
|
||||
G1CSetCandidateGroup* young_regions_cset_group() { return &_young_regions_cset_group; }
|
||||
G1CardSet* young_regions_cardset() { return _young_regions_cset_group.card_set(); };
|
||||
|
||||
G1CardSetMemoryManager* young_regions_card_set_mm() { return &_young_regions_cardset_mm; }
|
||||
G1MonotonicArenaMemoryStats young_regions_card_set_memory_stats() { return _young_regions_cset_group.card_set_memory_stats(); }
|
||||
|
||||
void prepare_group_cardsets_for_scan();
|
||||
|
||||
|
||||
@ -225,7 +225,6 @@ void G1CollectedHeap::register_region_with_region_attr(G1HeapRegion* r) {
|
||||
}
|
||||
|
||||
void G1CollectedHeap::register_old_region_with_region_attr(G1HeapRegion* r) {
|
||||
assert(!r->has_pinned_objects(), "must be");
|
||||
assert(r->rem_set()->is_complete(), "must be");
|
||||
_region_attr.set_in_old(r->hrm_index(), true);
|
||||
_rem_set->exclude_region_from_scan(r->hrm_index());
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
#include "gc/g1/g1Analytics.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectionSet.hpp"
|
||||
#include "gc/g1/g1CollectionSet.inline.hpp"
|
||||
#include "gc/g1/g1CollectionSetCandidates.inline.hpp"
|
||||
#include "gc/g1/g1CollectorState.hpp"
|
||||
#include "gc/g1/g1HeapRegion.inline.hpp"
|
||||
@ -53,10 +53,13 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
|
||||
_collection_set_regions(nullptr),
|
||||
_collection_set_cur_length(0),
|
||||
_collection_set_max_length(0),
|
||||
_collection_set_groups(),
|
||||
_selected_groups_cur_length(0),
|
||||
_selected_groups_inc_part_start(0),
|
||||
_eden_region_length(0),
|
||||
_survivor_region_length(0),
|
||||
_initial_old_region_length(0),
|
||||
_optional_old_regions(),
|
||||
_optional_groups(),
|
||||
_inc_build_state(Inactive),
|
||||
_inc_part_start(0) {
|
||||
}
|
||||
@ -77,7 +80,8 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
|
||||
"Young region length %u should match collection set length %u", young_region_length(), _collection_set_cur_length);
|
||||
|
||||
_initial_old_region_length = 0;
|
||||
_optional_old_regions.clear();
|
||||
assert(_optional_groups.length() == 0, "Should not have any optional groups yet");
|
||||
_optional_groups.clear();
|
||||
}
|
||||
|
||||
void G1CollectionSet::initialize(uint max_region_length) {
|
||||
@ -91,7 +95,10 @@ void G1CollectionSet::initialize(uint max_region_length) {
|
||||
void G1CollectionSet::abandon_all_candidates() {
|
||||
_candidates.clear();
|
||||
_initial_old_region_length = 0;
|
||||
_optional_old_regions.clear();
|
||||
}
|
||||
|
||||
void G1CollectionSet::prepare_groups_for_scan () {
|
||||
collection_set_groups()->prepare_for_scan();
|
||||
}
|
||||
|
||||
void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
|
||||
@ -101,6 +108,8 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
|
||||
"Precondition, actively building cset or adding optional later on");
|
||||
assert(hr->is_old(), "the region should be old");
|
||||
|
||||
assert(!hr->rem_set()->is_added_to_cset_group(), "Should have already uninstalled group remset");
|
||||
|
||||
assert(!hr->in_collection_set(), "should not already be in the collection set");
|
||||
_g1h->register_old_region_with_region_attr(hr);
|
||||
|
||||
@ -126,6 +135,7 @@ void G1CollectionSet::finalize_incremental_building() {
|
||||
void G1CollectionSet::clear() {
|
||||
assert_at_safepoint_on_vm_thread();
|
||||
_collection_set_cur_length = 0;
|
||||
_collection_set_groups.clear();
|
||||
}
|
||||
|
||||
void G1CollectionSet::iterate(G1HeapRegionClosure* cl) const {
|
||||
@ -151,10 +161,10 @@ void G1CollectionSet::par_iterate(G1HeapRegionClosure* cl,
|
||||
void G1CollectionSet::iterate_optional(G1HeapRegionClosure* cl) const {
|
||||
assert_at_safepoint();
|
||||
|
||||
for (G1HeapRegion* r : _optional_old_regions) {
|
||||
_optional_groups.iterate([&] (G1HeapRegion* r) {
|
||||
bool result = cl->do_heap_region(r);
|
||||
guarantee(!result, "Must not cancel iteration");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void G1CollectionSet::iterate_incremental_part_from(G1HeapRegionClosure* cl,
|
||||
@ -320,59 +330,40 @@ static int compare_region_idx(const uint a, const uint b) {
|
||||
return static_cast<int>(a-b);
|
||||
}
|
||||
|
||||
// The current mechanism skips evacuation of pinned old regions like g1 does for
|
||||
// young regions:
|
||||
// * evacuating pinned marking collection set candidate regions (available during mixed
|
||||
// gc) like young regions would not result in any memory gain but only take additional
|
||||
// time away from processing regions that would actually result in memory being freed.
|
||||
// To advance mixed gc progress (we committed to evacuate all marking collection set
|
||||
// candidate regions within the maximum number of mixed gcs in the phase), move them
|
||||
// to the optional collection set candidates to reclaim them asap as time permits.
|
||||
// * evacuating out retained collection set candidates would also just take up time with
|
||||
// no actual space freed in old gen. Better to concentrate on others.
|
||||
// Retained collection set candidates are aged out, ie. made to regular old regions
|
||||
// without remembered sets after a few attempts to save computation costs of keeping
|
||||
// them candidates for very long living pinned regions.
|
||||
// The current mechanism for evacuating pinned old regions is as below:
|
||||
// * pinned regions in the marking collection set candidate list (available during mixed gc) are evacuated like
|
||||
// pinned young regions to avoid the complexity of dealing with pinned regions that are part of a
|
||||
// collection group sharing a single cardset. These regions will be partially evacuated and added to the
|
||||
// retained collection set by the evacuation failure handling mechanism.
|
||||
// * evacuating pinned regions out of retained collection set candidates would also just take up time
|
||||
// with no actual space freed in old gen. Better to concentrate on others. So we skip over pinned
|
||||
// regions in retained collection set candidates. Retained collection set candidates are aged out, ie.
|
||||
// made to regular old regions without remembered sets after a few attempts to save computation costs
|
||||
// of keeping them candidates for very long living pinned regions.
|
||||
void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
|
||||
double non_young_start_time_sec = os::elapsedTime();
|
||||
|
||||
_selected_groups_cur_length = 0;
|
||||
_selected_groups_inc_part_start = 0;
|
||||
|
||||
if (!candidates()->is_empty()) {
|
||||
candidates()->verify();
|
||||
|
||||
G1CollectionCandidateRegionList initial_old_regions;
|
||||
assert(_optional_old_regions.length() == 0, "must be");
|
||||
G1CollectionCandidateRegionList pinned_marking_regions;
|
||||
G1CollectionCandidateRegionList pinned_retained_regions;
|
||||
|
||||
if (collector_state()->in_mixed_phase()) {
|
||||
time_remaining_ms = select_candidates_from_marking(time_remaining_ms,
|
||||
&initial_old_regions,
|
||||
&pinned_marking_regions);
|
||||
time_remaining_ms = select_candidates_from_marking(time_remaining_ms);
|
||||
} else {
|
||||
log_debug(gc, ergo, cset)("Do not add marking candidates to collection set due to pause type.");
|
||||
}
|
||||
|
||||
select_candidates_from_retained(time_remaining_ms,
|
||||
&initial_old_regions,
|
||||
&pinned_retained_regions);
|
||||
|
||||
// Move initially selected old regions to collection set directly.
|
||||
move_candidates_to_collection_set(&initial_old_regions);
|
||||
// Only prepare selected optional regions for now.
|
||||
prepare_optional_regions(&_optional_old_regions);
|
||||
// Move pinned marking regions we came across to retained candidates so that
|
||||
// there is progress in the mixed gc phase.
|
||||
move_pinned_marking_to_retained(&pinned_marking_regions);
|
||||
// Drop pinned retained regions to make progress with retained regions. Regions
|
||||
// in that list must have been pinned for at least G1NumCollectionsKeepPinned
|
||||
// GCs and hence are considered "long lived".
|
||||
drop_pinned_retained_regions(&pinned_retained_regions);
|
||||
|
||||
if (candidates()->retained_groups().num_regions() > 0) {
|
||||
select_candidates_from_retained(time_remaining_ms);
|
||||
}
|
||||
candidates()->verify();
|
||||
} else {
|
||||
log_debug(gc, ergo, cset)("No candidates to reclaim.");
|
||||
}
|
||||
|
||||
_selected_groups_cur_length = collection_set_groups()->length();
|
||||
stop_incremental_building();
|
||||
|
||||
double non_young_end_time_sec = os::elapsedTime();
|
||||
@ -381,75 +372,60 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
|
||||
QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
|
||||
}
|
||||
|
||||
void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions) {
|
||||
for (G1HeapRegion* r : *regions) {
|
||||
_g1h->clear_region_attr(r);
|
||||
add_old_region(r);
|
||||
}
|
||||
candidates()->remove(regions);
|
||||
}
|
||||
|
||||
static void print_finish_message(const char* reason, bool from_marking) {
|
||||
log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).",
|
||||
from_marking ? "marking" : "retained", reason);
|
||||
}
|
||||
|
||||
double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* initial_old_regions,
|
||||
G1CollectionCandidateRegionList* pinned_old_regions) {
|
||||
double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) {
|
||||
uint num_expensive_regions = 0;
|
||||
|
||||
uint num_initial_regions_selected = 0;
|
||||
uint num_optional_regions_selected = 0;
|
||||
uint num_pinned_regions = 0;
|
||||
uint num_inital_regions = 0;
|
||||
uint num_initial_groups = 0;
|
||||
uint num_optional_regions = 0;
|
||||
|
||||
double predicted_initial_time_ms = 0.0;
|
||||
double predicted_optional_time_ms = 0.0;
|
||||
|
||||
double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction();
|
||||
|
||||
const uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length());
|
||||
const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length());
|
||||
const uint max_optional_regions = max_old_cset_length - min_old_cset_length;
|
||||
uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length());
|
||||
uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length());
|
||||
bool check_time_remaining = _policy->use_adaptive_young_list_length();
|
||||
|
||||
G1CollectionCandidateList* marking_list = &candidates()->marking_regions();
|
||||
assert(marking_list != nullptr, "must be");
|
||||
G1CSetCandidateGroupList* from_marking_groups = &candidates()->from_marking_groups();
|
||||
|
||||
log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. "
|
||||
"Min %u regions, max %u regions, available %u regions"
|
||||
"Min %u regions, max %u regions, available %u regions (%u groups), "
|
||||
"time remaining %1.2fms, optional threshold %1.2fms",
|
||||
min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms);
|
||||
min_old_cset_length, max_old_cset_length, from_marking_groups->num_regions(), from_marking_groups->length(),
|
||||
time_remaining_ms, optional_threshold_ms);
|
||||
|
||||
G1CollectionCandidateListIterator iter = marking_list->begin();
|
||||
for (; iter != marking_list->end(); ++iter) {
|
||||
if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) {
|
||||
G1CSetCandidateGroupList selected_groups;
|
||||
|
||||
for (G1CSetCandidateGroup* group : *from_marking_groups) {
|
||||
if (num_inital_regions + num_optional_regions >= max_old_cset_length) {
|
||||
// Added maximum number of old regions to the CSet.
|
||||
print_finish_message("Maximum number of regions reached", true);
|
||||
break;
|
||||
}
|
||||
G1HeapRegion* hr = (*iter)->_r;
|
||||
// Skip evacuating pinned marking regions because we are not getting any free
|
||||
// space from them (and we expect to get free space from marking candidates).
|
||||
// Also prepare to move them to retained regions to be evacuated optionally later
|
||||
// to not impact the mixed phase too much.
|
||||
if (hr->has_pinned_objects()) {
|
||||
num_pinned_regions++;
|
||||
(*iter)->update_num_unreclaimed();
|
||||
log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index());
|
||||
pinned_old_regions->append(hr);
|
||||
continue;
|
||||
}
|
||||
double predicted_time_ms = _policy->predict_region_total_time_ms(hr, false);
|
||||
|
||||
double predicted_time_ms = group->predict_group_total_time_ms();
|
||||
|
||||
time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
|
||||
// Add regions to old set until we reach the minimum amount
|
||||
if (initial_old_regions->length() < min_old_cset_length) {
|
||||
initial_old_regions->append(hr);
|
||||
num_initial_regions_selected++;
|
||||
if (num_inital_regions < min_old_cset_length) {
|
||||
|
||||
num_initial_groups++;
|
||||
|
||||
add_group_to_collection_set(group);
|
||||
selected_groups.append(group);
|
||||
|
||||
num_inital_regions += group->length();
|
||||
|
||||
predicted_initial_time_ms += predicted_time_ms;
|
||||
// Record the number of regions added with no time remaining
|
||||
if (time_remaining_ms == 0.0) {
|
||||
num_expensive_regions++;
|
||||
num_expensive_regions += group->length();
|
||||
}
|
||||
} else if (!check_time_remaining) {
|
||||
// In the non-auto-tuning case, we'll finish adding regions
|
||||
@ -459,22 +435,34 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms,
|
||||
} else {
|
||||
// Keep adding regions to old set until we reach the optional threshold
|
||||
if (time_remaining_ms > optional_threshold_ms) {
|
||||
num_initial_groups++;
|
||||
|
||||
add_group_to_collection_set(group);
|
||||
selected_groups.append(group);
|
||||
|
||||
num_inital_regions += group->length();
|
||||
|
||||
predicted_initial_time_ms += predicted_time_ms;
|
||||
initial_old_regions->append(hr);
|
||||
num_initial_regions_selected++;
|
||||
|
||||
} else if (time_remaining_ms > 0) {
|
||||
// Keep adding optional regions until time is up.
|
||||
assert(_optional_old_regions.length() < max_optional_regions, "Should not be possible.");
|
||||
_optional_groups.append(group);
|
||||
prepare_optional_group(group, num_optional_regions);
|
||||
num_optional_regions += group->length();
|
||||
predicted_optional_time_ms += predicted_time_ms;
|
||||
_optional_old_regions.append(hr);
|
||||
num_optional_regions_selected++;
|
||||
} else {
|
||||
print_finish_message("Predicted time too high", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iter == marking_list->end()) {
|
||||
|
||||
// Remove selected groups from list of candidate groups.
|
||||
if (num_initial_groups > 0) {
|
||||
candidates()->remove(&selected_groups);
|
||||
}
|
||||
|
||||
if (from_marking_groups->length() == 0) {
|
||||
log_debug(gc, ergo, cset)("Marking candidates exhausted.");
|
||||
}
|
||||
|
||||
@ -483,22 +471,20 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms,
|
||||
num_expensive_regions);
|
||||
}
|
||||
|
||||
log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, "
|
||||
log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u regions (%u groups), optional: %u regions (%u groups), "
|
||||
"predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms",
|
||||
num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions,
|
||||
selected_groups.num_regions(), selected_groups.length(), _optional_groups.num_regions(), _optional_groups.length(),
|
||||
predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms);
|
||||
|
||||
assert(initial_old_regions->length() == num_initial_regions_selected, "must be");
|
||||
assert(_optional_old_regions.length() == num_optional_regions_selected, "must be");
|
||||
assert(selected_groups.num_regions() == num_inital_regions, "must be");
|
||||
assert(_optional_groups.num_regions() == num_optional_regions, "must be");
|
||||
return time_remaining_ms;
|
||||
}
|
||||
|
||||
void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* initial_old_regions,
|
||||
G1CollectionCandidateRegionList* pinned_old_regions) {
|
||||
uint num_initial_regions_selected = 0;
|
||||
uint num_optional_regions_selected = 0;
|
||||
uint num_expensive_regions_selected = 0;
|
||||
void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) {
|
||||
uint num_initial_regions = 0;
|
||||
uint num_optional_regions = 0;
|
||||
uint num_expensive_regions = 0;
|
||||
uint num_pinned_regions = 0;
|
||||
|
||||
double predicted_initial_time_ms = 0.0;
|
||||
@ -513,17 +499,27 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms,
|
||||
double optional_time_remaining_ms = _policy->max_time_for_retaining();
|
||||
time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms);
|
||||
|
||||
G1CollectionCandidateList* retained_list = &candidates()->retained_regions();
|
||||
G1CSetCandidateGroupList* retained_groups = &candidates()->retained_groups();
|
||||
|
||||
log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. "
|
||||
"Min %u regions, available %u, "
|
||||
"Min %u regions, available %u regions (%u groups), "
|
||||
"time remaining %1.2fms, optional remaining %1.2fms",
|
||||
min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms);
|
||||
min_regions, retained_groups->num_regions(), retained_groups->length(),
|
||||
time_remaining_ms, optional_time_remaining_ms);
|
||||
|
||||
G1CSetCandidateGroupList remove_from_retained;
|
||||
G1CSetCandidateGroupList groups_to_abandon;
|
||||
|
||||
for (G1CSetCandidateGroup* group : *retained_groups) {
|
||||
assert(group->length() == 1, "Retained groups should have only 1 region");
|
||||
|
||||
double predicted_time_ms = group->predict_group_total_time_ms();
|
||||
|
||||
for (G1CollectionSetCandidateInfo* ci : *retained_list) {
|
||||
G1HeapRegion* r = ci->_r;
|
||||
double predicted_time_ms = _policy->predict_region_total_time_ms(r, collector_state()->in_young_only_phase());
|
||||
bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms;
|
||||
|
||||
G1CollectionSetCandidateInfo* ci = group->at(0); // We only have one region in the group.
|
||||
G1HeapRegion* r = ci->_r;
|
||||
|
||||
// If we can't reclaim that region ignore it for now.
|
||||
if (r->has_pinned_objects()) {
|
||||
num_pinned_regions++;
|
||||
@ -531,22 +527,32 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms,
|
||||
log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index());
|
||||
} else {
|
||||
log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index());
|
||||
pinned_old_regions->append(r);
|
||||
// Drop pinned retained regions to make progress with retained regions. Regions
|
||||
// in that list must have been pinned for at least G1NumCollectionsKeepPinned
|
||||
// GCs and hence are considered "long lived".
|
||||
_g1h->clear_region_attr(r);
|
||||
groups_to_abandon.append(group);
|
||||
remove_from_retained.append(group);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) {
|
||||
if (fits_in_remaining_time || (num_expensive_regions < min_regions)) {
|
||||
predicted_initial_time_ms += predicted_time_ms;
|
||||
if (!fits_in_remaining_time) {
|
||||
num_expensive_regions_selected++;
|
||||
num_expensive_regions++;
|
||||
}
|
||||
initial_old_regions->append(r);
|
||||
num_initial_regions_selected++;
|
||||
|
||||
add_group_to_collection_set(group);
|
||||
remove_from_retained.append(group);
|
||||
|
||||
num_initial_regions += group->length();
|
||||
} else if (predicted_time_ms <= optional_time_remaining_ms) {
|
||||
// Prepare optional collection region.
|
||||
_optional_groups.append(group);
|
||||
prepare_optional_group(group, num_optional_regions);
|
||||
num_optional_regions += group->length();
|
||||
predicted_optional_time_ms += predicted_time_ms;
|
||||
_optional_old_regions.append(r);
|
||||
num_optional_regions_selected++;
|
||||
} else {
|
||||
// Fits neither initial nor optional time limit. Exit.
|
||||
break;
|
||||
@ -555,85 +561,106 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms,
|
||||
optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms);
|
||||
}
|
||||
|
||||
uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected;
|
||||
if (num_regions_selected == retained_list->length()) {
|
||||
if (num_initial_regions == retained_groups->num_regions()) {
|
||||
log_debug(gc, ergo, cset)("Retained candidates exhausted.");
|
||||
}
|
||||
if (num_expensive_regions_selected > 0) {
|
||||
|
||||
if (num_expensive_regions > 0) {
|
||||
log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.",
|
||||
num_expensive_regions_selected);
|
||||
num_expensive_regions);
|
||||
}
|
||||
|
||||
// Remove groups from retained and also do some bookkeeping on CandidateOrigin
|
||||
// for the regions in these groups.
|
||||
candidates()->remove(&remove_from_retained);
|
||||
|
||||
groups_to_abandon.clear(true /* uninstall_group_cardset */);
|
||||
|
||||
log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, "
|
||||
"predicted initial time: %1.2fms, predicted optional time: %1.2fms, "
|
||||
"time remaining: %1.2fms optional time remaining %1.2fms",
|
||||
num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions,
|
||||
num_initial_regions, num_optional_regions, num_pinned_regions,
|
||||
predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms);
|
||||
}
|
||||
|
||||
void G1CollectionSet::select_candidates_from_optional_regions(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* selected_regions) {
|
||||
assert(optional_region_length() > 0,
|
||||
double G1CollectionSet::select_candidates_from_optional_groups(double time_remaining_ms, uint& num_regions_selected) {
|
||||
|
||||
assert(_optional_groups.num_regions() > 0,
|
||||
"Should only be called when there are optional regions");
|
||||
|
||||
uint num_groups_selected = 0;
|
||||
double total_prediction_ms = 0.0;
|
||||
G1CSetCandidateGroupList selected;
|
||||
for (G1CSetCandidateGroup* group : _optional_groups) {
|
||||
double predicted_time_ms = group->predict_group_total_time_ms();
|
||||
|
||||
for (G1HeapRegion* r : _optional_old_regions) {
|
||||
double prediction_ms = _policy->predict_region_total_time_ms(r, false);
|
||||
|
||||
if (prediction_ms > time_remaining_ms) {
|
||||
log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.",
|
||||
prediction_ms, r->hrm_index(), time_remaining_ms);
|
||||
if (predicted_time_ms > time_remaining_ms) {
|
||||
log_debug(gc, ergo, cset)("Prediction %.3fms for group with %u regions does not fit remaining time: %.3fms.",
|
||||
predicted_time_ms, group->length(), time_remaining_ms);
|
||||
break;
|
||||
}
|
||||
// This region will be included in the next optional evacuation.
|
||||
|
||||
total_prediction_ms += prediction_ms;
|
||||
time_remaining_ms -= prediction_ms;
|
||||
total_prediction_ms += predicted_time_ms;
|
||||
time_remaining_ms -= predicted_time_ms;
|
||||
|
||||
selected_regions->append(r);
|
||||
num_regions_selected += group->length();
|
||||
num_groups_selected++;
|
||||
|
||||
add_group_to_collection_set(group);
|
||||
selected.append(group);
|
||||
}
|
||||
|
||||
log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms",
|
||||
selected_regions->length(), _optional_old_regions.length(), total_prediction_ms);
|
||||
log_debug(gc, ergo, cset) ("Completed with groups, selected %u", num_regions_selected);
|
||||
// Remove selected groups from candidate list.
|
||||
if (num_groups_selected > 0) {
|
||||
_optional_groups.remove(&selected);
|
||||
candidates()->remove(&selected);
|
||||
}
|
||||
return total_prediction_ms;
|
||||
}
|
||||
|
||||
void G1CollectionSet::prepare_optional_regions(G1CollectionCandidateRegionList* regions){
|
||||
uint cur_index = 0;
|
||||
for (G1HeapRegion* r : *regions) {
|
||||
uint G1CollectionSet::select_optional_collection_set_regions(double time_remaining_ms) {
|
||||
uint optional_regions_count = num_optional_regions();
|
||||
assert(optional_regions_count > 0,
|
||||
"Should only be called when there are optional regions");
|
||||
|
||||
uint num_regions_selected = 0;
|
||||
|
||||
double total_prediction_ms = select_candidates_from_optional_groups(time_remaining_ms, num_regions_selected);
|
||||
|
||||
time_remaining_ms -= total_prediction_ms;
|
||||
|
||||
log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms",
|
||||
num_regions_selected, optional_regions_count, total_prediction_ms);
|
||||
return num_regions_selected;
|
||||
}
|
||||
|
||||
void G1CollectionSet::prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index) {
|
||||
for (G1CollectionSetCandidateInfo ci : *gr) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
|
||||
assert(r->is_old(), "the region should be old");
|
||||
assert(!r->in_collection_set(), "should not already be in the CSet");
|
||||
|
||||
_g1h->register_optional_region_with_region_attr(r);
|
||||
|
||||
r->set_index_in_opt_cset(cur_index++);
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectionSet::move_pinned_marking_to_retained(G1CollectionCandidateRegionList* regions) {
|
||||
if (regions->length() == 0) {
|
||||
return;
|
||||
void G1CollectionSet::add_group_to_collection_set(G1CSetCandidateGroup* gr) {
|
||||
for (G1CollectionSetCandidateInfo ci : *gr) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
r->uninstall_cset_group();
|
||||
assert(r->rem_set()->is_complete(), "must be");
|
||||
add_region_to_collection_set(r);
|
||||
}
|
||||
candidates()->remove(regions);
|
||||
|
||||
for (G1HeapRegion* r : *regions) {
|
||||
assert(r->has_pinned_objects(), "must be pinned");
|
||||
assert(r->rem_set()->is_complete(), "must be complete");
|
||||
candidates()->add_retained_region_unsorted(r);
|
||||
}
|
||||
candidates()->sort_by_efficiency();
|
||||
_collection_set_groups.append(gr);
|
||||
}
|
||||
|
||||
void G1CollectionSet::drop_pinned_retained_regions(G1CollectionCandidateRegionList* regions) {
|
||||
if (regions->length() == 0) {
|
||||
return;
|
||||
}
|
||||
candidates()->remove(regions);
|
||||
|
||||
// We can now drop these region's remembered sets.
|
||||
for (G1HeapRegion* r : *regions) {
|
||||
r->rem_set()->clear(true /* only_cardset */);
|
||||
}
|
||||
void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) {
|
||||
_g1h->clear_region_attr(r);
|
||||
assert(r->rem_set()->is_complete(), "Remset for region %u complete", r->hrm_index());
|
||||
add_old_region(r);
|
||||
}
|
||||
|
||||
void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) {
|
||||
@ -644,31 +671,31 @@ void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_m
|
||||
bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) {
|
||||
update_incremental_marker();
|
||||
|
||||
G1CollectionCandidateRegionList selected_regions;
|
||||
select_candidates_from_optional_regions(remaining_pause_time,
|
||||
&selected_regions);
|
||||
|
||||
move_candidates_to_collection_set(&selected_regions);
|
||||
|
||||
_optional_old_regions.remove_prefix(&selected_regions);
|
||||
uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time);
|
||||
|
||||
_selected_groups_cur_length = collection_set_groups()->length();
|
||||
stop_incremental_building();
|
||||
|
||||
_g1h->verify_region_attr_remset_is_tracked();
|
||||
|
||||
return selected_regions.length() > 0;
|
||||
return num_regions_selected > 0;
|
||||
}
|
||||
|
||||
void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* pss) {
|
||||
for (G1HeapRegion* r : _optional_old_regions) {
|
||||
pss->record_unused_optional_region(r);
|
||||
// Clear collection set marker and make sure that the remembered set information
|
||||
// is correct as we still need it later.
|
||||
_g1h->clear_region_attr(r);
|
||||
_g1h->register_region_with_region_attr(r);
|
||||
r->clear_index_in_opt_cset();
|
||||
if (_optional_groups.length() > 0) {
|
||||
auto reset = [&] (G1HeapRegion* r) {
|
||||
pss->record_unused_optional_region(r);
|
||||
// Clear collection set marker and make sure that the remembered set information
|
||||
// is correct as we still need it later.
|
||||
_g1h->clear_region_attr(r);
|
||||
_g1h->register_region_with_region_attr(r);
|
||||
r->clear_index_in_opt_cset();
|
||||
};
|
||||
|
||||
_optional_groups.iterate(reset);
|
||||
// Remove groups from list without deleting the groups or clearing the associated cardsets.
|
||||
_optional_groups.remove_selected(_optional_groups.length(), _optional_groups.num_regions());
|
||||
}
|
||||
_optional_old_regions.clear();
|
||||
|
||||
_g1h->verify_region_attr_remset_is_tracked();
|
||||
}
|
||||
|
||||
@ -146,13 +146,21 @@ class G1CollectionSet {
|
||||
volatile uint _collection_set_cur_length;
|
||||
uint _collection_set_max_length;
|
||||
|
||||
// Old gen groups selected for evacuation.
|
||||
G1CSetCandidateGroupList _collection_set_groups;
|
||||
|
||||
// Groups are added to the collection set in increments when performing optional evacuations.
|
||||
// We use the value below to track these increments.
|
||||
uint _selected_groups_cur_length;
|
||||
uint _selected_groups_inc_part_start;
|
||||
|
||||
uint _eden_region_length;
|
||||
uint _survivor_region_length;
|
||||
uint _initial_old_region_length;
|
||||
|
||||
// When doing mixed collections we can add old regions to the collection set, which
|
||||
// will be collected only if there is enough time. We call these optional (old) regions.
|
||||
G1CollectionCandidateRegionList _optional_old_regions;
|
||||
G1CSetCandidateGroupList _optional_groups;
|
||||
|
||||
enum CSetBuildType {
|
||||
Active, // We are actively building the collection set
|
||||
@ -173,16 +181,20 @@ class G1CollectionSet {
|
||||
// Add the given old region to the head of the current collection set.
|
||||
void add_old_region(G1HeapRegion* hr);
|
||||
|
||||
void move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions);
|
||||
// Prepares old regions in the given set for optional collection later. Does not
|
||||
// add the region to collection set yet.
|
||||
void prepare_optional_regions(G1CollectionCandidateRegionList* regions);
|
||||
// Moves given old regions from the marking candidates to the retained candidates.
|
||||
// This makes sure that marking candidates will not remain there to unnecessarily
|
||||
// prolong the mixed phase.
|
||||
void move_pinned_marking_to_retained(G1CollectionCandidateRegionList* regions);
|
||||
// Removes the given list of regions from the retained candidates.
|
||||
void drop_pinned_retained_regions(G1CollectionCandidateRegionList* regions);
|
||||
void prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index);
|
||||
|
||||
void add_group_to_collection_set(G1CSetCandidateGroup* gr);
|
||||
|
||||
void add_region_to_collection_set(G1HeapRegion* r);
|
||||
|
||||
double select_candidates_from_marking(double time_remaining_ms);
|
||||
|
||||
void select_candidates_from_retained(double time_remaining_ms);
|
||||
|
||||
// Select regions for evacuation from the optional candidates given the remaining time
|
||||
// and return the number of actually selected regions.
|
||||
uint select_optional_collection_set_regions(double time_remaining_ms);
|
||||
double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_regions_selected);
|
||||
|
||||
// Finalize the young part of the initial collection set. Relabel survivor regions
|
||||
// as Eden and calculate a prediction on how long the evacuation of all young regions
|
||||
@ -196,22 +208,6 @@ class G1CollectionSet {
|
||||
// and retained collection set candidates.
|
||||
void finalize_old_part(double time_remaining_ms);
|
||||
|
||||
// Calculate and fill in the initial, optional and pinned old gen candidate regions from
|
||||
// the given candidate list and the remaining time.
|
||||
// Returns the remaining time.
|
||||
double select_candidates_from_marking(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* initial_old_regions,
|
||||
G1CollectionCandidateRegionList* pinned_old_regions);
|
||||
|
||||
void select_candidates_from_retained(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* initial_old_regions,
|
||||
G1CollectionCandidateRegionList* pinned_old_regions);
|
||||
|
||||
// Calculate the number of optional regions from the given collection set candidates,
|
||||
// the remaining time and the maximum number of these regions.
|
||||
void select_candidates_from_optional_regions(double time_remaining_ms,
|
||||
G1CollectionCandidateRegionList* selected);
|
||||
|
||||
// Iterate the part of the collection set given by the offset and length applying the given
|
||||
// G1HeapRegionClosure. The worker_id will determine where in the part to start the iteration
|
||||
// to allow for more efficient parallel iteration.
|
||||
@ -232,6 +228,11 @@ public:
|
||||
G1CollectionSetCandidates* candidates() { return &_candidates; }
|
||||
const G1CollectionSetCandidates* candidates() const { return &_candidates; }
|
||||
|
||||
G1CSetCandidateGroupList* collection_set_groups() { return &_collection_set_groups; }
|
||||
const G1CSetCandidateGroupList* collection_set_groups() const { return &_collection_set_groups; }
|
||||
|
||||
void prepare_groups_for_scan();
|
||||
|
||||
void init_region_lengths(uint eden_cset_region_length,
|
||||
uint survivor_cset_region_length);
|
||||
|
||||
@ -243,9 +244,12 @@ public:
|
||||
uint eden_region_length() const { return _eden_region_length; }
|
||||
uint survivor_region_length() const { return _survivor_region_length; }
|
||||
uint initial_old_region_length() const { return _initial_old_region_length; }
|
||||
uint optional_region_length() const { return _optional_old_regions.length(); }
|
||||
uint num_optional_regions() const { return _optional_groups.num_regions(); }
|
||||
|
||||
bool only_contains_young_regions() const { return (initial_old_region_length() + optional_region_length()) == 0; }
|
||||
bool only_contains_young_regions() const { return (initial_old_region_length() + num_optional_regions()) == 0; }
|
||||
|
||||
template <class CardOrRangeVisitor>
|
||||
inline void merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers);
|
||||
|
||||
// Reset the contents of the collection set.
|
||||
void clear();
|
||||
@ -255,7 +259,11 @@ public:
|
||||
// Initialize incremental collection set info.
|
||||
void start_incremental_building();
|
||||
// Start a new collection set increment.
|
||||
void update_incremental_marker() { _inc_build_state = Active; _inc_part_start = _collection_set_cur_length; }
|
||||
void update_incremental_marker() {
|
||||
_inc_build_state = Active;
|
||||
_inc_part_start = _collection_set_cur_length;
|
||||
_selected_groups_inc_part_start = _selected_groups_cur_length;
|
||||
}
|
||||
// Stop adding regions to the current collection set increment.
|
||||
void stop_incremental_building() { _inc_build_state = Inactive; }
|
||||
|
||||
@ -268,6 +276,8 @@ public:
|
||||
// Returns the length of the whole current collection set in number of regions
|
||||
size_t cur_length() const { return _collection_set_cur_length; }
|
||||
|
||||
uint collection_groups_increment_length() const { return _selected_groups_cur_length - _selected_groups_inc_part_start; }
|
||||
|
||||
// Iterate over the entire collection set (all increments calculated so far), applying
|
||||
// the given G1HeapRegionClosure on all of them.
|
||||
void iterate(G1HeapRegionClosure* cl) const;
|
||||
|
||||
51
src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
Normal file
51
src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_G1_G1COLLECTIONSET_INLINE_HPP
|
||||
#define SHARE_GC_G1_G1COLLECTIONSET_INLINE_HPP
|
||||
|
||||
#include "gc/g1/g1CollectionSet.hpp"
|
||||
#include "gc/g1/g1HeapRegionRemSet.hpp"
|
||||
|
||||
template <class CardOrRangeVisitor>
|
||||
inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) {
|
||||
uint length = collection_groups_increment_length();
|
||||
uint offset = _selected_groups_inc_part_start;
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint start_pos = (worker_id * length) / num_workers;
|
||||
uint cur_pos = start_pos;
|
||||
uint count = 0;
|
||||
do {
|
||||
G1HeapRegionRemSet::iterate_for_merge(collection_set_groups()->at(offset + cur_pos)->card_set(), cl);
|
||||
cur_pos++;
|
||||
count++;
|
||||
if (cur_pos == length) {
|
||||
cur_pos = 0;
|
||||
}
|
||||
} while (cur_pos != start_pos);
|
||||
}
|
||||
#endif /* SHARE_GC_G1_G1COLLECTIONSET_INLINE_HPP */
|
||||
@ -25,79 +25,101 @@
|
||||
#include "gc/g1/g1CollectionSetCandidates.inline.hpp"
|
||||
#include "gc/g1/g1CollectionSetChooser.hpp"
|
||||
#include "gc/g1/g1HeapRegion.inline.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
G1CollectionCandidateList::G1CollectionCandidateList() : _candidates(2, mtGC) { }
|
||||
uint G1CSetCandidateGroup::_next_group_id = 2;
|
||||
|
||||
void G1CollectionCandidateList::set(G1CollectionSetCandidateInfo* candidate_infos, uint num_infos) {
|
||||
assert(_candidates.is_empty(), "must be");
|
||||
G1CSetCandidateGroup::G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id) :
|
||||
_candidates(4, mtGCCardSet),
|
||||
_card_set_mm(config, card_set_freelist_pool),
|
||||
_card_set(config, &_card_set_mm),
|
||||
_reclaimable_bytes(size_t(0)),
|
||||
_gc_efficiency(0.0),
|
||||
_group_id(group_id)
|
||||
{ }
|
||||
|
||||
GrowableArrayFromArray<G1CollectionSetCandidateInfo> a(candidate_infos, (int)num_infos);
|
||||
_candidates.appendAll(&a);
|
||||
G1CSetCandidateGroup::G1CSetCandidateGroup() :
|
||||
G1CSetCandidateGroup(G1CollectedHeap::heap()->card_set_config(), G1CollectedHeap::heap()->card_set_freelist_pool(), _next_group_id++)
|
||||
{ }
|
||||
|
||||
void G1CSetCandidateGroup::add(G1HeapRegion* hr) {
|
||||
G1CollectionSetCandidateInfo c(hr);
|
||||
add(c);
|
||||
}
|
||||
|
||||
void G1CollectionCandidateList::append_unsorted(G1HeapRegion* r) {
|
||||
G1CollectionSetCandidateInfo c(r, r->calc_gc_efficiency());
|
||||
_candidates.append(c);
|
||||
void G1CSetCandidateGroup::add(G1CollectionSetCandidateInfo& hr_info) {
|
||||
G1HeapRegion* hr = hr_info._r;
|
||||
_candidates.append(hr_info);
|
||||
hr->install_cset_group(this);
|
||||
}
|
||||
|
||||
void G1CollectionCandidateList::sort_by_efficiency() {
|
||||
_candidates.sort(compare_gc_efficiency);
|
||||
}
|
||||
|
||||
void G1CollectionCandidateList::remove(G1CollectionCandidateRegionList* other) {
|
||||
guarantee((uint)_candidates.length() >= other->length(), "must be");
|
||||
|
||||
if (other->length() == 0) {
|
||||
// Nothing to remove or nothing in the original set.
|
||||
return;
|
||||
void G1CSetCandidateGroup::calculate_efficiency() {
|
||||
_reclaimable_bytes = 0;
|
||||
uint num_candidates = _candidates.length();
|
||||
for (uint i = 0; i < num_candidates; i++) {
|
||||
G1HeapRegion* hr = region_at(i);
|
||||
_reclaimable_bytes += hr->reclaimable_bytes();
|
||||
}
|
||||
_gc_efficiency = _reclaimable_bytes / predict_group_total_time_ms();
|
||||
}
|
||||
|
||||
// Create a list from scratch, copying over the elements from the candidate
|
||||
// list not in the other list. Finally deallocate and overwrite the old list.
|
||||
int new_length = _candidates.length() - other->length();
|
||||
GrowableArray<G1CollectionSetCandidateInfo> new_list(new_length, mtGC);
|
||||
size_t G1CSetCandidateGroup::liveness() const {
|
||||
size_t capacity = length() * G1HeapRegion::GrainBytes;
|
||||
|
||||
uint other_idx = 0;
|
||||
return (size_t) ceil(((capacity - _reclaimable_bytes) * 100.0) / capacity);
|
||||
}
|
||||
|
||||
for (uint candidate_idx = 0; candidate_idx < (uint)_candidates.length(); candidate_idx++) {
|
||||
if ((other_idx == other->length()) || _candidates.at(candidate_idx)._r != other->at(other_idx)) {
|
||||
new_list.append(_candidates.at(candidate_idx));
|
||||
} else {
|
||||
other_idx++;
|
||||
void G1CSetCandidateGroup::clear(bool uninstall_group_cardset) {
|
||||
if (uninstall_group_cardset) {
|
||||
for (G1CollectionSetCandidateInfo ci : _candidates) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
r->uninstall_cset_group();
|
||||
r->rem_set()->clear(true /* only_cardset */);
|
||||
}
|
||||
}
|
||||
_candidates.swap(&new_list);
|
||||
|
||||
verify();
|
||||
assert(_candidates.length() == new_length, "must be %u %u", _candidates.length(), new_length);
|
||||
}
|
||||
|
||||
void G1CollectionCandidateList::clear() {
|
||||
_card_set.clear();
|
||||
_candidates.clear();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void G1CollectionCandidateList::verify() {
|
||||
G1CollectionSetCandidateInfo* prev = nullptr;
|
||||
double G1CSetCandidateGroup::predict_group_total_time_ms() const {
|
||||
G1Policy* p = G1CollectedHeap::heap()->policy();
|
||||
|
||||
for (uint i = 0; i < (uint)_candidates.length(); i++) {
|
||||
G1CollectionSetCandidateInfo& ci = _candidates.at(i);
|
||||
assert(prev == nullptr || prev->_gc_efficiency >= ci._gc_efficiency,
|
||||
"Stored gc efficiency must be descending from region %u to %u",
|
||||
prev->_r->hrm_index(), ci._r->hrm_index());
|
||||
prev = &ci;
|
||||
assert(ci._r->rem_set()->is_tracked(), "remset for region %u must be tracked", ci._r->hrm_index());
|
||||
double predicted_copy_time_ms = 0.0;
|
||||
double predict_code_root_scan_time_ms = 0.0;
|
||||
size_t predict_bytes_to_copy = 0.0;
|
||||
|
||||
for (G1CollectionSetCandidateInfo ci : _candidates) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
assert(r->rem_set()->cset_group() == this, "Must be!");
|
||||
|
||||
predict_bytes_to_copy += p->predict_bytes_to_copy(r);
|
||||
predicted_copy_time_ms += p->predict_region_copy_time_ms(r, false /* for_young_only_phase */);
|
||||
predict_code_root_scan_time_ms += p->predict_region_code_root_scan_time(r, false /* for_young_only_phase */);
|
||||
}
|
||||
|
||||
size_t card_rs_length = _card_set.occupied();
|
||||
|
||||
double merge_scan_time_ms = p->predict_merge_scan_time(card_rs_length);
|
||||
double non_young_other_time_ms = p->predict_non_young_other_time_ms(length());
|
||||
|
||||
log_trace(gc, ergo, cset) ("Prediction for group with %u regions, card_rs_length %zu, merge_scan_time %.2fms, code_root_scan_time_ms %.2fms, evac_time_ms %.2fms, other_time %.2fms, bytes_to_cop %zu",
|
||||
length(),
|
||||
card_rs_length,
|
||||
merge_scan_time_ms,
|
||||
predict_code_root_scan_time_ms,
|
||||
predicted_copy_time_ms,
|
||||
non_young_other_time_ms,
|
||||
predict_bytes_to_copy);
|
||||
|
||||
return merge_scan_time_ms +
|
||||
predict_code_root_scan_time_ms +
|
||||
predicted_copy_time_ms +
|
||||
non_young_other_time_ms;
|
||||
}
|
||||
#endif
|
||||
|
||||
int G1CollectionCandidateList::compare_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) {
|
||||
assert(ci1->_r != nullptr && ci2->_r != nullptr, "Should not be!");
|
||||
|
||||
double gc_eff1 = ci1->_gc_efficiency;
|
||||
double gc_eff2 = ci2->_gc_efficiency;
|
||||
int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2) {
|
||||
double gc_eff1 = (*gr1)->gc_efficiency();
|
||||
double gc_eff2 = (*gr2)->gc_efficiency();
|
||||
|
||||
if (gc_eff1 > gc_eff2) {
|
||||
return -1;
|
||||
@ -108,7 +130,7 @@ int G1CollectionCandidateList::compare_gc_efficiency(G1CollectionSetCandidateInf
|
||||
}
|
||||
}
|
||||
|
||||
int G1CollectionCandidateList::compare_reclaimble_bytes(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) {
|
||||
int G1CSetCandidateGroup::compare_reclaimble_bytes(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) {
|
||||
// Make sure that null entries are moved to the end.
|
||||
if (ci1->_r == nullptr) {
|
||||
if (ci2->_r == nullptr) {
|
||||
@ -132,47 +154,95 @@ int G1CollectionCandidateList::compare_reclaimble_bytes(G1CollectionSetCandidate
|
||||
}
|
||||
}
|
||||
|
||||
G1CollectionCandidateRegionList::G1CollectionCandidateRegionList() : _regions(2, mtGC) { }
|
||||
G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { }
|
||||
|
||||
void G1CollectionCandidateRegionList::append(G1HeapRegion* r) {
|
||||
assert(!_regions.contains(r), "must be");
|
||||
_regions.append(r);
|
||||
void G1CSetCandidateGroupList::append(G1CSetCandidateGroup* group) {
|
||||
assert(group->length() > 0, "Do not add empty groups");
|
||||
assert(!_groups.contains(group), "Already added to list");
|
||||
_groups.append(group);
|
||||
_num_regions += group->length();
|
||||
}
|
||||
|
||||
void G1CollectionCandidateRegionList::remove_prefix(G1CollectionCandidateRegionList* other) {
|
||||
#ifdef ASSERT
|
||||
// Check that the given list is a prefix of this list.
|
||||
int i = 0;
|
||||
for (G1HeapRegion* r : *other) {
|
||||
assert(_regions.at(i) == r, "must be in order, but element %d is not", i);
|
||||
i++;
|
||||
G1CSetCandidateGroup* G1CSetCandidateGroupList::at(uint index) {
|
||||
return _groups.at(index);
|
||||
}
|
||||
|
||||
void G1CSetCandidateGroupList::clear(bool uninstall_group_cardset) {
|
||||
for (G1CSetCandidateGroup* gr : _groups) {
|
||||
gr->clear(uninstall_group_cardset);
|
||||
delete gr;
|
||||
}
|
||||
#endif
|
||||
_groups.clear();
|
||||
_num_regions = 0;
|
||||
}
|
||||
|
||||
void G1CSetCandidateGroupList::prepare_for_scan() {
|
||||
for (G1CSetCandidateGroup* gr : _groups) {
|
||||
gr->card_set()->reset_table_scanner_for_groups();
|
||||
}
|
||||
}
|
||||
|
||||
void G1CSetCandidateGroupList::remove_selected(uint count, uint num_regions) {
|
||||
_groups.remove_till(count);
|
||||
_num_regions -= num_regions;
|
||||
}
|
||||
|
||||
void G1CSetCandidateGroupList::remove(G1CSetCandidateGroupList* other) {
|
||||
guarantee((uint)_groups.length() >= other->length(), "Other should be a subset of this list");
|
||||
|
||||
if (other->length() == 0) {
|
||||
// Nothing to remove or nothing in the original set.
|
||||
return;
|
||||
}
|
||||
_regions.remove_till(other->length());
|
||||
|
||||
// Create a list from scratch, copying over the elements from the candidate
|
||||
// list not in the other list. Finally deallocate and overwrite the old list.
|
||||
int new_length = _groups.length() - other->length();
|
||||
_num_regions = num_regions() - other->num_regions();
|
||||
GrowableArray<G1CSetCandidateGroup*> new_list(new_length, mtGC);
|
||||
|
||||
uint other_idx = 0;
|
||||
for (G1CSetCandidateGroup* gr : _groups) {
|
||||
if (other_idx == other->length() || gr != other->at(other_idx)) {
|
||||
new_list.append(gr);
|
||||
} else {
|
||||
other_idx++;
|
||||
}
|
||||
}
|
||||
_groups.swap(&new_list);
|
||||
|
||||
verify();
|
||||
assert(_groups.length() == new_length, "Must be");
|
||||
}
|
||||
|
||||
G1HeapRegion* G1CollectionCandidateRegionList::at(uint index) {
|
||||
return _regions.at(index);
|
||||
void G1CSetCandidateGroupList::sort_by_efficiency() {
|
||||
_groups.sort(G1CSetCandidateGroup::compare_gc_efficiency);
|
||||
}
|
||||
|
||||
void G1CollectionCandidateRegionList::clear() {
|
||||
_regions.clear();
|
||||
#ifndef PRODUCT
|
||||
void G1CSetCandidateGroupList::verify() const {
|
||||
G1CSetCandidateGroup* prev = nullptr;
|
||||
|
||||
for (G1CSetCandidateGroup* gr : _groups) {
|
||||
assert(prev == nullptr || prev->gc_efficiency() >= gr->gc_efficiency(),
|
||||
"Stored gc efficiency must be descending");
|
||||
prev = gr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
G1CollectionSetCandidates::G1CollectionSetCandidates() :
|
||||
_marking_regions(),
|
||||
_retained_regions(),
|
||||
_contains_map(nullptr),
|
||||
_from_marking_groups(),
|
||||
_retained_groups(),
|
||||
_max_regions(0),
|
||||
_last_marking_candidates_length(0)
|
||||
{ }
|
||||
|
||||
G1CollectionSetCandidates::~G1CollectionSetCandidates() {
|
||||
FREE_C_HEAP_ARRAY(CandidateOrigin, _contains_map);
|
||||
_from_marking_groups.clear();
|
||||
_retained_groups.clear();
|
||||
}
|
||||
|
||||
bool G1CollectionSetCandidates::is_from_marking(G1HeapRegion* r) const {
|
||||
@ -188,8 +258,8 @@ void G1CollectionSetCandidates::initialize(uint max_regions) {
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::clear() {
|
||||
_marking_regions.clear();
|
||||
_retained_regions.clear();
|
||||
_retained_groups.clear(true /* uninstall_group_cardset */);
|
||||
_from_marking_groups.clear(true /* uninstall_group_cardset */);
|
||||
for (uint i = 0; i < _max_regions; i++) {
|
||||
_contains_map[i] = CandidateOrigin::Invalid;
|
||||
}
|
||||
@ -197,28 +267,62 @@ void G1CollectionSetCandidates::clear() {
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::sort_marking_by_efficiency() {
|
||||
G1CollectionCandidateListIterator iter = _marking_regions.begin();
|
||||
for (; iter != _marking_regions.end(); ++iter) {
|
||||
G1HeapRegion* hr = (*iter)->_r;
|
||||
(*iter)->_gc_efficiency = hr->calc_gc_efficiency();
|
||||
for (G1CSetCandidateGroup* gr : _from_marking_groups) {
|
||||
gr->calculate_efficiency();
|
||||
}
|
||||
_marking_regions.sort_by_efficiency();
|
||||
_from_marking_groups.sort_by_efficiency();
|
||||
|
||||
_marking_regions.verify();
|
||||
_from_marking_groups.verify();
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos,
|
||||
uint num_infos) {
|
||||
assert(_marking_regions.length() == 0, "must be empty before adding new ones");
|
||||
if (num_infos == 0) {
|
||||
log_debug(gc, ergo, cset) ("No regions selected from marking.");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_from_marking_groups.length() == 0, "must be empty at the start of a cycle");
|
||||
verify();
|
||||
|
||||
_marking_regions.set(candidate_infos, num_infos);
|
||||
G1Policy* p = G1CollectedHeap::heap()->policy();
|
||||
// During each Mixed GC, we must collect at least G1Policy::calc_min_old_cset_length regions to meet
|
||||
// the G1MixedGCCountTarget. For the first collection in a Mixed GC cycle, we can add all regions
|
||||
// required to meet this threshold to the same remset group. We are certain these will be collected in
|
||||
// the same MixedGC.
|
||||
uint group_limit = p->calc_min_old_cset_length(num_infos);
|
||||
|
||||
uint num_added_to_group = 0;
|
||||
|
||||
G1CSetCandidateGroup::reset_next_group_id();
|
||||
G1CSetCandidateGroup* current = nullptr;
|
||||
|
||||
current = new G1CSetCandidateGroup();
|
||||
|
||||
for (uint i = 0; i < num_infos; i++) {
|
||||
G1HeapRegion* r = candidate_infos[i]._r;
|
||||
assert(!contains(r), "must not contain region %u", r->hrm_index());
|
||||
_contains_map[r->hrm_index()] = CandidateOrigin::Marking;
|
||||
|
||||
if (num_added_to_group == group_limit) {
|
||||
if (group_limit != G1OldCSetGroupSize) {
|
||||
group_limit = G1OldCSetGroupSize;
|
||||
}
|
||||
|
||||
_from_marking_groups.append(current);
|
||||
|
||||
current = new G1CSetCandidateGroup();
|
||||
num_added_to_group = 0;
|
||||
}
|
||||
current->add(candidate_infos[i]);
|
||||
num_added_to_group++;
|
||||
}
|
||||
|
||||
_from_marking_groups.append(current);
|
||||
|
||||
assert(_from_marking_groups.num_regions() == num_infos, "Must be!");
|
||||
|
||||
log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_infos);
|
||||
_last_marking_candidates_length = num_infos;
|
||||
|
||||
verify();
|
||||
@ -227,46 +331,53 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi
|
||||
void G1CollectionSetCandidates::sort_by_efficiency() {
|
||||
// From marking regions must always be sorted so no reason to actually sort
|
||||
// them.
|
||||
_marking_regions.verify();
|
||||
_retained_regions.sort_by_efficiency();
|
||||
_retained_regions.verify();
|
||||
_from_marking_groups.verify();
|
||||
_retained_groups.sort_by_efficiency();
|
||||
_retained_groups.verify();
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) {
|
||||
assert(!contains(r), "must not contain region %u", r->hrm_index());
|
||||
_contains_map[r->hrm_index()] = CandidateOrigin::Retained;
|
||||
_retained_regions.append_unsorted(r);
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::remove(G1CollectionCandidateRegionList* other) {
|
||||
void G1CollectionSetCandidates::remove(G1CSetCandidateGroupList* other) {
|
||||
// During removal, we exploit the fact that elements in the marking_regions,
|
||||
// retained_regions and other list are sorted by gc_efficiency. Furthermore,
|
||||
// all regions in the passed other list are in one of the two other lists.
|
||||
//
|
||||
// Split original list into elements for the marking list and elements from the
|
||||
// retained list.
|
||||
G1CollectionCandidateRegionList other_marking_regions;
|
||||
G1CollectionCandidateRegionList other_retained_regions;
|
||||
G1CSetCandidateGroupList other_marking_groups;
|
||||
G1CSetCandidateGroupList other_retained_groups;
|
||||
|
||||
for (G1HeapRegion* r : *other) {
|
||||
for (G1CSetCandidateGroup* group : *other) {
|
||||
assert(group->length() > 0, "Should not have empty groups");
|
||||
// Regions in the same group have the same source (i.e from_marking or retained).
|
||||
G1HeapRegion* r = group->region_at(0);
|
||||
if (is_from_marking(r)) {
|
||||
other_marking_regions.append(r);
|
||||
other_marking_groups.append(group);
|
||||
} else {
|
||||
other_retained_regions.append(r);
|
||||
other_retained_groups.append(group);
|
||||
}
|
||||
}
|
||||
|
||||
_marking_regions.remove(&other_marking_regions);
|
||||
_retained_regions.remove(&other_retained_regions);
|
||||
_from_marking_groups.remove(&other_marking_groups);
|
||||
_retained_groups.remove(&other_retained_groups);
|
||||
|
||||
for (G1HeapRegion* r : *other) {
|
||||
assert(contains(r), "must contain region %u", r->hrm_index());
|
||||
other->iterate([&] (G1HeapRegion* r) {
|
||||
assert(contains(r), "Must contain region %u", r->hrm_index());
|
||||
_contains_map[r->hrm_index()] = CandidateOrigin::Invalid;
|
||||
}
|
||||
});
|
||||
|
||||
verify();
|
||||
}
|
||||
|
||||
void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) {
|
||||
assert(!contains(r), "Must not already contain region %u", r->hrm_index());
|
||||
_contains_map[r->hrm_index()] = CandidateOrigin::Retained;
|
||||
|
||||
G1CSetCandidateGroup* gr = new G1CSetCandidateGroup();
|
||||
gr->add(r);
|
||||
|
||||
_retained_groups.append(gr);
|
||||
}
|
||||
|
||||
bool G1CollectionSetCandidates::is_empty() const {
|
||||
return length() == 0;
|
||||
}
|
||||
@ -276,29 +387,31 @@ bool G1CollectionSetCandidates::has_more_marking_candidates() const {
|
||||
}
|
||||
|
||||
uint G1CollectionSetCandidates::marking_regions_length() const {
|
||||
return _marking_regions.length();
|
||||
return _from_marking_groups.num_regions();
|
||||
}
|
||||
|
||||
uint G1CollectionSetCandidates::retained_regions_length() const {
|
||||
return _retained_regions.length();
|
||||
return _retained_groups.num_regions();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void G1CollectionSetCandidates::verify_helper(G1CollectionCandidateList* list, uint& from_marking, CandidateOrigin* verify_map) {
|
||||
void G1CollectionSetCandidates::verify_helper(G1CSetCandidateGroupList* list, uint& from_marking, CandidateOrigin* verify_map) {
|
||||
list->verify();
|
||||
|
||||
for (uint i = 0; i < (uint)list->length(); i++) {
|
||||
G1HeapRegion* r = list->at(i)._r;
|
||||
for (G1CSetCandidateGroup* gr : *list) {
|
||||
for (G1CollectionSetCandidateInfo ci : *gr) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
|
||||
if (is_from_marking(r)) {
|
||||
from_marking++;
|
||||
if (is_from_marking(r)) {
|
||||
from_marking++;
|
||||
}
|
||||
const uint hrm_index = r->hrm_index();
|
||||
assert(_contains_map[hrm_index] == CandidateOrigin::Marking || _contains_map[hrm_index] == CandidateOrigin::Retained,
|
||||
"must be %u is %u", hrm_index, (uint)_contains_map[hrm_index]);
|
||||
assert(verify_map[hrm_index] == CandidateOrigin::Invalid, "already added");
|
||||
|
||||
verify_map[hrm_index] = CandidateOrigin::Verify;
|
||||
}
|
||||
const uint hrm_index = r->hrm_index();
|
||||
assert(_contains_map[hrm_index] == CandidateOrigin::Marking || _contains_map[hrm_index] == CandidateOrigin::Retained,
|
||||
"must be %u is %u", hrm_index, (uint)_contains_map[hrm_index]);
|
||||
assert(verify_map[hrm_index] == CandidateOrigin::Invalid, "already added");
|
||||
|
||||
verify_map[hrm_index] = CandidateOrigin::Verify;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,11 +423,11 @@ void G1CollectionSetCandidates::verify() {
|
||||
verify_map[i] = CandidateOrigin::Invalid;
|
||||
}
|
||||
|
||||
verify_helper(&_marking_regions, from_marking, verify_map);
|
||||
verify_helper(&_from_marking_groups, from_marking, verify_map);
|
||||
assert(from_marking == marking_regions_length(), "must be");
|
||||
|
||||
uint from_marking_retained = 0;
|
||||
verify_helper(&_retained_regions, from_marking_retained, verify_map);
|
||||
verify_helper(&_retained_groups, from_marking_retained, verify_map);
|
||||
assert(from_marking_retained == 0, "must be");
|
||||
|
||||
assert(length() >= marking_regions_length(), "must be");
|
||||
|
||||
@ -25,53 +25,24 @@
|
||||
#ifndef SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP
|
||||
#define SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP
|
||||
|
||||
#include "gc/g1/g1CardSetMemory.hpp"
|
||||
#include "gc/g1/g1CollectionSetCandidates.hpp"
|
||||
#include "gc/shared/gc_globals.hpp"
|
||||
#include "gc/shared/workerThread.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/bitMap.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
class G1CollectionCandidateList;
|
||||
class G1CollectionSetCandidates;
|
||||
class G1CSetCandidateGroupList;
|
||||
class G1HeapRegion;
|
||||
class G1HeapRegionClosure;
|
||||
|
||||
using G1CollectionCandidateRegionListIterator = GrowableArrayIterator<G1HeapRegion*>;
|
||||
|
||||
// A set of G1HeapRegion*, a thin wrapper around GrowableArray.
|
||||
class G1CollectionCandidateRegionList {
|
||||
GrowableArray<G1HeapRegion*> _regions;
|
||||
|
||||
public:
|
||||
G1CollectionCandidateRegionList();
|
||||
|
||||
// Append a G1HeapRegion to the end of this list. The region must not be in the list
|
||||
// already.
|
||||
void append(G1HeapRegion* r);
|
||||
// Remove the given list of G1HeapRegion* from this list. The given list must be a prefix
|
||||
// of this list.
|
||||
void remove_prefix(G1CollectionCandidateRegionList* list);
|
||||
|
||||
// Empty contents of the list.
|
||||
void clear();
|
||||
|
||||
G1HeapRegion* at(uint index);
|
||||
|
||||
uint length() const { return (uint)_regions.length(); }
|
||||
|
||||
G1CollectionCandidateRegionListIterator begin() const { return _regions.begin(); }
|
||||
G1CollectionCandidateRegionListIterator end() const { return _regions.end(); }
|
||||
};
|
||||
|
||||
struct G1CollectionSetCandidateInfo {
|
||||
G1HeapRegion* _r;
|
||||
double _gc_efficiency;
|
||||
uint _num_unreclaimed; // Number of GCs this region has been found unreclaimable.
|
||||
|
||||
G1CollectionSetCandidateInfo() : G1CollectionSetCandidateInfo(nullptr, 0.0) { }
|
||||
G1CollectionSetCandidateInfo(G1HeapRegion* r, double gc_efficiency) : _r(r), _gc_efficiency(gc_efficiency), _num_unreclaimed(0) { }
|
||||
G1CollectionSetCandidateInfo() : G1CollectionSetCandidateInfo(nullptr) { }
|
||||
G1CollectionSetCandidateInfo(G1HeapRegion* r) : _r(r), _num_unreclaimed(0) { }
|
||||
|
||||
bool update_num_unreclaimed() {
|
||||
++_num_unreclaimed;
|
||||
@ -79,100 +50,159 @@ struct G1CollectionSetCandidateInfo {
|
||||
}
|
||||
};
|
||||
|
||||
class G1CollectionCandidateListIterator : public StackObj {
|
||||
G1CollectionCandidateList* _which;
|
||||
uint _position;
|
||||
|
||||
public:
|
||||
G1CollectionCandidateListIterator(G1CollectionCandidateList* which, uint position);
|
||||
|
||||
G1CollectionCandidateListIterator& operator++();
|
||||
G1CollectionSetCandidateInfo* operator*();
|
||||
|
||||
bool operator==(const G1CollectionCandidateListIterator& rhs);
|
||||
bool operator!=(const G1CollectionCandidateListIterator& rhs);
|
||||
};
|
||||
|
||||
// List of collection set candidates (regions with their efficiency) ordered by
|
||||
// decreasing gc efficiency.
|
||||
class G1CollectionCandidateList : public CHeapObj<mtGC> {
|
||||
friend class G1CollectionCandidateListIterator;
|
||||
using G1CSetCandidateGroupIterator = GrowableArrayIterator<G1CollectionSetCandidateInfo>;
|
||||
|
||||
// G1CSetCandidateGroup groups candidate regions that will be selected for evacuation at the same time.
|
||||
// Grouping occurs both for candidates from marking or regions retained during evacuation failure, but a group
|
||||
// can not contain regions from both types of regions.
|
||||
//
|
||||
// Humongous objects are excluded from the candidate groups because regions associated with these
|
||||
// objects are never selected for evacuation.
|
||||
//
|
||||
// All regions in the group share a G1CardSet instance, which tracks remembered set entries for the
|
||||
// regions in the group. We do not have track to cross-region references for regions that are in the
|
||||
// same group saving memory.
|
||||
class G1CSetCandidateGroup : public CHeapObj<mtGCCardSet>{
|
||||
GrowableArray<G1CollectionSetCandidateInfo> _candidates;
|
||||
|
||||
G1CardSetMemoryManager _card_set_mm;
|
||||
|
||||
// The set of cards in the Java heap
|
||||
G1CardSet _card_set;
|
||||
|
||||
size_t _reclaimable_bytes;
|
||||
double _gc_efficiency;
|
||||
|
||||
// The _group_id is primarily used when printing out per-region liveness information,
|
||||
// making it easier to associate regions with their assigned G1CSetCandidateGroup, if any.
|
||||
// Note:
|
||||
// * _group_id 0 is reserved for special G1CSetCandidateGroups that hold only a single region,
|
||||
// such as G1CSetCandidateGroups for retained regions.
|
||||
// * _group_id 1 is reserved for the G1CSetCandidateGroup that contains all young regions.
|
||||
const uint _group_id;
|
||||
static uint _next_group_id;
|
||||
public:
|
||||
G1CollectionCandidateList();
|
||||
G1CSetCandidateGroup();
|
||||
G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id);
|
||||
~G1CSetCandidateGroup() {
|
||||
assert(length() == 0, "post condition!");
|
||||
}
|
||||
|
||||
// Put the given set of candidates into this list, preserving the efficiency ordering.
|
||||
void set(G1CollectionSetCandidateInfo* candidate_infos, uint num_infos);
|
||||
// Add the given G1HeapRegion to this list at the end, (potentially) making the list unsorted.
|
||||
void append_unsorted(G1HeapRegion* r);
|
||||
// Restore sorting order by decreasing gc efficiency, using the existing efficiency
|
||||
// values.
|
||||
void sort_by_efficiency();
|
||||
// Removes any heap regions stored in this list also in the other list. The other
|
||||
// list may only contain regions in this list, sorted by gc efficiency. It need
|
||||
// not be a prefix of this list. Returns the number of regions removed.
|
||||
// E.g. if this list is "A B G H", the other list may be "A G H", but not "F" (not in
|
||||
// this list) or "A H G" (wrong order).
|
||||
void remove(G1CollectionCandidateRegionList* other);
|
||||
|
||||
void clear();
|
||||
|
||||
G1CollectionSetCandidateInfo& at(uint position) { return _candidates.at(position); }
|
||||
void add(G1HeapRegion* hr);
|
||||
void add(G1CollectionSetCandidateInfo& hr_info);
|
||||
|
||||
uint length() const { return (uint)_candidates.length(); }
|
||||
|
||||
void verify() PRODUCT_RETURN;
|
||||
G1CardSet* card_set() { return &_card_set; }
|
||||
const G1CardSet* card_set() const { return &_card_set; }
|
||||
|
||||
uint group_id() const { return _group_id; }
|
||||
|
||||
void calculate_efficiency();
|
||||
|
||||
size_t liveness() const;
|
||||
// Comparison function to order regions in decreasing GC efficiency order. This
|
||||
// will cause regions with a lot of live objects and large remembered sets to end
|
||||
// up at the end of the list.
|
||||
static int compare_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2);
|
||||
static int compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2);
|
||||
|
||||
static int compare_reclaimble_bytes(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2);
|
||||
|
||||
G1CollectionCandidateListIterator begin() {
|
||||
return G1CollectionCandidateListIterator(this, 0);
|
||||
double gc_efficiency() const { return _gc_efficiency; }
|
||||
|
||||
G1HeapRegion* region_at(uint i) const { return _candidates.at(i)._r; }
|
||||
|
||||
G1CollectionSetCandidateInfo* at(uint i) { return &_candidates.at(i); }
|
||||
|
||||
double predict_group_total_time_ms() const;
|
||||
|
||||
G1MonotonicArenaMemoryStats card_set_memory_stats() const {
|
||||
return _card_set_mm.memory_stats();
|
||||
}
|
||||
|
||||
G1CollectionCandidateListIterator end() {
|
||||
return G1CollectionCandidateListIterator(this, length());
|
||||
void clear(bool uninstall_group_cardset = false);
|
||||
|
||||
G1CSetCandidateGroupIterator begin() const {
|
||||
return _candidates.begin();
|
||||
}
|
||||
|
||||
G1CSetCandidateGroupIterator end() const {
|
||||
return _candidates.end();
|
||||
}
|
||||
|
||||
static void reset_next_group_id() {
|
||||
_next_group_id = 2;
|
||||
}
|
||||
};
|
||||
|
||||
// Iterator for G1CollectionSetCandidates. There are no guarantees on the order
|
||||
// of the regions returned.
|
||||
class G1CollectionSetCandidatesIterator : public StackObj {
|
||||
G1CollectionSetCandidates* _which;
|
||||
uint _position;
|
||||
using G1CSetCandidateGroupListIterator = GrowableArrayIterator<G1CSetCandidateGroup*>;
|
||||
|
||||
public:
|
||||
G1CollectionSetCandidatesIterator(G1CollectionSetCandidates* which, uint position);
|
||||
class G1CSetCandidateGroupList {
|
||||
GrowableArray<G1CSetCandidateGroup*> _groups;
|
||||
volatile uint _num_regions;
|
||||
|
||||
G1CollectionSetCandidatesIterator& operator++();
|
||||
G1HeapRegion* operator*();
|
||||
public:
|
||||
G1CSetCandidateGroupList();
|
||||
void append(G1CSetCandidateGroup* group);
|
||||
|
||||
bool operator==(const G1CollectionSetCandidatesIterator& rhs);
|
||||
bool operator!=(const G1CollectionSetCandidatesIterator& rhs);
|
||||
// Delete all groups from the list. The cardset cleanup for regions within the
|
||||
// groups could have been done elsewhere (e.g. when adding groups to the
|
||||
// collection set or to retained regions). The uninstall_group_cardset is set to
|
||||
// true if cleanup needs to happen as we clear the groups from the list.
|
||||
void clear(bool uninstall_group_cardset = false);
|
||||
|
||||
G1CSetCandidateGroup* at(uint index);
|
||||
|
||||
uint length() const { return (uint)_groups.length(); }
|
||||
|
||||
uint num_regions() const { return _num_regions; }
|
||||
|
||||
void remove_selected(uint count, uint num_regions);
|
||||
|
||||
// Removes any candidate groups stored in this list and also in the other list. The other
|
||||
// list may only contain candidate groups in this list, sorted by gc efficiency. It need
|
||||
// not be a prefix of this list.
|
||||
// E.g. if this list is "A B G H", the other list may be "A G H", but not "F" (not in
|
||||
// this list) or "A H G" (wrong order).
|
||||
void remove(G1CSetCandidateGroupList* other);
|
||||
|
||||
void prepare_for_scan();
|
||||
|
||||
void sort_by_efficiency();
|
||||
|
||||
GrowableArray<G1CSetCandidateGroup*>* groups() {
|
||||
return &_groups;
|
||||
}
|
||||
|
||||
void verify() const PRODUCT_RETURN;
|
||||
|
||||
G1CSetCandidateGroupListIterator begin() const {
|
||||
return _groups.begin();
|
||||
}
|
||||
|
||||
G1CSetCandidateGroupListIterator end() const {
|
||||
return _groups.end();
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void iterate(Func&& f) const;
|
||||
};
|
||||
|
||||
// Tracks all collection set candidates, i.e. regions that could/should be evacuated soon.
|
||||
// Tracks all collection set candidates, i.e. region groups that could/should be evacuated soon.
|
||||
//
|
||||
// These candidate regions are tracked in two list of regions, sorted by decreasing
|
||||
// These candidate groups are tracked in two list of region groups, sorted by decreasing
|
||||
// "gc efficiency".
|
||||
//
|
||||
// * marking_regions: the set of regions selected by concurrent marking to be
|
||||
// evacuated to keep overall heap occupancy stable.
|
||||
// They are guaranteed to be evacuated and cleared out during
|
||||
// the mixed phase.
|
||||
// * from_marking_groups: the set of region groups selected by concurrent marking to be
|
||||
// evacuated to keep overall heap occupancy stable.
|
||||
// They are guaranteed to be evacuated and cleared out during
|
||||
// the mixed phase.
|
||||
//
|
||||
// * retained_regions: set of regions selected for evacuation during evacuation
|
||||
// failure.
|
||||
// Any young collection will try to evacuate them.
|
||||
// * retained_groups: set of region groups selected for evacuation during evacuation
|
||||
// failure.
|
||||
// Any young collection will try to evacuate them.
|
||||
//
|
||||
class G1CollectionSetCandidates : public CHeapObj<mtGC> {
|
||||
friend class G1CollectionSetCandidatesIterator;
|
||||
|
||||
enum class CandidateOrigin : uint8_t {
|
||||
Invalid,
|
||||
@ -181,10 +211,12 @@ class G1CollectionSetCandidates : public CHeapObj<mtGC> {
|
||||
Verify // Special value for verification.
|
||||
};
|
||||
|
||||
G1CollectionCandidateList _marking_regions; // Set of regions selected by concurrent marking.
|
||||
G1CollectionCandidateList _retained_regions; // Set of regions selected from evacuation failed regions.
|
||||
|
||||
CandidateOrigin* _contains_map;
|
||||
G1CSetCandidateGroupList _from_marking_groups; // Set of regions selected by concurrent marking.
|
||||
// Set of regions retained due to evacuation failure. Groups added to this list
|
||||
// should contain only one region each, making it easier to evacuate retained regions
|
||||
// in any young collection.
|
||||
G1CSetCandidateGroupList _retained_groups;
|
||||
uint _max_regions;
|
||||
|
||||
// The number of regions from the last merge of candidates from the marking.
|
||||
@ -196,8 +228,8 @@ public:
|
||||
G1CollectionSetCandidates();
|
||||
~G1CollectionSetCandidates();
|
||||
|
||||
G1CollectionCandidateList& marking_regions() { return _marking_regions; }
|
||||
G1CollectionCandidateList& retained_regions() { return _retained_regions; }
|
||||
G1CSetCandidateGroupList& from_marking_groups() { return _from_marking_groups; }
|
||||
G1CSetCandidateGroupList& retained_groups() { return _retained_groups; }
|
||||
|
||||
void initialize(uint max_regions);
|
||||
|
||||
@ -219,9 +251,9 @@ public:
|
||||
// Add the given region to the set of retained regions without regards to the
|
||||
// gc efficiency sorting. The retained regions must be re-sorted manually later.
|
||||
void add_retained_region_unsorted(G1HeapRegion* r);
|
||||
// Remove the given regions from the candidates. All given regions must be part
|
||||
// Remove the given groups from the candidates. All given regions must be part
|
||||
// of the candidates.
|
||||
void remove(G1CollectionCandidateRegionList* other);
|
||||
void remove(G1CSetCandidateGroupList* other);
|
||||
|
||||
bool contains(const G1HeapRegion* r) const;
|
||||
|
||||
@ -234,21 +266,15 @@ public:
|
||||
uint retained_regions_length() const;
|
||||
|
||||
private:
|
||||
void verify_helper(G1CollectionCandidateList* list, uint& from_marking, CandidateOrigin* verify_map) PRODUCT_RETURN;
|
||||
void verify_helper(G1CSetCandidateGroupList* list, uint& from_marking, CandidateOrigin* verify_map) PRODUCT_RETURN;
|
||||
|
||||
public:
|
||||
void verify() PRODUCT_RETURN;
|
||||
|
||||
uint length() const { return marking_regions_length() + retained_regions_length(); }
|
||||
|
||||
// Iteration
|
||||
G1CollectionSetCandidatesIterator begin() {
|
||||
return G1CollectionSetCandidatesIterator(this, 0);
|
||||
}
|
||||
|
||||
G1CollectionSetCandidatesIterator end() {
|
||||
return G1CollectionSetCandidatesIterator(this, length());
|
||||
}
|
||||
template<typename Func>
|
||||
void iterate_regions(Func&& f) const;
|
||||
};
|
||||
|
||||
#endif /* SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP */
|
||||
|
||||
@ -29,54 +29,21 @@
|
||||
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
inline G1CollectionCandidateListIterator::G1CollectionCandidateListIterator(G1CollectionCandidateList* which, uint position) :
|
||||
_which(which), _position(position) { }
|
||||
|
||||
inline G1CollectionCandidateListIterator& G1CollectionCandidateListIterator::operator++() {
|
||||
assert(_position < _which->length(), "must be");
|
||||
_position++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline G1CollectionSetCandidateInfo* G1CollectionCandidateListIterator::operator*() {
|
||||
return &_which->_candidates.at(_position);
|
||||
}
|
||||
|
||||
inline bool G1CollectionCandidateListIterator::operator==(const G1CollectionCandidateListIterator& rhs) {
|
||||
assert(_which == rhs._which, "iterator belongs to different array");
|
||||
return _position == rhs._position;
|
||||
}
|
||||
|
||||
inline bool G1CollectionCandidateListIterator::operator!=(const G1CollectionCandidateListIterator& rhs) {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
inline G1CollectionSetCandidatesIterator::G1CollectionSetCandidatesIterator(G1CollectionSetCandidates* which, uint position) :
|
||||
_which(which), _position(position) {
|
||||
}
|
||||
|
||||
inline G1CollectionSetCandidatesIterator& G1CollectionSetCandidatesIterator::operator++() {
|
||||
assert(_position < _which->length(), "must not be at end already");
|
||||
_position++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline G1HeapRegion* G1CollectionSetCandidatesIterator::operator*() {
|
||||
uint length = _which->marking_regions_length();
|
||||
if (_position < length) {
|
||||
return _which->_marking_regions.at(_position)._r;
|
||||
} else {
|
||||
return _which->_retained_regions.at(_position - length)._r;
|
||||
template<typename Func>
|
||||
void G1CSetCandidateGroupList::iterate(Func&& f) const {
|
||||
for (G1CSetCandidateGroup* group : _groups) {
|
||||
for (G1CollectionSetCandidateInfo ci : *group) {
|
||||
G1HeapRegion* r = ci._r;
|
||||
f(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool G1CollectionSetCandidatesIterator::operator==(const G1CollectionSetCandidatesIterator& rhs) {
|
||||
assert(_which == rhs._which, "iterator belongs to different array");
|
||||
return _position == rhs._position;
|
||||
}
|
||||
template<typename Func>
|
||||
void G1CollectionSetCandidates::iterate_regions(Func&& f) const {
|
||||
_from_marking_groups.iterate(f);
|
||||
|
||||
inline bool G1CollectionSetCandidatesIterator::operator!=(const G1CollectionSetCandidatesIterator& rhs) {
|
||||
return !(*this == rhs);
|
||||
_retained_groups.iterate(f);
|
||||
}
|
||||
|
||||
#endif /* SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_INLINE_HPP */
|
||||
|
||||
@ -93,7 +93,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
|
||||
void set(uint idx, G1HeapRegion* hr) {
|
||||
assert(idx < _max_size, "Index %u out of bounds %u", idx, _max_size);
|
||||
assert(_data[idx]._r == nullptr, "Value must not have been set.");
|
||||
_data[idx] = CandidateInfo(hr, 0.0);
|
||||
_data[idx] = CandidateInfo(hr);
|
||||
}
|
||||
|
||||
void sort_by_reclaimable_bytes() {
|
||||
@ -103,7 +103,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask {
|
||||
for (uint i = _cur_claim_idx; i < _max_size; i++) {
|
||||
assert(_data[i]._r == nullptr, "must be");
|
||||
}
|
||||
qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)G1CollectionCandidateList::compare_reclaimble_bytes);
|
||||
qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)G1CSetCandidateGroup::compare_reclaimble_bytes);
|
||||
for (uint i = _cur_claim_idx; i < _max_size; i++) {
|
||||
assert(_data[i]._r == nullptr, "must be");
|
||||
}
|
||||
|
||||
@ -2980,6 +2980,11 @@ G1CMTask::G1CMTask(uint worker_id,
|
||||
#define G1PPRL_DOUBLE_FORMAT "%14.1f"
|
||||
#define G1PPRL_GCEFF_FORMAT " %14s"
|
||||
#define G1PPRL_GCEFF_H_FORMAT " %14s"
|
||||
#define G1PPRL_GID_H_FORMAT " %9s"
|
||||
#define G1PPRL_GID_FORMAT " " UINT32_FORMAT_W(9)
|
||||
#define G1PPRL_LEN_FORMAT " " UINT32_FORMAT_W(14)
|
||||
#define G1PPRL_LEN_H_FORMAT " %14s"
|
||||
#define G1PPRL_GID_GCEFF_FORMAT " %14.1f"
|
||||
|
||||
// For summary info
|
||||
#define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT
|
||||
@ -2992,7 +2997,6 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p
|
||||
_total_capacity_bytes(0),
|
||||
_total_live_bytes(0),
|
||||
_total_remset_bytes(0),
|
||||
_young_cardset_bytes_per_region(0),
|
||||
_total_code_roots_bytes(0)
|
||||
{
|
||||
if (!log_is_enabled(Trace, gc, liveness)) {
|
||||
@ -3003,13 +3007,6 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p
|
||||
MemRegion reserved = g1h->reserved();
|
||||
double now = os::elapsedTime();
|
||||
|
||||
uint num_young_regions = g1h->young_regions_count();
|
||||
size_t young_cardset_bytes = g1h->young_regions_cardset()->mem_size();
|
||||
|
||||
if (num_young_regions > 0) {
|
||||
_young_cardset_bytes_per_region = young_cardset_bytes / num_young_regions;
|
||||
}
|
||||
|
||||
// Print the header of the output.
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP"
|
||||
@ -3023,25 +3020,24 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_GCEFF_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_STATE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_GID_H_FORMAT,
|
||||
"type", "address-range",
|
||||
"used", "live", "gc-eff",
|
||||
"remset", "state", "code-roots");
|
||||
"used", "live",
|
||||
"state", "code-roots",
|
||||
"group-id");
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_H_FORMAT
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_GCEFF_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_STATE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_GID_H_FORMAT,
|
||||
"", "",
|
||||
"(bytes)", "(bytes)", "(bytes/ms)",
|
||||
"(bytes)", "", "(bytes)");
|
||||
"(bytes)", "(bytes)",
|
||||
"", "(bytes)", "");
|
||||
}
|
||||
|
||||
bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) {
|
||||
@ -3055,14 +3051,13 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) {
|
||||
size_t capacity_bytes = r->capacity();
|
||||
size_t used_bytes = r->used();
|
||||
size_t live_bytes = r->live_bytes();
|
||||
double gc_eff = r->calc_gc_efficiency();
|
||||
size_t remset_bytes = r->rem_set()->mem_size();
|
||||
size_t code_roots_bytes = r->rem_set()->code_roots_mem_size();
|
||||
const char* remset_type = r->rem_set()->get_short_state_str();
|
||||
FormatBuffer<16> gc_efficiency("");
|
||||
uint cset_groud_gid = 0;
|
||||
|
||||
if (r->is_young()) {
|
||||
remset_bytes = _young_cardset_bytes_per_region;
|
||||
if (r->rem_set()->is_added_to_cset_group()) {
|
||||
cset_groud_gid = r->rem_set()->cset_group_id();
|
||||
}
|
||||
|
||||
_total_used_bytes += used_bytes;
|
||||
@ -3071,25 +3066,19 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) {
|
||||
_total_remset_bytes += remset_bytes;
|
||||
_total_code_roots_bytes += code_roots_bytes;
|
||||
|
||||
if(gc_eff < 0) {
|
||||
gc_efficiency.append("-");
|
||||
} else {
|
||||
gc_efficiency.append(G1PPRL_DOUBLE_FORMAT, gc_eff);
|
||||
}
|
||||
|
||||
// Print a line for this particular region.
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_FORMAT
|
||||
G1PPRL_ADDR_BASE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_GCEFF_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_STATE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT,
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_GID_FORMAT,
|
||||
type, p2i(bottom), p2i(end),
|
||||
used_bytes, live_bytes, gc_efficiency.buffer(),
|
||||
remset_bytes, remset_type, code_roots_bytes);
|
||||
used_bytes, live_bytes,
|
||||
remset_type, code_roots_bytes,
|
||||
cset_groud_gid);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -3103,6 +3092,9 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
|
||||
_total_remset_bytes += g1h->card_set_freelist_pool()->mem_size();
|
||||
// add static memory usages to remembered set sizes
|
||||
_total_remset_bytes += G1HeapRegionRemSet::static_mem_size();
|
||||
|
||||
do_cset_groups();
|
||||
|
||||
// Print the footer of the output.
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
@ -3120,3 +3112,77 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
|
||||
bytes_to_mb(_total_remset_bytes),
|
||||
bytes_to_mb(_total_code_roots_bytes));
|
||||
}
|
||||
|
||||
void G1PrintRegionLivenessInfoClosure::do_cset_groups() {
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" Collectionset Candidate Groups");
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX " Types: Y=Young Regions, M=From Marking Regions, R=Retained Regions");
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_GID_H_FORMAT
|
||||
G1PPRL_LEN_H_FORMAT
|
||||
G1PPRL_GCEFF_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_TYPE_H_FORMAT,
|
||||
"groud-id", "num-regions",
|
||||
"gc-eff", "liveness",
|
||||
"remset", "type");
|
||||
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_GID_H_FORMAT
|
||||
G1PPRL_LEN_H_FORMAT
|
||||
G1PPRL_GCEFF_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_TYPE_H_FORMAT,
|
||||
"", "",
|
||||
"(bytes/ms)", "%",
|
||||
"(bytes)", "");
|
||||
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
G1CSetCandidateGroup* young_only_cset_group =g1h->young_regions_cset_group();
|
||||
|
||||
_total_remset_bytes += young_only_cset_group->card_set()->mem_size();
|
||||
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_GID_FORMAT
|
||||
G1PPRL_LEN_FORMAT
|
||||
G1PPRL_GCEFF_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_TYPE_H_FORMAT,
|
||||
young_only_cset_group->group_id(), young_only_cset_group->length(),
|
||||
"-",
|
||||
size_t(0), young_only_cset_group->card_set()->mem_size(),
|
||||
"Y");
|
||||
|
||||
for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) {
|
||||
_total_remset_bytes += group->card_set()->mem_size();
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_GID_FORMAT
|
||||
G1PPRL_LEN_FORMAT
|
||||
G1PPRL_GID_GCEFF_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_TYPE_H_FORMAT,
|
||||
group->group_id(), group->length(),
|
||||
group->gc_efficiency(),
|
||||
group->liveness(), group->card_set()->mem_size(),
|
||||
"M");
|
||||
}
|
||||
|
||||
for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->retained_groups()) {
|
||||
_total_remset_bytes += group->card_set()->mem_size();
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_GID_FORMAT
|
||||
G1PPRL_LEN_FORMAT
|
||||
G1PPRL_GID_GCEFF_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_TYPE_H_FORMAT,
|
||||
group->group_id(), group->length(),
|
||||
group->gc_efficiency(),
|
||||
group->liveness(), group->card_set()->mem_size(),
|
||||
"R");
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,8 +973,6 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure {
|
||||
// Accumulator for the remembered set size
|
||||
size_t _total_remset_bytes;
|
||||
|
||||
size_t _young_cardset_bytes_per_region;
|
||||
|
||||
// Accumulator for code roots memory size
|
||||
size_t _total_code_roots_bytes;
|
||||
|
||||
@ -982,6 +980,8 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure {
|
||||
return (double) val / (double) M;
|
||||
}
|
||||
|
||||
void do_cset_groups();
|
||||
|
||||
public:
|
||||
// The header and footer are printed in the constructor and
|
||||
// destructor respectively.
|
||||
|
||||
@ -246,7 +246,7 @@ void G1FullCollector::complete_collection() {
|
||||
|
||||
_heap->resize_all_tlabs();
|
||||
|
||||
_heap->young_regions_cardset()->clear();
|
||||
_heap->young_regions_cset_group()->clear();
|
||||
|
||||
_heap->policy()->record_full_collection_end();
|
||||
_heap->gc_epilogue(true);
|
||||
|
||||
@ -36,7 +36,10 @@ void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1
|
||||
}
|
||||
|
||||
bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(G1HeapRegion* hr) {
|
||||
hr->uninstall_group_cardset();
|
||||
if (!hr->is_humongous()) {
|
||||
hr->uninstall_cset_group();
|
||||
}
|
||||
|
||||
|
||||
uint const region_idx = hr->hrm_index();
|
||||
if (!_collector->is_compaction_target(region_idx)) {
|
||||
|
||||
@ -118,7 +118,7 @@ void G1HeapRegion::hr_clear(bool clear_space) {
|
||||
clear_young_index_in_cset();
|
||||
clear_index_in_opt_cset();
|
||||
uninstall_surv_rate_group();
|
||||
uninstall_group_cardset();
|
||||
uninstall_cset_group();
|
||||
set_free();
|
||||
reset_pre_dummy_top();
|
||||
|
||||
@ -137,18 +137,6 @@ void G1HeapRegion::clear_cardtable() {
|
||||
ct->clear_MemRegion(MemRegion(bottom(), end()));
|
||||
}
|
||||
|
||||
double G1HeapRegion::calc_gc_efficiency() {
|
||||
// GC efficiency is the ratio of how much space would be
|
||||
// reclaimed over how long we predict it would take to reclaim it.
|
||||
G1Policy* policy = G1CollectedHeap::heap()->policy();
|
||||
|
||||
// Retrieve a prediction of the elapsed time for this region for
|
||||
// a mixed gc because the region will only be evacuated during a
|
||||
// mixed gc.
|
||||
double region_elapsed_time_ms = policy->predict_region_total_time_ms(this, false /* for_young_only_phase */);
|
||||
return (double)reclaimable_bytes() / region_elapsed_time_ms;
|
||||
}
|
||||
|
||||
void G1HeapRegion::set_free() {
|
||||
if (!is_free()) {
|
||||
report_region_type_change(G1HeapRegionTraceType::Free);
|
||||
@ -191,6 +179,9 @@ void G1HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||
_type.set_starts_humongous();
|
||||
_humongous_start_region = this;
|
||||
|
||||
G1CSetCandidateGroup* cset_group = new G1CSetCandidateGroup();
|
||||
cset_group->add(this);
|
||||
|
||||
_bot->update_for_block(bottom(), obj_top);
|
||||
if (fill_size > 0) {
|
||||
_bot->update_for_block(obj_top, obj_top + fill_size);
|
||||
@ -211,12 +202,19 @@ void G1HeapRegion::clear_humongous() {
|
||||
assert(is_humongous(), "pre-condition");
|
||||
|
||||
assert(capacity() == G1HeapRegion::GrainBytes, "pre-condition");
|
||||
if (is_starts_humongous()) {
|
||||
G1CSetCandidateGroup* cset_group = _rem_set->cset_group();
|
||||
assert(cset_group != nullptr, "pre-condition %u missing cardset", hrm_index());
|
||||
uninstall_cset_group();
|
||||
cset_group->clear();
|
||||
delete cset_group;
|
||||
}
|
||||
_humongous_start_region = nullptr;
|
||||
}
|
||||
|
||||
void G1HeapRegion::prepare_remset_for_scan() {
|
||||
if (is_young()) {
|
||||
uninstall_group_cardset();
|
||||
uninstall_cset_group();
|
||||
}
|
||||
_rem_set->reset_table_scanner();
|
||||
}
|
||||
@ -250,7 +248,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index,
|
||||
assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()),
|
||||
"invalid space boundaries");
|
||||
|
||||
_rem_set = new G1HeapRegionRemSet(this, config);
|
||||
_rem_set = new G1HeapRegionRemSet(this);
|
||||
initialize();
|
||||
}
|
||||
|
||||
@ -600,7 +598,9 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure {
|
||||
}
|
||||
|
||||
bool failed() const {
|
||||
if (_from != _to && !_from->is_young() && _to->rem_set()->is_complete()) {
|
||||
if (_from != _to && !_from->is_young() &&
|
||||
_to->rem_set()->is_complete() &&
|
||||
_from->rem_set()->cset_group() != _to->rem_set()->cset_group()) {
|
||||
const CardValue dirty = G1CardTable::dirty_card_val();
|
||||
return !(_to->rem_set()->contains_reference(this->_p) ||
|
||||
(this->_containing_obj->is_objArray() ?
|
||||
|
||||
@ -40,6 +40,7 @@ class G1CardSet;
|
||||
class G1CardSetConfiguration;
|
||||
class G1CollectedHeap;
|
||||
class G1CMBitMap;
|
||||
class G1CSetCandidateGroup;
|
||||
class G1Predictions;
|
||||
class G1HeapRegion;
|
||||
class G1HeapRegionRemSet;
|
||||
@ -488,8 +489,6 @@ public:
|
||||
void set_index_in_opt_cset(uint index) { _index_in_opt_cset = index; }
|
||||
void clear_index_in_opt_cset() { _index_in_opt_cset = InvalidCSetIndex; }
|
||||
|
||||
double calc_gc_efficiency();
|
||||
|
||||
uint young_index_in_cset() const { return _young_index_in_cset; }
|
||||
void clear_young_index_in_cset() { _young_index_in_cset = 0; }
|
||||
void set_young_index_in_cset(uint index) {
|
||||
@ -509,8 +508,8 @@ public:
|
||||
void install_surv_rate_group(G1SurvRateGroup* surv_rate_group);
|
||||
void uninstall_surv_rate_group();
|
||||
|
||||
void install_group_cardset(G1CardSet* group_cardset);
|
||||
void uninstall_group_cardset();
|
||||
void install_cset_group(G1CSetCandidateGroup* cset_group);
|
||||
void uninstall_cset_group();
|
||||
|
||||
void record_surv_words_in_group(size_t words_survived);
|
||||
|
||||
|
||||
@ -511,12 +511,12 @@ inline void G1HeapRegion::add_pinned_object_count(size_t value) {
|
||||
Atomic::add(&_pinned_object_count, value, memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void G1HeapRegion::install_group_cardset(G1CardSet* group_cardset) {
|
||||
_rem_set->install_group_cardset(group_cardset);
|
||||
inline void G1HeapRegion::install_cset_group(G1CSetCandidateGroup* cset_group) {
|
||||
_rem_set->install_cset_group(cset_group);
|
||||
}
|
||||
|
||||
inline void G1HeapRegion::uninstall_group_cardset() {
|
||||
_rem_set->uninstall_group_cardset();
|
||||
inline void G1HeapRegion::uninstall_cset_group() {
|
||||
_rem_set->uninstall_cset_group();
|
||||
}
|
||||
|
||||
#endif // SHARE_GC_G1_G1HEAPREGION_INLINE_HPP
|
||||
|
||||
@ -52,48 +52,52 @@ void G1HeapRegionRemSet::initialize(MemRegion reserved) {
|
||||
_heap_base_address = reserved.start();
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::uninstall_group_cardset() {
|
||||
if (_saved_card_set != nullptr) {
|
||||
_card_set = _saved_card_set;
|
||||
_saved_card_set = nullptr;
|
||||
}
|
||||
void G1HeapRegionRemSet::uninstall_cset_group() {
|
||||
_cset_group = nullptr;
|
||||
}
|
||||
|
||||
G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr,
|
||||
G1CardSetConfiguration* config) :
|
||||
G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr) :
|
||||
_code_roots(),
|
||||
_card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()),
|
||||
_card_set(new G1CardSet(config, &_card_set_mm)),
|
||||
_saved_card_set(nullptr),
|
||||
_cset_group(nullptr),
|
||||
_hr(hr),
|
||||
_state(Untracked) { }
|
||||
|
||||
G1HeapRegionRemSet::~G1HeapRegionRemSet() {
|
||||
assert(!is_added_to_cset_group(), "Still assigned to a CSet group");
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::clear_fcc() {
|
||||
G1FromCardCache::clear(_hr->hrm_index());
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) {
|
||||
assert(_saved_card_set == nullptr, "pre-condition");
|
||||
if (!only_cardset) {
|
||||
_code_roots.clear();
|
||||
}
|
||||
clear_fcc();
|
||||
_card_set->clear();
|
||||
|
||||
if (is_added_to_cset_group()) {
|
||||
card_set()->clear();
|
||||
assert(card_set()->occupied() == 0, "Should be clear.");
|
||||
}
|
||||
|
||||
if (!keep_tracked) {
|
||||
set_state_untracked();
|
||||
} else {
|
||||
assert(is_tracked(), "must be");
|
||||
}
|
||||
assert(occupied() == 0, "Should be clear.");
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::reset_table_scanner() {
|
||||
_code_roots.reset_table_scanner();
|
||||
_card_set->reset_table_scanner();
|
||||
if (is_added_to_cset_group()) {
|
||||
card_set()->reset_table_scanner();
|
||||
}
|
||||
}
|
||||
|
||||
G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const {
|
||||
return _card_set_mm.memory_stats();
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
return cset_group()->card_set_memory_stats();
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::print_static_mem_size(outputStream* out) {
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "gc/g1/g1CardSet.hpp"
|
||||
#include "gc/g1/g1CardSetMemory.hpp"
|
||||
#include "gc/g1/g1CodeRootSet.hpp"
|
||||
#include "gc/g1/g1CollectionSetCandidates.hpp"
|
||||
#include "gc/g1/g1FromCardCache.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
@ -35,6 +36,7 @@
|
||||
#include "utilities/bitMap.hpp"
|
||||
|
||||
class G1CardSetMemoryManager;
|
||||
class G1CSetCandidateGroup;
|
||||
class outputStream;
|
||||
|
||||
class G1HeapRegionRemSet : public CHeapObj<mtGC> {
|
||||
@ -44,11 +46,8 @@ class G1HeapRegionRemSet : public CHeapObj<mtGC> {
|
||||
// the region that owns this RSet.
|
||||
G1CodeRootSet _code_roots;
|
||||
|
||||
G1CardSetMemoryManager _card_set_mm;
|
||||
|
||||
// The set of cards in the Java heap
|
||||
G1CardSet* _card_set;
|
||||
G1CardSet* _saved_card_set;
|
||||
// The collection set groups to which the region owning this RSet is assigned.
|
||||
G1CSetCandidateGroup* _cset_group;
|
||||
|
||||
G1HeapRegion* _hr;
|
||||
|
||||
@ -57,26 +56,48 @@ class G1HeapRegionRemSet : public CHeapObj<mtGC> {
|
||||
|
||||
void clear_fcc();
|
||||
|
||||
G1CardSet* card_set() {
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
return cset_group()->card_set();
|
||||
}
|
||||
|
||||
const G1CardSet* card_set() const {
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
return cset_group()->card_set();
|
||||
}
|
||||
|
||||
public:
|
||||
G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config);
|
||||
~G1HeapRegionRemSet() { delete _card_set; }
|
||||
G1HeapRegionRemSet(G1HeapRegion* hr);
|
||||
~G1HeapRegionRemSet();
|
||||
|
||||
bool cardset_is_empty() const {
|
||||
return _card_set->is_empty();
|
||||
return !is_added_to_cset_group() || card_set()->is_empty();
|
||||
}
|
||||
|
||||
void install_group_cardset(G1CardSet* group_cardset) {
|
||||
assert(group_cardset != nullptr, "pre-condition");
|
||||
assert(_saved_card_set == nullptr, "pre-condition");
|
||||
void install_cset_group(G1CSetCandidateGroup* cset_group) {
|
||||
assert(cset_group != nullptr, "pre-condition");
|
||||
assert(_cset_group == nullptr, "pre-condition");
|
||||
|
||||
_saved_card_set = _card_set;
|
||||
_card_set = group_cardset;
|
||||
_cset_group = cset_group;
|
||||
}
|
||||
|
||||
void uninstall_group_cardset();
|
||||
void uninstall_cset_group();
|
||||
|
||||
bool has_group_cardset() {
|
||||
return _saved_card_set != nullptr;
|
||||
bool is_added_to_cset_group() const {
|
||||
return _cset_group != nullptr;
|
||||
}
|
||||
|
||||
G1CSetCandidateGroup* cset_group() {
|
||||
return _cset_group;
|
||||
}
|
||||
|
||||
const G1CSetCandidateGroup* cset_group() const {
|
||||
return _cset_group;
|
||||
}
|
||||
|
||||
uint cset_group_id() const {
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
return cset_group()->group_id();
|
||||
}
|
||||
|
||||
bool is_empty() const {
|
||||
@ -84,7 +105,7 @@ public:
|
||||
}
|
||||
|
||||
bool occupancy_less_or_equal_than(size_t occ) const {
|
||||
return (code_roots_list_length() == 0) && _card_set->occupancy_less_or_equal_to(occ);
|
||||
return (code_roots_list_length() == 0) && card_set()->occupancy_less_or_equal_to(occ);
|
||||
}
|
||||
|
||||
// Iterate the card based remembered set for merging them into the card table.
|
||||
@ -97,10 +118,10 @@ public:
|
||||
inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl);
|
||||
|
||||
size_t occupied() {
|
||||
return _card_set->occupied();
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
return card_set()->occupied();
|
||||
}
|
||||
|
||||
G1CardSet* card_set() { return _card_set; }
|
||||
|
||||
static void initialize(MemRegion reserved);
|
||||
|
||||
@ -146,13 +167,7 @@ public:
|
||||
// The actual # of bytes this hr_remset takes up. Also includes the code
|
||||
// root set.
|
||||
size_t mem_size() {
|
||||
return _card_set->mem_size()
|
||||
+ (sizeof(G1HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet.
|
||||
+ code_roots_mem_size();
|
||||
}
|
||||
|
||||
size_t unused_mem_size() {
|
||||
return _card_set->unused_mem_size();
|
||||
return sizeof(G1HeapRegionRemSet) + code_roots_mem_size();
|
||||
}
|
||||
|
||||
// Returns the memory occupancy of all static data structures associated
|
||||
|
||||
@ -108,7 +108,7 @@ public:
|
||||
|
||||
template <class CardOrRangeVisitor>
|
||||
inline void G1HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) {
|
||||
iterate_for_merge(_card_set, cl);
|
||||
iterate_for_merge(card_set(), cl);
|
||||
}
|
||||
|
||||
template <class CardOrRangeVisitor>
|
||||
@ -125,6 +125,8 @@ uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const {
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) {
|
||||
assert(is_added_to_cset_group(), "pre-condition");
|
||||
|
||||
assert(_state != Untracked, "must be");
|
||||
|
||||
uint cur_idx = _hr->hrm_index();
|
||||
@ -137,15 +139,15 @@ void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) {
|
||||
return;
|
||||
}
|
||||
|
||||
_card_set->add_card(to_card(from));
|
||||
card_set()->add_card(to_card(from));
|
||||
}
|
||||
|
||||
bool G1HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) {
|
||||
return _card_set->contains_card(to_card(from));
|
||||
return card_set()->contains_card(to_card(from));
|
||||
}
|
||||
|
||||
void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) {
|
||||
_card_set->print_info(st, to_card(from));
|
||||
card_set()->print_info(st, to_card(from));
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP
|
||||
|
||||
@ -150,7 +150,11 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) {
|
||||
|
||||
assert(to_rem_set != nullptr, "Need per-region 'into' remsets.");
|
||||
if (to_rem_set->is_tracked()) {
|
||||
to_rem_set->add_reference(p, _worker_id);
|
||||
G1HeapRegion* from = _g1h->heap_region_containing(p);
|
||||
|
||||
if (from->rem_set()->cset_group() != to_rem_set->cset_group()) {
|
||||
to_rem_set->add_reference(p, _worker_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +272,11 @@ template <class T> void G1RebuildRemSetClosure::do_oop_work(T* p) {
|
||||
G1HeapRegion* to = _g1h->heap_region_containing(obj);
|
||||
G1HeapRegionRemSet* rem_set = to->rem_set();
|
||||
if (rem_set->is_tracked()) {
|
||||
rem_set->add_reference(p, _worker_id);
|
||||
G1HeapRegion* from = _g1h->heap_region_containing(p);
|
||||
|
||||
if (from->rem_set()->cset_group() != rem_set->cset_group()) {
|
||||
rem_set->add_reference(p, _worker_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
|
||||
_old_gen_is_full(false),
|
||||
_partial_array_splitter(g1h->partial_array_state_manager(), num_workers),
|
||||
_string_dedup_requests(),
|
||||
_max_num_optional_regions(collection_set->optional_region_length()),
|
||||
_max_num_optional_regions(collection_set->num_optional_regions()),
|
||||
_numa(g1h->numa()),
|
||||
_obj_alloc_stat(nullptr),
|
||||
ALLOCATION_FAILURE_INJECTOR_ONLY(_allocation_failure_inject_counter(0) COMMA)
|
||||
|
||||
@ -488,16 +488,15 @@ uint G1Policy::calculate_desired_eden_length_before_mixed(double base_time_ms,
|
||||
uint min_eden_length,
|
||||
uint max_eden_length) const {
|
||||
uint min_marking_candidates = MIN2(calc_min_old_cset_length(candidates()->last_marking_candidates_length()),
|
||||
candidates()->marking_regions_length());
|
||||
candidates()->from_marking_groups().num_regions());
|
||||
double predicted_region_evac_time_ms = base_time_ms;
|
||||
for (G1CollectionSetCandidateInfo* ci : candidates()->marking_regions()) {
|
||||
// We optimistically assume that any of these marking candidate regions will
|
||||
// not be pinned, so just consider them as normal.
|
||||
if (min_marking_candidates == 0) {
|
||||
uint selected_candidates = 0;
|
||||
for (G1CSetCandidateGroup* gr : candidates()->from_marking_groups()) {
|
||||
if (selected_candidates >= min_marking_candidates) {
|
||||
break;
|
||||
}
|
||||
predicted_region_evac_time_ms += predict_region_total_time_ms(ci->_r, false /* for_young_only_phase */);
|
||||
min_marking_candidates--;
|
||||
predicted_region_evac_time_ms += gr->predict_group_total_time_ms();
|
||||
selected_candidates += gr->length();
|
||||
}
|
||||
|
||||
return calculate_desired_eden_length_before_young_only(predicted_region_evac_time_ms,
|
||||
@ -523,12 +522,13 @@ double G1Policy::predict_retained_regions_evac_time() const {
|
||||
|
||||
double result = 0.0;
|
||||
|
||||
G1CollectionCandidateList& list = candidates()->retained_regions();
|
||||
G1CSetCandidateGroupList* retained_groups = &candidates()->retained_groups();
|
||||
uint min_regions_left = MIN2(min_retained_old_cset_length(),
|
||||
list.length());
|
||||
retained_groups->num_regions());
|
||||
|
||||
for (G1CollectionSetCandidateInfo* ci : list) {
|
||||
G1HeapRegion* r = ci->_r;
|
||||
for (G1CSetCandidateGroup* group : *retained_groups) {
|
||||
assert(group->length() == 1, "We should only have one region in a retained group");
|
||||
G1HeapRegion* r = group->region_at(0); // We only have one region per group.
|
||||
// We optimistically assume that any of these marking candidate regions will
|
||||
// be reclaimable the next gc, so just consider them as normal.
|
||||
if (r->has_pinned_objects()) {
|
||||
@ -539,12 +539,12 @@ double G1Policy::predict_retained_regions_evac_time() const {
|
||||
break;
|
||||
}
|
||||
min_regions_left--;
|
||||
result += predict_region_total_time_ms(r, collector_state()->in_young_only_phase());
|
||||
result += group->predict_group_total_time_ms();
|
||||
num_regions++;
|
||||
}
|
||||
|
||||
log_trace(gc, ergo, heap)("Selected %u of %u retained candidates (pinned %u) taking %1.3fms additional time",
|
||||
num_regions, list.length(), num_pinned_regions, result);
|
||||
num_regions, retained_groups->num_regions(), num_pinned_regions, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1111,6 +1111,10 @@ double G1Policy::predict_young_region_other_time_ms(uint count) const {
|
||||
return _analytics->predict_young_other_time_ms(count);
|
||||
}
|
||||
|
||||
double G1Policy::predict_non_young_other_time_ms(uint count) const {
|
||||
return _analytics->predict_non_young_other_time_ms(count);
|
||||
}
|
||||
|
||||
double G1Policy::predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy) const {
|
||||
if (count == 0) {
|
||||
return 0.0;
|
||||
@ -1127,13 +1131,12 @@ double G1Policy::predict_region_copy_time_ms(G1HeapRegion* hr, bool for_young_on
|
||||
return _analytics->predict_object_copy_time_ms(bytes_to_copy, for_young_only_phase);
|
||||
}
|
||||
|
||||
double G1Policy::predict_region_merge_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const {
|
||||
size_t card_rs_length = hr->rem_set()->occupied();
|
||||
size_t scan_card_num = _analytics->predict_scan_card_num(card_rs_length, for_young_only_phase);
|
||||
double G1Policy::predict_merge_scan_time(size_t card_rs_length) const {
|
||||
size_t scan_card_num = _analytics->predict_scan_card_num(card_rs_length, false);
|
||||
|
||||
return
|
||||
_analytics->predict_card_merge_time_ms(card_rs_length, for_young_only_phase) +
|
||||
_analytics->predict_card_scan_time_ms(scan_card_num, for_young_only_phase);
|
||||
_analytics->predict_card_merge_time_ms(card_rs_length, false) +
|
||||
_analytics->predict_card_scan_time_ms(scan_card_num, false);
|
||||
}
|
||||
|
||||
double G1Policy::predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const {
|
||||
@ -1143,27 +1146,6 @@ double G1Policy::predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_y
|
||||
_analytics->predict_code_root_scan_time_ms(code_root_length, for_young_only_phase);
|
||||
}
|
||||
|
||||
double G1Policy::predict_region_non_copy_time_ms(G1HeapRegion* hr,
|
||||
bool for_young_only_phase) const {
|
||||
|
||||
double region_elapsed_time_ms = predict_region_merge_scan_time(hr, for_young_only_phase) +
|
||||
predict_region_code_root_scan_time(hr, for_young_only_phase);
|
||||
// The prediction of the "other" time for this region is based
|
||||
// upon the region type and NOT the GC type.
|
||||
if (hr->is_young()) {
|
||||
region_elapsed_time_ms += _analytics->predict_young_other_time_ms(1);
|
||||
} else {
|
||||
region_elapsed_time_ms += _analytics->predict_non_young_other_time_ms(1);
|
||||
}
|
||||
return region_elapsed_time_ms;
|
||||
}
|
||||
|
||||
double G1Policy::predict_region_total_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const {
|
||||
return
|
||||
predict_region_non_copy_time_ms(hr, for_young_only_phase) +
|
||||
predict_region_copy_time_ms(hr, for_young_only_phase);
|
||||
}
|
||||
|
||||
bool G1Policy::should_allocate_mutator_region() const {
|
||||
uint young_list_length = _g1h->young_regions_count();
|
||||
return young_list_length < young_list_target_length();
|
||||
@ -1339,11 +1321,6 @@ void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_se
|
||||
}
|
||||
|
||||
void G1Policy::abandon_collection_set_candidates() {
|
||||
// Clear remembered sets of remaining candidate regions and the actual candidate
|
||||
// set.
|
||||
for (G1HeapRegion* r : *candidates()) {
|
||||
r->rem_set()->clear(true /* only_cardset */);
|
||||
}
|
||||
_collection_set->abandon_all_candidates();
|
||||
}
|
||||
|
||||
|
||||
@ -46,10 +46,8 @@
|
||||
|
||||
class G1HeapRegion;
|
||||
class G1CollectionSet;
|
||||
class G1CollectionCandidateList;
|
||||
class G1CollectionSetCandidates;
|
||||
class G1CollectionSetChooser;
|
||||
class G1CollectionCandidateRegionList;
|
||||
class G1IHOPControl;
|
||||
class G1Analytics;
|
||||
class G1SurvivorRegions;
|
||||
@ -140,7 +138,6 @@ public:
|
||||
|
||||
double predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const;
|
||||
|
||||
private:
|
||||
// Base time contains handling remembered sets and constant other time of the
|
||||
// whole young gen, refinement buffers, and copying survivors.
|
||||
// Basically everything but copying eden regions.
|
||||
@ -148,24 +145,16 @@ private:
|
||||
|
||||
// Copy time for a region is copying live data.
|
||||
double predict_region_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const;
|
||||
// Merge-scan time for a region is handling card-based remembered sets of that region
|
||||
// (as a single unit).
|
||||
double predict_region_merge_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const;
|
||||
// Code root scan time prediction for the given region.
|
||||
double predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const;
|
||||
// Non-copy time for a region is handling remembered sets and other time.
|
||||
double predict_region_non_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const;
|
||||
|
||||
public:
|
||||
|
||||
double predict_merge_scan_time(size_t card_rs_length) const;
|
||||
// Predict other time for count young regions.
|
||||
double predict_young_region_other_time_ms(uint count) const;
|
||||
double predict_non_young_other_time_ms(uint count) const;
|
||||
// Predict copying live data time for count eden regions. Return the predict bytes if
|
||||
// bytes_to_copy is non-null.
|
||||
double predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy = nullptr) const;
|
||||
// Total time for a region is handling remembered sets (as a single unit), copying its live data
|
||||
// and other time.
|
||||
double predict_region_total_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const;
|
||||
|
||||
void cset_regions_freed() {
|
||||
bool update = should_update_surv_rate_group_predictors();
|
||||
@ -247,11 +236,11 @@ private:
|
||||
// Limit the given desired young length to available free regions.
|
||||
uint calculate_young_target_length(uint desired_young_length) const;
|
||||
|
||||
size_t predict_bytes_to_copy(G1HeapRegion* hr) const;
|
||||
double predict_survivor_regions_evac_time() const;
|
||||
double predict_retained_regions_evac_time() const;
|
||||
|
||||
public:
|
||||
size_t predict_bytes_to_copy(G1HeapRegion* hr) const;
|
||||
size_t pending_cards_at_gc_start() const { return _pending_cards_at_gc_start; }
|
||||
|
||||
// The minimum number of retained regions we will add to the CSet during a young GC.
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "gc/g1/g1CardTable.inline.hpp"
|
||||
#include "gc/g1/g1CardTableEntryClosure.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectionSet.inline.hpp"
|
||||
#include "gc/g1/g1ConcurrentRefine.hpp"
|
||||
#include "gc/g1/g1DirtyCardQueue.hpp"
|
||||
#include "gc/g1/g1FromCardCache.hpp"
|
||||
@ -1118,6 +1119,7 @@ class G1MergeHeapRootsTask : public WorkerTask {
|
||||
// This is needed to be able to use the bitmap for evacuation failure handling.
|
||||
class G1ClearBitmapClosure : public G1HeapRegionClosure {
|
||||
G1CollectedHeap* _g1h;
|
||||
G1RemSetScanState* _scan_state;
|
||||
|
||||
void assert_bitmap_clear(G1HeapRegion* hr, const G1CMBitMap* bitmap) {
|
||||
assert(bitmap->get_next_marked_addr(hr->bottom(), hr->end()) == hr->end(),
|
||||
@ -1142,7 +1144,10 @@ class G1MergeHeapRootsTask : public WorkerTask {
|
||||
}
|
||||
|
||||
public:
|
||||
G1ClearBitmapClosure(G1CollectedHeap* g1h) : _g1h(g1h) { }
|
||||
G1ClearBitmapClosure(G1CollectedHeap* g1h, G1RemSetScanState* scan_state) :
|
||||
_g1h(g1h),
|
||||
_scan_state(scan_state)
|
||||
{ }
|
||||
|
||||
bool do_heap_region(G1HeapRegion* hr) {
|
||||
assert(_g1h->is_in_cset(hr), "Should only be used iterating the collection set");
|
||||
@ -1156,26 +1161,11 @@ class G1MergeHeapRootsTask : public WorkerTask {
|
||||
assert_bitmap_clear(hr, _g1h->concurrent_mark()->mark_bitmap());
|
||||
}
|
||||
_g1h->concurrent_mark()->clear_statistics(hr);
|
||||
_scan_state->add_all_dirty_region(hr->hrm_index());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to allow two closure to be applied when
|
||||
// iterating through the collection set.
|
||||
class G1CombinedClosure : public G1HeapRegionClosure {
|
||||
G1HeapRegionClosure* _closure1;
|
||||
G1HeapRegionClosure* _closure2;
|
||||
public:
|
||||
G1CombinedClosure(G1HeapRegionClosure* cl1, G1HeapRegionClosure* cl2) :
|
||||
_closure1(cl1),
|
||||
_closure2(cl2) { }
|
||||
|
||||
bool do_heap_region(G1HeapRegion* hr) {
|
||||
return _closure1->do_heap_region(hr) ||
|
||||
_closure2->do_heap_region(hr);
|
||||
}
|
||||
};
|
||||
|
||||
// Visitor for the remembered sets of humongous candidate regions to merge their
|
||||
// remembered set into the card table.
|
||||
class G1FlushHumongousCandidateRemSets : public G1HeapRegionIndexClosure {
|
||||
@ -1394,14 +1384,15 @@ public:
|
||||
{
|
||||
// 2. collection set
|
||||
G1MergeCardSetClosure merge(_scan_state);
|
||||
G1ClearBitmapClosure clear(g1h);
|
||||
G1CombinedClosure combined(&merge, &clear);
|
||||
G1ClearBitmapClosure clear_bitmap(g1h, _scan_state);
|
||||
|
||||
if (_initial_evacuation) {
|
||||
G1HeapRegionRemSet::iterate_for_merge(g1h->young_regions_cardset(), merge);
|
||||
}
|
||||
|
||||
g1h->collection_set_iterate_increment_from(&combined, nullptr, worker_id);
|
||||
g1h->collection_set()->merge_cardsets_for_collection_groups(merge, worker_id, _num_workers);
|
||||
|
||||
g1h->collection_set_iterate_increment_from(&clear_bitmap, nullptr, worker_id);
|
||||
G1MergeCardSetStats stats = merge.stats();
|
||||
|
||||
for (uint i = 0; i < G1GCPhaseTimes::MergeRSContainersSentinel; i++) {
|
||||
@ -1475,6 +1466,16 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) {
|
||||
workers->run_task(&cl, num_workers);
|
||||
}
|
||||
|
||||
{
|
||||
size_t young_rs_length = g1h->young_regions_cardset()->occupied();
|
||||
// We only use young_rs_length statistics to estimate young regions length.
|
||||
g1h->policy()->record_card_rs_length(young_rs_length);
|
||||
|
||||
// Clear current young only collection set. Survivor regions will be added
|
||||
// to the set during evacuation.
|
||||
g1h->young_regions_cset_group()->clear();
|
||||
}
|
||||
|
||||
print_merge_heap_roots_stats();
|
||||
}
|
||||
|
||||
|
||||
@ -191,6 +191,12 @@ private:
|
||||
size_t _max_rs_mem_sz;
|
||||
G1HeapRegion* _max_rs_mem_sz_region;
|
||||
|
||||
size_t _max_code_root_mem_sz;
|
||||
G1HeapRegion* _max_code_root_mem_sz_region;
|
||||
|
||||
size_t _max_group_cardset_mem_sz;
|
||||
G1CSetCandidateGroup* _max_cardset_mem_sz_group;
|
||||
|
||||
size_t total_rs_unused_mem_sz() const { return _all.rs_unused_mem_size(); }
|
||||
size_t total_rs_mem_sz() const { return _all.rs_mem_size(); }
|
||||
size_t total_cards_occupied() const { return _all.cards_occupied(); }
|
||||
@ -198,8 +204,8 @@ private:
|
||||
size_t max_rs_mem_sz() const { return _max_rs_mem_sz; }
|
||||
G1HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; }
|
||||
|
||||
size_t _max_code_root_mem_sz;
|
||||
G1HeapRegion* _max_code_root_mem_sz_region;
|
||||
size_t max_group_cardset_mem_sz() const { return _max_group_cardset_mem_sz; }
|
||||
G1CSetCandidateGroup* max_cardset_mem_sz_group() const { return _max_cardset_mem_sz_group; }
|
||||
|
||||
size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); }
|
||||
size_t total_code_root_elems() const { return _all.code_root_elems(); }
|
||||
@ -211,28 +217,29 @@ public:
|
||||
HRRSStatsIter() : _young("Young"), _humongous("Humongous"),
|
||||
_free("Free"), _old("Old"), _all("All"),
|
||||
_max_rs_mem_sz(0), _max_rs_mem_sz_region(nullptr),
|
||||
_max_code_root_mem_sz(0), _max_code_root_mem_sz_region(nullptr)
|
||||
_max_code_root_mem_sz(0), _max_code_root_mem_sz_region(nullptr),
|
||||
_max_group_cardset_mem_sz(0), _max_cardset_mem_sz_group(nullptr)
|
||||
{}
|
||||
|
||||
bool do_heap_region(G1HeapRegion* r) {
|
||||
G1HeapRegionRemSet* hrrs = r->rem_set();
|
||||
size_t rs_mem_sz = 0;
|
||||
size_t rs_unused_mem_sz = 0;
|
||||
size_t occupied_cards = 0;
|
||||
|
||||
size_t occupied_cards = hrrs->occupied();
|
||||
// G1HeapRegionRemSet::mem_size() includes the
|
||||
// size of the code roots
|
||||
size_t rs_unused_mem_sz = hrrs->unused_mem_size();
|
||||
size_t rs_mem_sz = hrrs->mem_size();
|
||||
// Accumulate card set details for regions that are assigned to single region
|
||||
// groups. G1HeapRegionRemSet::mem_size() includes the size of the code roots
|
||||
if (hrrs->is_added_to_cset_group() && hrrs->cset_group()->length() == 1) {
|
||||
G1CardSet* card_set = hrrs->cset_group()->card_set();
|
||||
|
||||
if (r->is_young()) {
|
||||
uint num_young = G1CollectedHeap::heap()->young_regions_count();
|
||||
occupied_cards /= num_young;
|
||||
rs_unused_mem_sz /= num_young;
|
||||
rs_mem_sz /= num_young;
|
||||
}
|
||||
rs_mem_sz = hrrs->mem_size() + card_set->mem_size();
|
||||
rs_unused_mem_sz = card_set->unused_mem_size();
|
||||
occupied_cards = hrrs->occupied();
|
||||
|
||||
if (rs_mem_sz > _max_rs_mem_sz) {
|
||||
_max_rs_mem_sz = rs_mem_sz;
|
||||
_max_rs_mem_sz_region = r;
|
||||
if (rs_mem_sz > _max_rs_mem_sz) {
|
||||
_max_rs_mem_sz = rs_mem_sz;
|
||||
_max_rs_mem_sz_region = r;
|
||||
}
|
||||
}
|
||||
|
||||
size_t code_root_mem_sz = hrrs->code_roots_mem_size();
|
||||
@ -262,6 +269,47 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void do_cset_groups() {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
G1CSetCandidateGroup* young_only_cset_group = g1h->young_regions_cset_group();
|
||||
|
||||
// If the group has only a single region, then stats were accumulated
|
||||
// during region iteration.
|
||||
if (young_only_cset_group->length() > 1) {
|
||||
G1CardSet* young_only_card_set = young_only_cset_group->card_set();
|
||||
size_t rs_mem_sz = young_only_card_set->mem_size();
|
||||
size_t rs_unused_mem_sz = young_only_card_set->unused_mem_size();
|
||||
size_t occupied_cards = young_only_card_set->occupied();
|
||||
|
||||
_max_group_cardset_mem_sz = rs_mem_sz;
|
||||
_max_cardset_mem_sz_group = young_only_cset_group;
|
||||
|
||||
// Only update cardset details
|
||||
_young.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
|
||||
_all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
|
||||
}
|
||||
|
||||
|
||||
RegionTypeCounter* current = &_old;
|
||||
for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) {
|
||||
if (group->length() > 1) {
|
||||
G1CardSet* group_card_set = group->card_set();
|
||||
size_t rs_mem_sz = group_card_set->mem_size();
|
||||
size_t rs_unused_mem_sz = group_card_set->unused_mem_size();
|
||||
size_t occupied_cards = group_card_set->occupied();
|
||||
|
||||
if (rs_mem_sz > _max_group_cardset_mem_sz) {
|
||||
_max_group_cardset_mem_sz = rs_mem_sz;
|
||||
_max_cardset_mem_sz_group = group;
|
||||
}
|
||||
|
||||
// Only update cardset details
|
||||
_old.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
|
||||
_all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_summary_on(outputStream* out) {
|
||||
RegionTypeCounter* counters[] = { &_young, &_humongous, &_free, &_old, nullptr };
|
||||
|
||||
@ -281,13 +329,25 @@ public:
|
||||
(*current)->print_cards_occupied_info_on(out, total_cards_occupied());
|
||||
}
|
||||
|
||||
// Largest sized rem set region statistics
|
||||
G1HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set();
|
||||
out->print_cr(" Region with largest rem set = " HR_FORMAT ", "
|
||||
"size = %zu occupied = %zu",
|
||||
HR_FORMAT_PARAMS(max_rs_mem_sz_region()),
|
||||
rem_set->mem_size(),
|
||||
rem_set->occupied());
|
||||
// Largest sized single region rem set statistics
|
||||
if (max_rs_mem_sz_region() != nullptr) {
|
||||
G1HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set();
|
||||
out->print_cr(" Region with largest rem set = " HR_FORMAT ", "
|
||||
"size = %zu occupied = %zu",
|
||||
HR_FORMAT_PARAMS(max_rs_mem_sz_region()),
|
||||
rem_set->mem_size(),
|
||||
rem_set->occupied());
|
||||
}
|
||||
|
||||
if (max_cardset_mem_sz_group() != nullptr) {
|
||||
G1CSetCandidateGroup* cset_group = max_cardset_mem_sz_group();
|
||||
G1HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set();
|
||||
out->print_cr(" Collectionset Candidate Group with largest cardset = %u:(%u regions), "
|
||||
"size = %zu occupied = %zu",
|
||||
cset_group->group_id(), cset_group->length(),
|
||||
cset_group->card_set()->mem_size(),
|
||||
cset_group->card_set()->occupied());
|
||||
}
|
||||
|
||||
G1HeapRegionRemSet::print_static_mem_size(out);
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
@ -332,5 +392,6 @@ void G1RemSetSummary::print_on(outputStream* out, bool show_thread_times) {
|
||||
|
||||
HRRSStatsIter blk;
|
||||
G1CollectedHeap::heap()->heap_region_iterate(&blk);
|
||||
blk.do_cset_groups();
|
||||
blk.print_summary_on(out);
|
||||
}
|
||||
|
||||
@ -104,6 +104,17 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) {
|
||||
r->rem_set()->clear(true /* only_cardset */);
|
||||
});
|
||||
}
|
||||
|
||||
size_t remset_bytes = r->rem_set()->mem_size();
|
||||
size_t occupied = 0;
|
||||
// per region cardset details only valid if group contains a single region.
|
||||
if (r->rem_set()->is_added_to_cset_group() &&
|
||||
r->rem_set()->cset_group()->length() == 1 ) {
|
||||
G1CardSet *card_set = r->rem_set()->cset_group()->card_set();
|
||||
remset_bytes += card_set->mem_size();
|
||||
occupied = card_set->occupied();
|
||||
}
|
||||
|
||||
G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark();
|
||||
log_trace(gc, remset, tracking)("After rebuild region %u "
|
||||
"(tams " PTR_FORMAT " "
|
||||
@ -113,7 +124,7 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) {
|
||||
r->hrm_index(),
|
||||
p2i(cm->top_at_mark_start(r)),
|
||||
cm->live_bytes(r->hrm_index()),
|
||||
r->rem_set()->occupied(),
|
||||
r->rem_set()->mem_size());
|
||||
occupied,
|
||||
remset_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +272,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou
|
||||
|
||||
collection_set()->finalize_initial_collection_set(target_pause_time_ms, survivor_regions());
|
||||
evacuation_info->set_collection_set_regions(collection_set()->region_length() +
|
||||
collection_set()->optional_region_length());
|
||||
collection_set()->num_optional_regions());
|
||||
|
||||
concurrent_mark()->verify_no_collection_set_oops();
|
||||
|
||||
@ -515,7 +515,7 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info)
|
||||
Tickspan task_time = run_task_timed(&g1_prep_task);
|
||||
|
||||
G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats();
|
||||
sampled_card_set_stats.add(_g1h->young_regions_card_set_mm()->memory_stats());
|
||||
sampled_card_set_stats.add(_g1h->young_regions_card_set_memory_stats());
|
||||
_g1h->set_young_gen_card_set_stats(sampled_card_set_stats);
|
||||
|
||||
_g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates());
|
||||
@ -790,7 +790,7 @@ void G1YoungCollector::evacuate_next_optional_regions(G1ParScanThreadStateSet* p
|
||||
void G1YoungCollector::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) {
|
||||
const double collection_start_time_ms = phase_times()->cur_collection_start_sec() * 1000.0;
|
||||
|
||||
while (!evacuation_alloc_failed() && collection_set()->optional_region_length() > 0) {
|
||||
while (!evacuation_alloc_failed() && collection_set()->num_optional_regions() > 0) {
|
||||
|
||||
double time_used_ms = os::elapsedTime() * 1000.0 - collection_start_time_ms;
|
||||
double time_left_ms = MaxGCPauseMillis - time_used_ms;
|
||||
@ -798,7 +798,7 @@ void G1YoungCollector::evacuate_optional_collection_set(G1ParScanThreadStateSet*
|
||||
if (time_left_ms < 0 ||
|
||||
!collection_set()->finalize_optional_for_evacuation(time_left_ms * policy()->optional_evacuation_fraction())) {
|
||||
log_trace(gc, ergo, cset)("Skipping evacuation of %u optional regions, no more regions can be evacuated in %.3fms",
|
||||
collection_set()->optional_region_length(), time_left_ms);
|
||||
collection_set()->num_optional_regions(), time_left_ms);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -989,9 +989,9 @@ void G1YoungCollector::enqueue_candidates_as_root_regions() {
|
||||
assert(collector_state()->in_concurrent_start_gc(), "must be");
|
||||
|
||||
G1CollectionSetCandidates* candidates = collection_set()->candidates();
|
||||
for (G1HeapRegion* r : *candidates) {
|
||||
candidates->iterate_regions([&] (G1HeapRegion* r) {
|
||||
_g1h->concurrent_mark()->add_root_region(r);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void G1YoungCollector::post_evacuate_collection_set(G1EvacInfo* evacuation_info,
|
||||
@ -1111,7 +1111,7 @@ void G1YoungCollector::collect() {
|
||||
collection_set(),
|
||||
&_evac_failure_regions);
|
||||
|
||||
bool may_do_optional_evacuation = collection_set()->optional_region_length() != 0;
|
||||
bool may_do_optional_evacuation = collection_set()->num_optional_regions() != 0;
|
||||
// Actually do the work...
|
||||
evacuate_initial_collection_set(&per_thread_states, may_do_optional_evacuation);
|
||||
|
||||
|
||||
@ -106,8 +106,12 @@ public:
|
||||
|
||||
G1MonotonicArenaMemoryStats _total;
|
||||
G1CollectionSetCandidates* candidates = g1h->collection_set()->candidates();
|
||||
for (G1HeapRegion* r : *candidates) {
|
||||
_total.add(r->rem_set()->card_set_memory_stats());
|
||||
for (G1CSetCandidateGroup* gr : candidates->from_marking_groups()) {
|
||||
_total.add(gr->card_set_memory_stats());
|
||||
}
|
||||
|
||||
for (G1CSetCandidateGroup* gr : candidates->retained_groups()) {
|
||||
_total.add(gr->card_set_memory_stats());
|
||||
}
|
||||
g1h->set_collection_set_candidates_stats(_total);
|
||||
}
|
||||
@ -617,7 +621,6 @@ class FreeCSetStats {
|
||||
size_t _bytes_allocated_in_old_since_last_gc; // Size of young regions turned into old
|
||||
size_t _failure_used_words; // Live size in failed regions
|
||||
size_t _failure_waste_words; // Wasted size in failed regions
|
||||
size_t _card_rs_length; // (Card Set) Remembered set size
|
||||
uint _regions_freed; // Number of regions freed
|
||||
|
||||
public:
|
||||
@ -627,7 +630,6 @@ public:
|
||||
_bytes_allocated_in_old_since_last_gc(0),
|
||||
_failure_used_words(0),
|
||||
_failure_waste_words(0),
|
||||
_card_rs_length(0),
|
||||
_regions_freed(0) { }
|
||||
|
||||
void merge_stats(FreeCSetStats* other) {
|
||||
@ -637,7 +639,6 @@ public:
|
||||
_bytes_allocated_in_old_since_last_gc += other->_bytes_allocated_in_old_since_last_gc;
|
||||
_failure_used_words += other->_failure_used_words;
|
||||
_failure_waste_words += other->_failure_waste_words;
|
||||
_card_rs_length += other->_card_rs_length;
|
||||
_regions_freed += other->_regions_freed;
|
||||
}
|
||||
|
||||
@ -652,10 +653,6 @@ public:
|
||||
G1Policy *policy = g1h->policy();
|
||||
policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc);
|
||||
|
||||
// Add the cards from the group cardsets.
|
||||
_card_rs_length += g1h->young_regions_cardset()->occupied();
|
||||
|
||||
policy->record_card_rs_length(_card_rs_length);
|
||||
policy->cset_regions_freed();
|
||||
}
|
||||
|
||||
@ -681,10 +678,6 @@ public:
|
||||
_before_used_bytes += used;
|
||||
_regions_freed += 1;
|
||||
}
|
||||
|
||||
void account_card_rs_length(G1HeapRegion* r) {
|
||||
_card_rs_length += r->rem_set()->occupied();
|
||||
}
|
||||
};
|
||||
|
||||
// Closure applied to all regions in the collection set.
|
||||
@ -806,8 +799,6 @@ public:
|
||||
|
||||
|
||||
if (r->is_young()) {
|
||||
// We only use card_rs_length statistics to estimate young regions length.
|
||||
stats()->account_card_rs_length(r);
|
||||
assert_tracks_surviving_words(r);
|
||||
r->record_surv_words_in_group(_surviving_young_words[r->young_index_in_cset()]);
|
||||
}
|
||||
@ -894,8 +885,6 @@ public:
|
||||
p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0);
|
||||
|
||||
_g1h->clear_collection_set();
|
||||
|
||||
_g1h->young_regions_cardset()->clear();
|
||||
}
|
||||
|
||||
double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); }
|
||||
|
||||
@ -277,6 +277,14 @@
|
||||
"as a percentage of the heap size.") \
|
||||
range(0, 100) \
|
||||
\
|
||||
product(uint, G1OldCSetGroupSize, 5, EXPERIMENTAL, \
|
||||
"The maximum number of old CSet regions in a collection group. " \
|
||||
"All regions in a group will be evacuated in the same GC pause." \
|
||||
"The first group calculated after marking from marking " \
|
||||
"candidates may exceed this limit as it is calculated based on " \
|
||||
"G1MixedGCCountTarget.") \
|
||||
range(1, 256) \
|
||||
\
|
||||
product(bool, G1VerifyHeapRegionCodeRoots, false, DIAGNOSTIC, \
|
||||
"Verify the code root lists attached to each heap region.") \
|
||||
\
|
||||
|
||||
@ -46,20 +46,17 @@ class TestResultTracker {
|
||||
private int trackedRegion = -1;
|
||||
private int curGC = -1;
|
||||
private String stdout;
|
||||
private int expectedMarkingSkipEvents; // How many times has the region from the "marking" collection set candidate set been "skipped".
|
||||
private int expectedRetainedSkipEvents; // How many times has the region from the "retained" collection set candidate set been "skipped".
|
||||
private int expectedDropEvents; // How many times has the region from the "retained" collection set candidate set been "dropped".
|
||||
private int expectedMarkingReclaimEvents; // How many times has the region from the "marking" collection set candidate set been put into the collection set.
|
||||
private int expectedRetainedReclaimEvents; // How many times has the region from the "marking" collection set candidate set been put into the collection set.
|
||||
private int expectedRetainedReclaimEvents; // How many times has the region from the "retained" collection set candidate set been put into the collection set.
|
||||
|
||||
TestResultTracker(String stdout,
|
||||
int expectedMarkingSkipEvents,
|
||||
int expectedRetainedSkipEvents,
|
||||
int expectedDropEvents,
|
||||
int expectedMarkingReclaimEvents,
|
||||
int expectedRetainedReclaimEvents) {
|
||||
this.stdout = stdout;
|
||||
this.expectedMarkingSkipEvents = expectedMarkingSkipEvents;
|
||||
this.expectedRetainedSkipEvents = expectedRetainedSkipEvents;
|
||||
this.expectedDropEvents = expectedDropEvents;
|
||||
this.expectedMarkingReclaimEvents = expectedMarkingReclaimEvents;
|
||||
@ -116,34 +113,12 @@ class TestResultTracker {
|
||||
// The code below tracks that single pinned region through the various stages as defined by the policy.
|
||||
//
|
||||
public void verify() throws Exception {
|
||||
final String skipDropEvents = "GC\\((\\d+)\\).*(Marking|Retained) candidate (\\d+) can not be reclaimed currently\\. (Skipping|Dropping)";
|
||||
final String skipDropEvents = "GC\\((\\d+)\\).*(Retained) candidate (\\d+) can not be reclaimed currently\\. (Skipping|Dropping)";
|
||||
final String reclaimEvents = "GC\\((\\d+)\\) Finish adding (retained|marking) candidates to collection set\\. Initial: (\\d+).*pinned: (\\d+)";
|
||||
|
||||
Matcher skipDropMatcher = Pattern.compile(skipDropEvents, Pattern.MULTILINE).matcher(stdout);
|
||||
Matcher reclaimMatcher = Pattern.compile(reclaimEvents, Pattern.MULTILINE).matcher(stdout);
|
||||
|
||||
for (int i = 0; i < expectedMarkingSkipEvents; i++) {
|
||||
expectMoreMatches(skipDropMatcher, "expectedMarkingSkipEvents");
|
||||
curGC = expectIncreasingGC(skipDropMatcher);
|
||||
|
||||
Asserts.assertEQ("Marking", skipDropMatcher.group(2), "Expected \"Marking\" tag for GC " + curGC + " but got \"" + skipDropMatcher.group(2) + "\"");
|
||||
updateOrCompareCurRegion("MarkingSkip", Integer.parseInt(skipDropMatcher.group(3)));
|
||||
Asserts.assertEQ("Skipping", skipDropMatcher.group(4), "Expected \"Skipping\" tag for GC " + curGC + " but got \"" + skipDropMatcher.group(4) + "\"");
|
||||
|
||||
while (true) {
|
||||
if (!reclaimMatcher.find()) {
|
||||
Asserts.fail("Could not find \"Finish adding * candidates\" line for GC " + curGC);
|
||||
}
|
||||
if (reclaimMatcher.group(2).equals("retained")) {
|
||||
continue;
|
||||
}
|
||||
if (Integer.parseInt(reclaimMatcher.group(1)) == curGC) {
|
||||
int actual = Integer.parseInt(reclaimMatcher.group(4));
|
||||
Asserts.assertEQ(actual, 1, "Expected number of pinned to be 1 after marking skip but is " + actual);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < expectedRetainedSkipEvents; i++) {
|
||||
expectMoreMatches(skipDropMatcher, "expectedRetainedSkipEvents");
|
||||
@ -232,11 +207,11 @@ class TestResultTracker {
|
||||
public class TestPinnedOldObjectsEvacuation {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// younGCsBeforeUnpin, expectedMarkingSkipEvents, expectedRetainedSkipEvents, expectedDropEvents, expectedMarkingReclaimEvents, expectedRetainedReclaimEvents
|
||||
testPinnedEvacuation(1, 1, 0, 0, 0, 1);
|
||||
testPinnedEvacuation(2, 1, 1, 0, 0, 1);
|
||||
testPinnedEvacuation(3, 1, 2, 0, 0, 1);
|
||||
testPinnedEvacuation(4, 1, 2, 1, 0, 0);
|
||||
// younGCsBeforeUnpin, expectedRetainedSkipEvents, expectedDropEvents, expectedMarkingReclaimEvents, expectedRetainedReclaimEvents
|
||||
testPinnedEvacuation(1, 0, 0, 0, 1);
|
||||
testPinnedEvacuation(2, 1, 0, 0, 1);
|
||||
testPinnedEvacuation(3, 2, 0, 0, 1);
|
||||
testPinnedEvacuation(4, 2, 1, 0, 0);
|
||||
}
|
||||
|
||||
private static int numMatches(String stringToMatch, String pattern) {
|
||||
@ -252,7 +227,6 @@ public class TestPinnedOldObjectsEvacuation {
|
||||
}
|
||||
|
||||
private static void testPinnedEvacuation(int youngGCsBeforeUnpin,
|
||||
int expectedMarkingSkipEvents,
|
||||
int expectedRetainedSkipEvents,
|
||||
int expectedDropEvents,
|
||||
int expectedMarkingReclaimEvents,
|
||||
@ -278,7 +252,6 @@ public class TestPinnedOldObjectsEvacuation {
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
TestResultTracker t = new TestResultTracker(output.getStdout(),
|
||||
expectedMarkingSkipEvents,
|
||||
expectedRetainedSkipEvents,
|
||||
expectedDropEvents,
|
||||
expectedMarkingReclaimEvents,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user