This commit is contained in:
Thomas Schatzl 2015-10-15 13:00:17 +02:00
commit f2b8803873
9 changed files with 373 additions and 230 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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()) {

View 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

View 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

View File

@ -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;

View File

@ -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;

View File

@ -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");
}