Merge
This commit is contained in:
commit
f2b8803873
@ -3731,8 +3731,7 @@ void CMTask::do_marking_step(double time_target_ms,
|
||||
// and do_marking_step() is not being called serially.
|
||||
bool do_stealing = do_termination && !is_serial;
|
||||
|
||||
double diff_prediction_ms =
|
||||
g1_policy->get_new_prediction(&_marking_step_diffs_ms);
|
||||
double diff_prediction_ms = _g1h->g1_policy()->predictor().get_new_prediction(&_marking_step_diffs_ms);
|
||||
_time_target_ms = time_target_ms - diff_prediction_ms;
|
||||
|
||||
// set up the variables that are used in the work-based scheme to
|
||||
|
@ -80,6 +80,7 @@ static double non_young_other_cost_per_region_ms_defaults[] = {
|
||||
};
|
||||
|
||||
G1CollectorPolicy::G1CollectorPolicy() :
|
||||
_predictor(G1ConfidencePercent / 100.0),
|
||||
_parallel_gc_threads(ParallelGCThreads),
|
||||
|
||||
_recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
|
||||
@ -127,8 +128,6 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||
_survivor_cset_region_length(0),
|
||||
_old_cset_region_length(0),
|
||||
|
||||
_sigma(G1ConfidencePercent / 100.0),
|
||||
|
||||
_collection_set(NULL),
|
||||
_collection_set_bytes_used_before(0),
|
||||
|
||||
@ -151,12 +150,12 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||
|
||||
_gc_overhead_perc(0.0) {
|
||||
|
||||
// SurvRateGroups below must be initialized after '_sigma' because they
|
||||
// indirectly access '_sigma' through this object passed to their constructor.
|
||||
// SurvRateGroups below must be initialized after the predictor because they
|
||||
// indirectly use it through this object passed to their constructor.
|
||||
_short_lived_surv_rate_group =
|
||||
new SurvRateGroup(this, "Short Lived", G1YoungSurvRateNumRegionsSummary);
|
||||
new SurvRateGroup(&_predictor, "Short Lived", G1YoungSurvRateNumRegionsSummary);
|
||||
_survivor_surv_rate_group =
|
||||
new SurvRateGroup(this, "Survivor", G1YoungSurvRateNumRegionsSummary);
|
||||
new SurvRateGroup(&_predictor, "Survivor", G1YoungSurvRateNumRegionsSummary);
|
||||
|
||||
// Set up the region size and associated fields. Given that the
|
||||
// policy is created before the heap, we have to set this up here,
|
||||
@ -289,6 +288,10 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||
_collectionSetChooser = new CollectionSetChooser();
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const {
|
||||
return _predictor.get_new_prediction(seq);
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::initialize_alignments() {
|
||||
_space_alignment = HeapRegion::GrainBytes;
|
||||
size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint();
|
||||
@ -316,8 +319,7 @@ void G1CollectorPolicy::post_heap_initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
const G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
|
||||
G1CollectorState* G1CollectorPolicy::collector_state() { return _g1->collector_state(); }
|
||||
G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
|
||||
|
||||
G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
|
||||
_min_desired_young_length(0), _max_desired_young_length(0) {
|
||||
@ -428,8 +430,8 @@ void G1CollectorPolicy::init() {
|
||||
_young_list_fixed_length = _young_gen_sizer->min_desired_young_length();
|
||||
}
|
||||
_free_regions_at_end_of_collection = _g1->num_free_regions();
|
||||
update_young_list_target_length();
|
||||
|
||||
update_young_list_target_length();
|
||||
// We may immediately start allocating regions and placing them on the
|
||||
// collection set list. Initialize the per-collection set info
|
||||
start_incremental_cset_building();
|
||||
@ -460,9 +462,8 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length,
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t free_bytes =
|
||||
(base_free_regions - young_length) * HeapRegion::GrainBytes;
|
||||
if ((2.0 * sigma()) * (double) bytes_to_copy > (double) free_bytes) {
|
||||
size_t free_bytes = (base_free_regions - young_length) * HeapRegion::GrainBytes;
|
||||
if ((2.0 /* magic */ * _predictor.sigma()) * bytes_to_copy > free_bytes) {
|
||||
// end condition 3: out-of-space (conservatively!)
|
||||
return false;
|
||||
}
|
||||
@ -1269,7 +1270,7 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time,
|
||||
cg1r->set_red_zone(g * k_gr);
|
||||
cg1r->reinitialize_threads();
|
||||
|
||||
int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * sigma()), 1);
|
||||
int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * _predictor.sigma()), 1);
|
||||
int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta,
|
||||
cg1r->yellow_zone());
|
||||
// Change the barrier params
|
||||
@ -1286,17 +1287,125 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time,
|
||||
dcqs.notify_if_necessary();
|
||||
}
|
||||
|
||||
double
|
||||
G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards,
|
||||
size_t scanned_cards) const {
|
||||
size_t G1CollectorPolicy::predict_rs_length_diff() const {
|
||||
return (size_t) get_new_prediction(_rs_length_diff_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_alloc_rate_ms() const {
|
||||
return get_new_prediction(_alloc_rate_ms_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_cost_per_card_ms() const {
|
||||
return get_new_prediction(_cost_per_card_ms_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_scan_hcc_ms() const {
|
||||
return get_new_prediction(_cost_scan_hcc_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_rs_update_time_ms(size_t pending_cards) const {
|
||||
return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_young_cards_per_entry_ratio() const {
|
||||
return get_new_prediction(_young_cards_per_entry_ratio_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_mixed_cards_per_entry_ratio() const {
|
||||
if (_mixed_cards_per_entry_ratio_seq->num() < 2) {
|
||||
return predict_young_cards_per_entry_ratio();
|
||||
} else {
|
||||
return get_new_prediction(_mixed_cards_per_entry_ratio_seq);
|
||||
}
|
||||
}
|
||||
|
||||
size_t G1CollectorPolicy::predict_young_card_num(size_t rs_length) const {
|
||||
return (size_t) (rs_length * predict_young_cards_per_entry_ratio());
|
||||
}
|
||||
|
||||
size_t G1CollectorPolicy::predict_non_young_card_num(size_t rs_length) const {
|
||||
return (size_t)(rs_length * predict_mixed_cards_per_entry_ratio());
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_rs_scan_time_ms(size_t card_num) const {
|
||||
if (collector_state()->gcs_are_young()) {
|
||||
return card_num * get_new_prediction(_cost_per_entry_ms_seq);
|
||||
} else {
|
||||
return predict_mixed_rs_scan_time_ms(card_num);
|
||||
}
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_mixed_rs_scan_time_ms(size_t card_num) const {
|
||||
if (_mixed_cost_per_entry_ms_seq->num() < 3) {
|
||||
return card_num * get_new_prediction(_cost_per_entry_ms_seq);
|
||||
} else {
|
||||
return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq);
|
||||
}
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const {
|
||||
if (_cost_per_byte_ms_during_cm_seq->num() < 3) {
|
||||
return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq);
|
||||
} else {
|
||||
return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq);
|
||||
}
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_object_copy_time_ms(size_t bytes_to_copy) const {
|
||||
if (collector_state()->during_concurrent_mark()) {
|
||||
return predict_object_copy_time_ms_during_cm(bytes_to_copy);
|
||||
} else {
|
||||
return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq);
|
||||
}
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_constant_other_time_ms() const {
|
||||
return get_new_prediction(_constant_other_time_ms_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_young_other_time_ms(size_t young_num) const {
|
||||
return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_non_young_other_time_ms(size_t non_young_num) const {
|
||||
return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_remark_time_ms() const {
|
||||
return get_new_prediction(_concurrent_mark_remark_times_ms);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_cleanup_time_ms() const {
|
||||
return get_new_prediction(_concurrent_mark_cleanup_times_ms);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const {
|
||||
TruncatedSeq* seq = surv_rate_group->get_seq(age);
|
||||
guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age);
|
||||
double pred = get_new_prediction(seq);
|
||||
if (pred > 1.0) {
|
||||
pred = 1.0;
|
||||
}
|
||||
return pred;
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_yg_surv_rate(int age) const {
|
||||
return predict_yg_surv_rate(age, _short_lived_surv_rate_group);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::accum_yg_surv_rate_pred(int age) const {
|
||||
return _short_lived_surv_rate_group->accum_surv_rate_pred(age);
|
||||
}
|
||||
|
||||
double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards,
|
||||
size_t scanned_cards) const {
|
||||
return
|
||||
predict_rs_update_time_ms(pending_cards) +
|
||||
predict_rs_scan_time_ms(scanned_cards) +
|
||||
predict_constant_other_time_ms();
|
||||
}
|
||||
|
||||
double
|
||||
G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const {
|
||||
double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const {
|
||||
size_t rs_length = predict_rs_length_diff();
|
||||
size_t card_num;
|
||||
if (collector_state()->gcs_are_young()) {
|
||||
@ -1315,14 +1424,13 @@ size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) const {
|
||||
assert(hr->is_young() && hr->age_in_surv_rate_group() != -1, "invariant");
|
||||
int age = hr->age_in_surv_rate_group();
|
||||
double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group());
|
||||
bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate);
|
||||
bytes_to_copy = (size_t) (hr->used() * yg_surv_rate);
|
||||
}
|
||||
return bytes_to_copy;
|
||||
}
|
||||
|
||||
double
|
||||
G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr,
|
||||
bool for_young_gc) const {
|
||||
double G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr,
|
||||
bool for_young_gc) const {
|
||||
size_t rs_length = hr->rem_set()->occupied();
|
||||
size_t card_num;
|
||||
|
||||
@ -1349,9 +1457,8 @@ G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr,
|
||||
return region_elapsed_time_ms;
|
||||
}
|
||||
|
||||
void
|
||||
G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length,
|
||||
uint survivor_cset_region_length) {
|
||||
void G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length,
|
||||
uint survivor_cset_region_length) {
|
||||
_eden_cset_region_length = eden_cset_region_length;
|
||||
_survivor_cset_region_length = survivor_cset_region_length;
|
||||
_old_cset_region_length = 0;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "gc/g1/g1CollectorState.hpp"
|
||||
#include "gc/g1/g1InCSetState.hpp"
|
||||
#include "gc/g1/g1MMUTracker.hpp"
|
||||
#include "gc/g1/g1Predictions.hpp"
|
||||
#include "gc/shared/collectorPolicy.hpp"
|
||||
|
||||
// A G1CollectorPolicy makes policy decisions that determine the
|
||||
@ -161,7 +162,11 @@ public:
|
||||
};
|
||||
|
||||
class G1CollectorPolicy: public CollectorPolicy {
|
||||
private:
|
||||
private:
|
||||
G1Predictions _predictor;
|
||||
|
||||
double get_new_prediction(TruncatedSeq const* seq) const;
|
||||
|
||||
// either equal to the number of parallel threads, if ParallelGCThreads
|
||||
// has been set, or 1 otherwise
|
||||
int _parallel_gc_threads;
|
||||
@ -169,10 +174,6 @@ private:
|
||||
// The number of GC threads currently active.
|
||||
uintx _no_of_gc_threads;
|
||||
|
||||
enum SomePrivateConstants {
|
||||
NumPrevPausesForHeuristics = 10
|
||||
};
|
||||
|
||||
G1MMUTracker* _mmu_tracker;
|
||||
|
||||
void initialize_alignments();
|
||||
@ -211,7 +212,8 @@ private:
|
||||
uint _reserve_regions;
|
||||
|
||||
enum PredictionConstants {
|
||||
TruncatedSeqLength = 10
|
||||
TruncatedSeqLength = 10,
|
||||
NumPrevPausesForHeuristics = 10
|
||||
};
|
||||
|
||||
TruncatedSeq* _alloc_rate_ms_seq;
|
||||
@ -251,25 +253,9 @@ private:
|
||||
|
||||
size_t _recorded_rs_lengths;
|
||||
size_t _max_rs_lengths;
|
||||
double _sigma;
|
||||
|
||||
size_t _rs_lengths_prediction;
|
||||
|
||||
double sigma() const { return _sigma; }
|
||||
|
||||
// A function that prevents us putting too much stock in small sample
|
||||
// sets. Returns a number between 2.0 and 1.0, depending on the number
|
||||
// of samples. 5 or more samples yields one; fewer scales linearly from
|
||||
// 2.0 at 1 sample to 1.0 at 5.
|
||||
double confidence_factor(int samples) const {
|
||||
if (samples > 4) return 1.0;
|
||||
else return 1.0 + sigma() * ((double)(5 - samples))/2.0;
|
||||
}
|
||||
|
||||
double get_new_neg_prediction(TruncatedSeq* seq) {
|
||||
return seq->davg() - sigma() * seq->dsd();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group);
|
||||
#endif // PRODUCT
|
||||
@ -286,6 +272,8 @@ private:
|
||||
size_t _pending_cards;
|
||||
|
||||
public:
|
||||
G1Predictions& predictor() { return _predictor; }
|
||||
|
||||
// Accessors
|
||||
|
||||
void set_region_eden(HeapRegion* hr, int young_index_in_cset) {
|
||||
@ -304,106 +292,41 @@ public:
|
||||
bool verify_young_ages();
|
||||
#endif // PRODUCT
|
||||
|
||||
double get_new_prediction(TruncatedSeq* seq) const {
|
||||
return MAX2(seq->davg() + sigma() * seq->dsd(),
|
||||
seq->davg() * confidence_factor(seq->num()));
|
||||
}
|
||||
|
||||
void record_max_rs_lengths(size_t rs_lengths) {
|
||||
_max_rs_lengths = rs_lengths;
|
||||
}
|
||||
|
||||
size_t predict_rs_length_diff() const {
|
||||
return (size_t) get_new_prediction(_rs_length_diff_seq);
|
||||
}
|
||||
size_t predict_rs_length_diff() const;
|
||||
|
||||
double predict_alloc_rate_ms() const {
|
||||
return get_new_prediction(_alloc_rate_ms_seq);
|
||||
}
|
||||
double predict_alloc_rate_ms() const;
|
||||
|
||||
double predict_cost_per_card_ms() const {
|
||||
return get_new_prediction(_cost_per_card_ms_seq);
|
||||
}
|
||||
double predict_cost_per_card_ms() const;
|
||||
|
||||
double predict_scan_hcc_ms() const {
|
||||
return get_new_prediction(_cost_scan_hcc_seq);
|
||||
}
|
||||
double predict_scan_hcc_ms() const;
|
||||
|
||||
double predict_rs_update_time_ms(size_t pending_cards) const {
|
||||
return (double) pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
|
||||
}
|
||||
double predict_rs_update_time_ms(size_t pending_cards) const;
|
||||
|
||||
double predict_young_cards_per_entry_ratio() const {
|
||||
return get_new_prediction(_young_cards_per_entry_ratio_seq);
|
||||
}
|
||||
double predict_young_cards_per_entry_ratio() const;
|
||||
|
||||
double predict_mixed_cards_per_entry_ratio() const {
|
||||
if (_mixed_cards_per_entry_ratio_seq->num() < 2) {
|
||||
return predict_young_cards_per_entry_ratio();
|
||||
} else {
|
||||
return get_new_prediction(_mixed_cards_per_entry_ratio_seq);
|
||||
}
|
||||
}
|
||||
double predict_mixed_cards_per_entry_ratio() const;
|
||||
|
||||
size_t predict_young_card_num(size_t rs_length) const {
|
||||
return (size_t) ((double) rs_length *
|
||||
predict_young_cards_per_entry_ratio());
|
||||
}
|
||||
size_t predict_young_card_num(size_t rs_length) const;
|
||||
|
||||
size_t predict_non_young_card_num(size_t rs_length) const {
|
||||
return (size_t) ((double) rs_length *
|
||||
predict_mixed_cards_per_entry_ratio());
|
||||
}
|
||||
size_t predict_non_young_card_num(size_t rs_length) const;
|
||||
|
||||
double predict_rs_scan_time_ms(size_t card_num) const {
|
||||
if (collector_state()->gcs_are_young()) {
|
||||
return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq);
|
||||
} else {
|
||||
return predict_mixed_rs_scan_time_ms(card_num);
|
||||
}
|
||||
}
|
||||
double predict_rs_scan_time_ms(size_t card_num) const;
|
||||
|
||||
double predict_mixed_rs_scan_time_ms(size_t card_num) const {
|
||||
if (_mixed_cost_per_entry_ms_seq->num() < 3) {
|
||||
return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq);
|
||||
} else {
|
||||
return (double) (card_num *
|
||||
get_new_prediction(_mixed_cost_per_entry_ms_seq));
|
||||
}
|
||||
}
|
||||
double predict_mixed_rs_scan_time_ms(size_t card_num) const;
|
||||
|
||||
double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const {
|
||||
if (_cost_per_byte_ms_during_cm_seq->num() < 3) {
|
||||
return (1.1 * (double) bytes_to_copy) *
|
||||
get_new_prediction(_cost_per_byte_ms_seq);
|
||||
} else {
|
||||
return (double) bytes_to_copy *
|
||||
get_new_prediction(_cost_per_byte_ms_during_cm_seq);
|
||||
}
|
||||
}
|
||||
double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const;
|
||||
|
||||
double predict_object_copy_time_ms(size_t bytes_to_copy) const {
|
||||
if (collector_state()->during_concurrent_mark()) {
|
||||
return predict_object_copy_time_ms_during_cm(bytes_to_copy);
|
||||
} else {
|
||||
return (double) bytes_to_copy *
|
||||
get_new_prediction(_cost_per_byte_ms_seq);
|
||||
}
|
||||
}
|
||||
double predict_object_copy_time_ms(size_t bytes_to_copy) const;
|
||||
|
||||
double predict_constant_other_time_ms() const {
|
||||
return get_new_prediction(_constant_other_time_ms_seq);
|
||||
}
|
||||
double predict_constant_other_time_ms() const;
|
||||
|
||||
double predict_young_other_time_ms(size_t young_num) const {
|
||||
return (double) young_num *
|
||||
get_new_prediction(_young_other_cost_per_region_ms_seq);
|
||||
}
|
||||
double predict_young_other_time_ms(size_t young_num) const;
|
||||
|
||||
double predict_non_young_other_time_ms(size_t non_young_num) const {
|
||||
return (double) non_young_num *
|
||||
get_new_prediction(_non_young_other_cost_per_region_ms_seq);
|
||||
}
|
||||
double predict_non_young_other_time_ms(size_t non_young_num) const;
|
||||
|
||||
double predict_base_elapsed_time_ms(size_t pending_cards) const;
|
||||
double predict_base_elapsed_time_ms(size_t pending_cards,
|
||||
@ -420,11 +343,15 @@ public:
|
||||
|
||||
double predict_survivor_regions_evac_time() const;
|
||||
|
||||
bool should_update_surv_rate_group_predictors() {
|
||||
return collector_state()->last_gc_was_young() && !collector_state()->in_marking_window();
|
||||
}
|
||||
|
||||
void cset_regions_freed() {
|
||||
bool propagate = collector_state()->should_propagate();
|
||||
_short_lived_surv_rate_group->all_surviving_words_recorded(propagate);
|
||||
_survivor_surv_rate_group->all_surviving_words_recorded(propagate);
|
||||
// also call it on any more surv rate groups
|
||||
bool update = should_update_surv_rate_group_predictors();
|
||||
|
||||
_short_lived_surv_rate_group->all_surviving_words_recorded(update);
|
||||
_survivor_surv_rate_group->all_surviving_words_recorded(update);
|
||||
}
|
||||
|
||||
G1MMUTracker* mmu_tracker() {
|
||||
@ -439,34 +366,17 @@ public:
|
||||
return _mmu_tracker->max_gc_time() * 1000.0;
|
||||
}
|
||||
|
||||
double predict_remark_time_ms() const {
|
||||
return get_new_prediction(_concurrent_mark_remark_times_ms);
|
||||
}
|
||||
double predict_remark_time_ms() const;
|
||||
|
||||
double predict_cleanup_time_ms() const {
|
||||
return get_new_prediction(_concurrent_mark_cleanup_times_ms);
|
||||
}
|
||||
double predict_cleanup_time_ms() const;
|
||||
|
||||
// Returns an estimate of the survival rate of the region at yg-age
|
||||
// "yg_age".
|
||||
double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const {
|
||||
TruncatedSeq* seq = surv_rate_group->get_seq(age);
|
||||
if (seq->num() == 0)
|
||||
gclog_or_tty->print("BARF! age is %d", age);
|
||||
guarantee( seq->num() > 0, "invariant" );
|
||||
double pred = get_new_prediction(seq);
|
||||
if (pred > 1.0)
|
||||
pred = 1.0;
|
||||
return pred;
|
||||
}
|
||||
double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const;
|
||||
|
||||
double predict_yg_surv_rate(int age) const {
|
||||
return predict_yg_surv_rate(age, _short_lived_surv_rate_group);
|
||||
}
|
||||
double predict_yg_surv_rate(int age) const;
|
||||
|
||||
double accum_yg_surv_rate_pred(int age) const {
|
||||
return _short_lived_surv_rate_group->accum_surv_rate_pred(age);
|
||||
}
|
||||
double accum_yg_surv_rate_pred(int age) const;
|
||||
|
||||
private:
|
||||
// Statistics kept per GC stoppage, pause or full.
|
||||
@ -613,8 +523,7 @@ public:
|
||||
|
||||
virtual G1CollectorPolicy* as_g1_policy() { return this; }
|
||||
|
||||
const G1CollectorState* collector_state() const;
|
||||
G1CollectorState* collector_state();
|
||||
G1CollectorState* collector_state() const;
|
||||
|
||||
G1GCPhaseTimes* phase_times() const { return _phase_times; }
|
||||
|
||||
@ -888,15 +797,4 @@ public:
|
||||
virtual void post_heap_initialize();
|
||||
};
|
||||
|
||||
// This should move to some place more general...
|
||||
|
||||
// If we have "n" measurements, and we've kept track of their "sum" and the
|
||||
// "sum_of_squares" of the measurements, this returns the variance of the
|
||||
// sequence.
|
||||
inline double variance(int n, double sum_of_squares, double sum) {
|
||||
double n_d = (double)n;
|
||||
double avg = sum/n_d;
|
||||
return (sum_of_squares - 2.0 * avg * sum + n_d * avg * avg) / n_d;
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP
|
||||
|
@ -121,11 +121,7 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC {
|
||||
return (_in_marking_window && !_in_marking_window_im);
|
||||
}
|
||||
|
||||
bool should_propagate() const { // XXX should have a more suitable state name or abstraction for this
|
||||
return (_last_young_gc && !_in_marking_window);
|
||||
}
|
||||
|
||||
G1YCType yc_type() {
|
||||
G1YCType yc_type() const {
|
||||
if (during_initial_mark_pause()) {
|
||||
return InitialMark;
|
||||
} else if (mark_in_progress()) {
|
||||
|
98
hotspot/src/share/vm/gc/g1/g1Predictions.cpp
Normal file
98
hotspot/src/share/vm/gc/g1/g1Predictions.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1Predictions.hpp"
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void G1Predictions::test() {
|
||||
double const epsilon = 1e-6;
|
||||
{
|
||||
// Some basic formula tests with confidence = 0.0
|
||||
G1Predictions predictor(0.0);
|
||||
TruncatedSeq s;
|
||||
|
||||
double p0 = predictor.get_new_prediction(&s);
|
||||
assert(p0 < epsilon, "Initial prediction of empty sequence must be 0.0 but is %f", p0);
|
||||
|
||||
s.add(5.0);
|
||||
double p1 = predictor.get_new_prediction(&s);
|
||||
assert(fabs(p1 - 5.0) < epsilon, "Prediction should be 5.0 but is %f", p1);
|
||||
for (int i = 0; i < 40; i++) {
|
||||
s.add(5.0);
|
||||
}
|
||||
double p2 = predictor.get_new_prediction(&s);
|
||||
assert(fabs(p2 - 5.0) < epsilon, "Prediction should be 5.0 but is %f", p1);
|
||||
}
|
||||
|
||||
{
|
||||
// The following tests checks that the initial predictions are based on the
|
||||
// average of the sequence and not on the stddev (which is 0).
|
||||
G1Predictions predictor(0.5);
|
||||
TruncatedSeq s;
|
||||
|
||||
s.add(1.0);
|
||||
double p1 = predictor.get_new_prediction(&s);
|
||||
assert(p1 > 1.0, "First prediction must be larger than average, but avg is %f and prediction %f", s.davg(), p1);
|
||||
s.add(1.0);
|
||||
double p2 = predictor.get_new_prediction(&s);
|
||||
assert(p2 < p1, "First prediction must be larger than second, but they are %f %f", p1, p2);
|
||||
s.add(1.0);
|
||||
double p3 = predictor.get_new_prediction(&s);
|
||||
assert(p3 < p2, "Second prediction must be larger than third, but they are %f %f", p2, p3);
|
||||
s.add(1.0);
|
||||
s.add(1.0); // Five elements are now in the sequence.
|
||||
double p5 = predictor.get_new_prediction(&s);
|
||||
assert(p5 < p3, "Fifth prediction must be smaller than third, but they are %f %f", p3, p5);
|
||||
assert(fabs(p5 - 1.0) < epsilon, "Prediction must be 1.0+epsilon, but is %f", p5);
|
||||
}
|
||||
|
||||
{
|
||||
// The following tests checks that initially prediction based on the average is
|
||||
// used, that gets overridden by the stddev prediction at the end.
|
||||
G1Predictions predictor(0.5);
|
||||
TruncatedSeq s;
|
||||
|
||||
s.add(0.5);
|
||||
double p1 = predictor.get_new_prediction(&s);
|
||||
assert(p1 > 0.5, "First prediction must be larger than average, but avg is %f and prediction %f", s.davg(), p1);
|
||||
s.add(0.2);
|
||||
double p2 = predictor.get_new_prediction(&s);
|
||||
assert(p2 < p1, "First prediction must be larger than second, but they are %f %f", p1, p2);
|
||||
s.add(0.5);
|
||||
double p3 = predictor.get_new_prediction(&s);
|
||||
assert(p3 < p2, "Second prediction must be larger than third, but they are %f %f", p2, p3);
|
||||
s.add(0.2);
|
||||
s.add(2.0);
|
||||
double p5 = predictor.get_new_prediction(&s);
|
||||
assert(p5 > p3, "Fifth prediction must be bigger than third, but they are %f %f", p3, p5);
|
||||
}
|
||||
}
|
||||
|
||||
void TestPredictions_test() {
|
||||
G1Predictions::test();
|
||||
}
|
||||
|
||||
#endif
|
67
hotspot/src/share/vm/gc/g1/g1Predictions.hpp
Normal file
67
hotspot/src/share/vm/gc/g1/g1Predictions.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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_VM_GC_G1_G1PREDICTIONS_HPP
|
||||
#define SHARE_VM_GC_G1_G1PREDICTIONS_HPP
|
||||
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "utilities/numberSeq.hpp"
|
||||
|
||||
// Utility class containing various helper methods for prediction.
|
||||
class G1Predictions VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
double _sigma;
|
||||
|
||||
// This function is used to estimate the stddev of sample sets. There is some
|
||||
// special consideration of small sample sets: the actual stddev for them is
|
||||
// not very useful, so we calculate some value based on the sample average.
|
||||
// Five or more samples yields zero (at that point we use the stddev); fewer
|
||||
// scale the sample set average linearly from two times the average to 0.5 times
|
||||
// it.
|
||||
double stddev_estimate(TruncatedSeq const* seq) const {
|
||||
double estimate = seq->dsd();
|
||||
int const samples = seq->num();
|
||||
if (samples < 5) {
|
||||
estimate = MAX2(seq->davg() * (5 - samples) / 2.0, estimate);
|
||||
}
|
||||
return estimate;
|
||||
}
|
||||
public:
|
||||
G1Predictions(double sigma) : _sigma(sigma) {
|
||||
assert(sigma >= 0.0, "Confidence must be larger than or equal to zero");
|
||||
}
|
||||
|
||||
// Confidence factor.
|
||||
double sigma() const { return _sigma; }
|
||||
|
||||
double get_new_prediction(TruncatedSeq const* seq) const {
|
||||
return seq->davg() + _sigma * stddev_estimate(seq);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
static void test();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1PREDICTIONS_HPP
|
@ -24,15 +24,15 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/g1Predictions.hpp"
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#include "gc/g1/survRateGroup.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p,
|
||||
SurvRateGroup::SurvRateGroup(G1Predictions* predictor,
|
||||
const char* name,
|
||||
size_t summary_surv_rates_len) :
|
||||
_g1p(g1p), _name(name),
|
||||
_predictor(predictor), _name(name),
|
||||
_summary_surv_rates_len(summary_surv_rates_len),
|
||||
_summary_surv_rates_max_len(0),
|
||||
_summary_surv_rates(NULL),
|
||||
@ -52,10 +52,13 @@ SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p,
|
||||
start_adding_regions();
|
||||
}
|
||||
|
||||
double SurvRateGroup::get_new_prediction(TruncatedSeq const* seq) const {
|
||||
return _predictor->get_new_prediction(seq);
|
||||
}
|
||||
|
||||
void SurvRateGroup::reset() {
|
||||
_all_regions_allocated = 0;
|
||||
_setup_seq_num = 0;
|
||||
_accum_surv_rate = 0.0;
|
||||
_last_pred = 0.0;
|
||||
// the following will set up the arrays with length 1
|
||||
_region_num = 1;
|
||||
@ -76,15 +79,12 @@ void SurvRateGroup::reset() {
|
||||
_region_num = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SurvRateGroup::start_adding_regions() {
|
||||
void SurvRateGroup::start_adding_regions() {
|
||||
_setup_seq_num = _stats_arrays_length;
|
||||
_region_num = 0;
|
||||
_accum_surv_rate = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
SurvRateGroup::stop_adding_regions() {
|
||||
void SurvRateGroup::stop_adding_regions() {
|
||||
if (_region_num > _stats_arrays_length) {
|
||||
double* old_surv_rate = _surv_rate;
|
||||
double* old_accum_surv_rate_pred = _accum_surv_rate_pred;
|
||||
@ -119,33 +119,12 @@ SurvRateGroup::stop_adding_regions() {
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
SurvRateGroup::accum_surv_rate(size_t adjustment) {
|
||||
// we might relax this one in the future...
|
||||
guarantee( adjustment == 0 || adjustment == 1, "pre-condition" );
|
||||
|
||||
double ret = _accum_surv_rate;
|
||||
if (adjustment > 0) {
|
||||
TruncatedSeq* seq = get_seq(_region_num+1);
|
||||
double surv_rate = _g1p->get_new_prediction(seq);
|
||||
ret += surv_rate;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
SurvRateGroup::next_age_index() {
|
||||
TruncatedSeq* seq = get_seq(_region_num);
|
||||
double surv_rate = _g1p->get_new_prediction(seq);
|
||||
_accum_surv_rate += surv_rate;
|
||||
|
||||
int SurvRateGroup::next_age_index() {
|
||||
++_region_num;
|
||||
return (int) ++_all_regions_allocated;
|
||||
}
|
||||
|
||||
void
|
||||
SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
||||
void SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
||||
guarantee( 0 <= age_in_group && (size_t) age_in_group < _region_num,
|
||||
"pre-condition" );
|
||||
guarantee( _surv_rate[age_in_group] <= 0.00001,
|
||||
@ -161,9 +140,8 @@ SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
||||
if (propagate && _region_num > 0) { // conservative
|
||||
void SurvRateGroup::all_surviving_words_recorded(bool update_predictors) {
|
||||
if (update_predictors && _region_num > 0) { // conservative
|
||||
double surv_rate = _surv_rate_pred[_region_num-1]->last();
|
||||
for (size_t i = _region_num; i < _stats_arrays_length; ++i) {
|
||||
guarantee( _surv_rate[i] <= 0.00001,
|
||||
@ -175,24 +153,22 @@ SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
||||
double accum = 0.0;
|
||||
double pred = 0.0;
|
||||
for (size_t i = 0; i < _stats_arrays_length; ++i) {
|
||||
pred = _g1p->get_new_prediction(_surv_rate_pred[i]);
|
||||
pred = get_new_prediction(_surv_rate_pred[i]);
|
||||
if (pred > 1.0) pred = 1.0;
|
||||
accum += pred;
|
||||
_accum_surv_rate_pred[i] = accum;
|
||||
// gclog_or_tty->print_cr("age %3d, accum %10.2lf", i, accum);
|
||||
}
|
||||
_last_pred = pred;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void
|
||||
SurvRateGroup::print() {
|
||||
void SurvRateGroup::print() {
|
||||
gclog_or_tty->print_cr("Surv Rate Group: %s (" SIZE_FORMAT " entries)",
|
||||
_name, _region_num);
|
||||
for (size_t i = 0; i < _region_num; ++i) {
|
||||
gclog_or_tty->print_cr(" age " SIZE_FORMAT_W(4) " surv rate %6.2lf %% pred %6.2lf %%",
|
||||
i, _surv_rate[i] * 100.0,
|
||||
_g1p->get_new_prediction(_surv_rate_pred[i]) * 100.0);
|
||||
i, _surv_rate[i] * 100.0,
|
||||
_predictor->get_new_prediction(_surv_rate_pred[i]) * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,9 +187,9 @@ SurvRateGroup::print_surv_rate_summary() {
|
||||
size_t limit = MIN2((int) length, 10);
|
||||
while (index < limit) {
|
||||
gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4)
|
||||
" %6.2lf%% %6.2lf",
|
||||
index, _summary_surv_rates[index]->avg() * 100.0,
|
||||
(double) _summary_surv_rates[index]->num());
|
||||
" %6.2lf%% %6.2lf",
|
||||
index, _summary_surv_rates[index]->avg() * 100.0,
|
||||
(double) _summary_surv_rates[index]->num());
|
||||
++index;
|
||||
}
|
||||
|
||||
@ -230,9 +206,9 @@ SurvRateGroup::print_surv_rate_summary() {
|
||||
|
||||
if (index == length || num % 10 == 0) {
|
||||
gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) " .. " SIZE_FORMAT_W(4)
|
||||
" %6.2lf%% %6.2lf",
|
||||
(index-1) / 10 * 10, index-1, sum / (double) num,
|
||||
(double) samples / (double) num);
|
||||
" %6.2lf%% %6.2lf",
|
||||
(index-1) / 10 * 10, index-1, sum / (double) num,
|
||||
(double) samples / (double) num);
|
||||
sum = 0.0;
|
||||
num = 0;
|
||||
samples = 0;
|
||||
|
@ -27,18 +27,20 @@
|
||||
|
||||
#include "utilities/numberSeq.hpp"
|
||||
|
||||
class G1CollectorPolicy;
|
||||
class G1Predictions;
|
||||
|
||||
class SurvRateGroup : public CHeapObj<mtGC> {
|
||||
private:
|
||||
G1CollectorPolicy* _g1p;
|
||||
G1Predictions* _predictor;
|
||||
|
||||
double get_new_prediction(TruncatedSeq const* seq) const;
|
||||
|
||||
const char* _name;
|
||||
|
||||
size_t _stats_arrays_length;
|
||||
double* _surv_rate;
|
||||
double* _accum_surv_rate_pred;
|
||||
double _last_pred;
|
||||
double _accum_surv_rate;
|
||||
TruncatedSeq** _surv_rate_pred;
|
||||
NumberSeq** _summary_surv_rates;
|
||||
size_t _summary_surv_rates_len;
|
||||
@ -49,18 +51,18 @@ private:
|
||||
size_t _setup_seq_num;
|
||||
|
||||
public:
|
||||
SurvRateGroup(G1CollectorPolicy* g1p,
|
||||
SurvRateGroup(G1Predictions* predictor,
|
||||
const char* name,
|
||||
size_t summary_surv_rates_len);
|
||||
void reset();
|
||||
void start_adding_regions();
|
||||
void stop_adding_regions();
|
||||
void record_surviving_words(int age_in_group, size_t surv_words);
|
||||
void all_surviving_words_recorded(bool propagate);
|
||||
void all_surviving_words_recorded(bool update_predictors);
|
||||
const char* name() { return _name; }
|
||||
|
||||
size_t region_num() { return _region_num; }
|
||||
double accum_surv_rate_pred(int age) {
|
||||
double accum_surv_rate_pred(int age) const {
|
||||
assert(age >= 0, "must be");
|
||||
if ((size_t)age < _stats_arrays_length)
|
||||
return _accum_surv_rate_pred[age];
|
||||
@ -70,9 +72,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
double accum_surv_rate(size_t adjustment);
|
||||
|
||||
TruncatedSeq* get_seq(size_t age) {
|
||||
TruncatedSeq* get_seq(size_t age) const {
|
||||
if (age >= _setup_seq_num) {
|
||||
guarantee( _setup_seq_num > 0, "invariant" );
|
||||
age = _setup_seq_num-1;
|
||||
|
@ -3870,6 +3870,7 @@ void TestBufferingOopClosure_test();
|
||||
void TestCodeCacheRemSet_test();
|
||||
void FreeRegionList_test();
|
||||
void test_memset_with_concurrent_readers();
|
||||
void TestPredictions_test();
|
||||
#endif
|
||||
|
||||
void execute_internal_vm_tests() {
|
||||
@ -3912,6 +3913,7 @@ void execute_internal_vm_tests() {
|
||||
run_unit_test(FreeRegionList_test());
|
||||
}
|
||||
run_unit_test(test_memset_with_concurrent_readers());
|
||||
run_unit_test(TestPredictions_test());
|
||||
#endif
|
||||
tty->print_cr("All internal VM tests passed");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user