--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Thu Oct 15 13:00:17 2015 +0200
@@ -3731,8 +3731,7 @@
// 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
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Oct 15 13:00:17 2015 +0200
@@ -80,6 +80,7 @@
};
G1CollectorPolicy::G1CollectorPolicy() :
+ _predictor(G1ConfidencePercent / 100.0),
_parallel_gc_threads(ParallelGCThreads),
_recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
@@ -127,8 +128,6 @@
_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 @@
_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 @@
_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 @@
}
}
-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 @@
_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();
-
// 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 @@
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 @@
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 @@
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 @@
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 @@
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;
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Oct 15 13:00:17 2015 +0200
@@ -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 @@
};
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 @@
// 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 @@
uint _reserve_regions;
enum PredictionConstants {
- TruncatedSeqLength = 10
+ TruncatedSeqLength = 10,
+ NumPrevPausesForHeuristics = 10
};
TruncatedSeq* _alloc_rate_ms_seq;
@@ -251,25 +253,9 @@
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 @@
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 @@
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_rs_update_time_ms(size_t pending_cards) const {
- return (double) pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
- }
+ double predict_scan_hcc_ms() const;
- double predict_young_cards_per_entry_ratio() const {
- return get_new_prediction(_young_cards_per_entry_ratio_seq);
- }
+ double predict_rs_update_time_ms(size_t pending_cards) const;
+
+ 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_non_young_card_num(size_t rs_length) const {
- return (size_t) ((double) rs_length *
- predict_mixed_cards_per_entry_ratio());
- }
+ size_t predict_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);
- }
- }
+ size_t predict_non_young_card_num(size_t rs_length) const;
+
+ 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;
- 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(size_t bytes_to_copy) const;
+
+ double predict_constant_other_time_ms() 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_young_other_time_ms(size_t young_num) const;
- double predict_constant_other_time_ms() const {
- return get_new_prediction(_constant_other_time_ms_seq);
- }
-
- 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_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 @@
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 @@
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 @@
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 @@
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
--- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Thu Oct 15 13:00:17 2015 +0200
@@ -121,11 +121,7 @@
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()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1Predictions.cpp Thu Oct 15 13:00:17 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1Predictions.hpp Thu Oct 15 13:00:17 2015 +0200
@@ -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
--- a/hotspot/src/share/vm/gc/g1/survRateGroup.cpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/survRateGroup.cpp Thu Oct 15 13:00:17 2015 +0200
@@ -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 @@
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 @@
_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 @@
}
}
-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 @@
}
}
-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 @@
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 @@
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 @@
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;
--- a/hotspot/src/share/vm/gc/g1/survRateGroup.hpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/survRateGroup.hpp Thu Oct 15 13:00:17 2015 +0200
@@ -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 @@
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 @@
}
}
- 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;
--- a/hotspot/src/share/vm/prims/jni.cpp Wed Oct 14 14:50:43 2015 +0200
+++ b/hotspot/src/share/vm/prims/jni.cpp Thu Oct 15 13:00:17 2015 +0200
@@ -3870,6 +3870,7 @@
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 @@
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");
}