g1CollectorPolicy.hpp revision 838
/*
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
// A G1CollectorPolicy makes policy decisions that determine the
// characteristics of the collector. Examples include:
// * choice of collection set.
// * when to collect.
class HeapRegion;
class CollectionSetChooser;
// Yes, this is a bit unpleasant... but it saves replicating the same thing
// over and over again and introducing subtle problems through small typos and
// cutting and pasting mistakes. The macros below introduces a number
// sequnce into the following two classes and the methods that access it.
#define define_num_seq(name) \
private: \
public: \
} \
}
class MainBodySummary;
class PauseSummary: public CHeapObj {
public:
};
class MainBodySummary: public CHeapObj {
// in parallel case.
};
class Summary: public PauseSummary,
public MainBodySummary {
public:
virtual MainBodySummary* main_body_summary() { return this; }
};
class AbandonedSummary: public PauseSummary {
};
class G1CollectorPolicy: public CollectorPolicy {
protected:
// The number of pauses during the execution.
long _n_pauses;
// either equal to the number of parallel threads, if ParallelGCThreads
// has been set, or 1 otherwise
int _parallel_gc_threads;
enum SomePrivateConstants {
NumPrevGCsForHeuristics = 10,
};
void initialize_flags();
void initialize_all() {
}
virtual size_t default_init_heap_size() {
// Pick some reasonable default.
return 8*M;
}
double _cur_collection_start_sec;
double _cur_collection_par_time_ms;
double _cur_satb_drain_time_ms;
double _cur_clear_ct_time_ms;
bool _satb_drain_time_set;
double _cur_CH_strong_roots_end_sec;
double _cur_CH_strong_roots_dur_ms;
double _cur_G1_strong_roots_end_sec;
double _cur_G1_strong_roots_dur_ms;
// Statistics for recent GC pauses. See below for how indexed.
// These exclude marking times.
double _stop_world_start;
int _aux_num;
double* _cur_aux_start_times_ms;
double* _cur_aux_times_ms;
bool* _cur_aux_times_set;
double* _par_last_ext_root_scan_times_ms;
double* _par_last_mark_stack_scan_times_ms;
double* _par_last_scan_only_times_ms;
double* _par_last_scan_only_regions_scanned;
double* _par_last_update_rs_start_times_ms;
double* _par_last_update_rs_times_ms;
double* _par_last_scan_rs_start_times_ms;
double* _par_last_scan_rs_times_ms;
double* _par_last_scan_new_refs_times_ms;
double* _par_last_obj_copy_times_ms;
double* _par_last_termination_times_ms;
// indicates that we are in young GC mode
bool _in_young_gc_mode;
// indicates whether we are in full young or partially young GC mode
bool _full_young_gcs;
// if true, then it tries to dynamically adjust the length of the
// young list
bool _last_young_gc_full;
double _target_pause_time_ms;
unsigned _full_young_pause_num;
unsigned _partial_young_pause_num;
bool _during_marking;
bool _in_marking_window;
bool _in_marking_window_im;
// add here any more surv rate groups
bool during_marking() {
return _during_marking;
}
// <NEW PREDICTION>
private:
enum PredictionConstants {
TruncatedSeqLength = 10
};
double _prev_collection_pause_end_ms;
double _predicted_survival_ratio;
double _predicted_rs_update_time_ms;
double _predicted_rs_scan_time_ms;
double _predicted_object_copy_time_ms;
double _predicted_young_other_time_ms;
double _predicted_pause_time_ms;
double _vtime_diff_ms;
double _sigma;
double _expensive_region_limit_ms;
double _known_garbage_ratio;
double sigma() {
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) {
}
}
#ifndef PRODUCT
#endif // PRODUCT
protected:
double _pause_time_target_ms;
bool _within_target;
public:
}
}
#ifndef PRODUCT
bool verify_young_ages();
#endif // PRODUCT
}
return _young_cset_length;
}
}
if (prediction < 0.00001)
return 0;
else
return (size_t) prediction;
}
if (diff > max_pending_card_num)
else
return prediction;
}
}
double predict_alloc_rate_ms() {
return get_new_prediction(_alloc_rate_ms_seq);
}
double predict_cost_per_card_ms() {
return get_new_prediction(_cost_per_card_ms_seq);
}
return (double) pending_cards * predict_cost_per_card_ms();
}
double predict_fully_young_cards_per_entry_ratio() {
}
else
}
}
}
if (full_young_gcs())
else
}
else
return (double) card_num *
}
return 1.5 * (double) scan_only_region_num *
else
return (double) scan_only_region_num *
}
else
return (double) scan_only_region_num *
}
return 1.1 * (double) bytes_to_copy *
else
return (double) bytes_to_copy *
}
if (_in_marking_window && !_in_marking_window_im)
else
return (double) bytes_to_copy *
}
double predict_constant_other_time_ms() {
}
return
(double) young_num *
}
return
(double) non_young_num *
}
void check_if_region_is_too_expensive(double predicted_time_ms);
// for use by: calculate_optimal_so_length(length)
double base_time_ms,
double *gc_eff,
double *pause_time_ms);
// for use by: calculate_young_list_target_config(rs_length)
double base_time_with_so_ms,
double target_pause_time_ms,
double* gc_eff);
void start_recording_regions();
void end_recording_regions();
void record_vtime_diff_ms(double vtime_diff_ms) {
}
void record_young_free_cset_time_ms(double time_ms) {
}
void record_non_young_free_cset_time_ms(double time_ms) {
}
double predict_young_gc_eff() {
return get_new_neg_prediction(_young_gc_eff_seq);
}
double predict_survivor_regions_evac_time();
// </NEW PREDICTION>
public:
void cset_regions_freed() {
// also call it on any more surv rate groups
}
}
}
G1MMUTracker* mmu_tracker() {
return _mmu_tracker;
}
double predict_init_time_ms() {
}
double predict_remark_time_ms() {
}
double predict_cleanup_time_ms() {
}
// Returns an estimate of the survival rate of the region at yg-age
// "yg_age".
if (pred > 1.0)
pred = 1.0;
return pred;
}
double predict_yg_surv_rate(int age) {
}
double accum_yg_surv_rate_pred(int age) {
}
protected:
}
void check_other_times(int level,
NumberSeq* calc_other_times_ms) const;
double sum_of_values (double* data);
double _last_pause_time_ms;
return
}
// Used to count used bytes in CS.
friend class CountCSClosure;
// Statistics kept per GC stoppage, pause or full.
// We track markings.
int _num_markings;
double _mark_thread_startup_sec; // Time at startup of marking thread
// Add a new GC of the given duration and end time to the record.
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
// Info about marking.
int _n_marks; // Sticky at 2, so we know when we've done at least 2.
// The number of collection pauses at the end of the last mark.
// Stash a pointer to the g1 heap.
// The average time in ms per collection pause, averaged over recent pauses.
double recent_avg_time_for_pauses_ms();
// The average time in ms for processing CollectedHeap strong roots, per
// collection pause, averaged over recent pauses.
double recent_avg_time_for_CH_strong_ms();
// The average time in ms for processing the G1 remembered set, per
// pause, averaged over recent pauses.
double recent_avg_time_for_G1_strong_ms();
// The average time in ms for "evacuating followers", per pause, averaged
// over recent pauses.
double recent_avg_time_for_evac_ms();
// The number of "recent" GCs recorded in the number sequences
int number_of_recent_gcs();
// The average survival ratio, computed by the total number of bytes
// suriviving / total number of bytes before collection over the last
// several recent pauses.
double recent_avg_survival_fraction();
// The survival fraction of the most recent pause; if there have been no
// pauses, returns 1.0.
double last_survival_fraction();
// Returns a "conservative" estimate of the recent survival rate, i.e.,
// one that may be higher than "recent_avg_survival_fraction".
// This is conservative in several ways:
// If there have been few pauses, it will assume a potential high
// variance, and err on the side of caution.
// It puts a lower bound (currently 0.1) on the value it will return.
// To try to detect phase changes, if the most recent pause ("latest") has a
// higher-than average ("avg") survival rate, it returns that rate.
// "work" version is a utility function; young is restricted to young regions.
double conservative_avg_survival_fraction_work(double avg,
double latest);
// The arguments are the two sequences that keep track of the number of bytes
// surviving and the total number of bytes before collection, resp.,
// over the last evereal recent pauses
// Returns the survival rate for the category in the most recent pause.
// If there have been no pauses, returns 1.0.
// The arguments are the two sequences that keep track of the number of bytes
// surviving and the total number of bytes before collection, resp.,
// over the last several recent pauses
// Returns the average survival ration over the last several recent pauses
// If there have been no pauses, return 1.0
double conservative_avg_survival_fraction() {
double avg = recent_avg_survival_fraction();
double latest = last_survival_fraction();
}
// The ratio of gc time to elapsed time, computed over recent pauses.
double _recent_avg_pause_time_ratio;
double recent_avg_pause_time_ratio() {
return _recent_avg_pause_time_ratio;
}
// Number of pauses between concurrent marking.
// True iff CM has been initiated.
bool _conc_mark_initiated;
// True iff CM should be initiated
bool _last_full_young_gc;
// This set of variables tracks the collector efficiency, in order to
// determine whether we should initiate a new marking.
double _cur_mark_stop_world_time_ms;
double _mark_init_start_sec;
double _mark_remark_start_sec;
double _mark_cleanup_start_sec;
double _mark_closure_time_ms;
void calculate_young_list_min_length();
public:
virtual G1CollectorPolicy* as_g1_policy() { return this; }
return CollectorPolicy::G1CollectorPolicyKind;
}
void check_prediction_validity();
}
return bytes_in_to_space_during_gc();
}
unsigned calc_gc_alloc_time_stamp() {
}
protected:
// Count the number of bytes used in the CS.
void count_CS_bytes_used();
// Together these do the base cleanup-recording work. Subclasses might
// want to put something between them.
public:
virtual void init();
// Create jstat counters for the policy.
virtual void initialize_gc_policy_counters();
bool is_tlab,
bool* gc_overhead_limit_was_exceeded);
// This method controls how a collector handles one or more
// of its generations being fully allocated.
bool is_tlab);
// The number of collection pauses so far.
// Update the heuristic info to record a collection pause of the given
// start time, where the given number of bytes were used at the start.
// This may involve changing the desired size of a collection set.
virtual void record_stop_world_start();
virtual void record_collection_pause_start(double start_time_sec,
// Must currently be called while the world is stopped.
virtual void record_concurrent_mark_init_start();
virtual void record_concurrent_mark_init_end();
void record_concurrent_mark_init_end_pre(double
void record_mark_closure_time(double mark_closure_time_ms);
virtual void record_concurrent_mark_remark_start();
virtual void record_concurrent_mark_remark_end();
virtual void record_concurrent_mark_cleanup_start();
virtual void record_concurrent_mark_cleanup_completed();
virtual void record_concurrent_pause();
virtual void record_concurrent_pause_end();
virtual void record_collection_pause_end_CH_strong_roots();
virtual void record_collection_pause_end_G1_strong_roots();
virtual void record_collection_pause_end(bool abandoned);
// Record the fact that a full collection occurred.
virtual void record_full_collection_start();
virtual void record_full_collection_end();
}
}
_par_last_scan_only_regions_scanned[worker_i] = (double) n;
}
void record_satb_drain_time(double ms) {
_satb_drain_time_set = true;
}
void record_satb_drain_processed_buffers (int processed_buffers) {
}
void record_mod_union_time(double ms) {
}
}
}
void record_update_rs_processed_buffers (int thread,
double processed_buffers) {
}
}
}
}
double get_scan_new_refs_time(int thread) {
return _par_last_scan_new_refs_times_ms[thread];
}
void reset_obj_copy_time(int thread) {
}
void reset_obj_copy_time() {
}
}
void record_obj_copy_time(double ms) {
record_obj_copy_time(0, ms);
}
}
void record_termination_time(double ms) {
}
void record_pause_time_ms(double ms) {
}
void record_clear_ct_time(double ms) {
}
void record_par_time(double ms) {
}
void record_aux_start_time(int i) {
}
void record_aux_end_time(int i) {
_cur_aux_times_set[i] = true;
_cur_aux_times_ms[i] += ms;
}
// Record the fact that "bytes" bytes allocated in a region.
// Returns "true" if this is a good time to do a collection pause.
// The "word_size" argument, if non-zero, indicates the size of an
// allocation request that is prompting this query.
// Choose a new collection set. Marks the chosen regions as being
// "in_collection_set", and links them together. The head and number of
// the collection set are available via access methods.
virtual void choose_collection_set() = 0;
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
// The number of elements in the current collection set.
// Add "hr" to the CS.
bool should_initiate_conc_mark() { return _should_initiate_conc_mark; }
void set_should_initiate_conc_mark() { _should_initiate_conc_mark = true; }
void unset_should_initiate_conc_mark(){ _should_initiate_conc_mark = false; }
void checkpoint_conc_overhead();
// If an expansion would be appropriate, because recent GC overhead had
// exceeded the desired limit, return an amount to expand by.
virtual size_t expansion_amount();
// note start of mark thread
void note_start_of_mark_thread();
// The marked bytes of the "r" has changed; reclassify it's desirability
// for marking. Also asserts that "r" is eligible for a CS.
virtual void note_change_in_marked_bytes(HeapRegion* r) = 0;
#ifndef PRODUCT
// Check any appropriate marked bytes info, asserting false if
// something's wrong, else returning "true".
virtual bool assertMarkedBytesDataOK() = 0;
#endif
// Print tracing information.
void print_tracing_info() const;
// Print stats on young survival ratio
void print_yg_surv_rate_info() const;
void finished_recalculating_age_indexes(bool is_survivors) {
if (is_survivors) {
} else {
}
// do that for any other surv rate groups
}
bool in_young_gc_mode() {
return _in_young_gc_mode;
}
void set_in_young_gc_mode(bool in_young_gc_mode) {
}
bool full_young_gcs() {
return _full_young_gcs;
}
void set_full_young_gcs(bool full_young_gcs) {
}
bool adaptive_young_list_length() {
return _adaptive_young_list_length;
}
void set_adaptive_young_list_length(bool adaptive_young_list_length) {
}
inline double get_gc_eff_factor() {
double ratio = _known_garbage_ratio;
// square = square * square;
#if 0
#endif // 0
return ret;
}
//
// Survivor regions policy.
//
protected:
// Current tenuring threshold, set to 0 if the collector reaches the
// maximum amount of suvivors regions.
int _tenuring_threshold;
// The limit on the number of regions allocated for survivors.
// The amount of survor regions after a collection.
// List of survivor regions.
public:
inline GCAllocPurpose
return GCAllocForSurvived;
} else {
return GCAllocForTenured;
}
}
return purpose == GCAllocForSurvived;
}
return GCAllocForTenured;
}
// The limit on regions for a particular purpose is reached.
void note_alloc_region_limit_reached(int purpose) {
if (purpose == GCAllocForSurvived) {
_tenuring_threshold = 0;
}
}
void note_start_adding_survivor_regions() {
}
void note_stop_adding_survivor_regions() {
}
HeapRegion* tail) {
}
return _recorded_survivor_regions;
}
{
}
// Calculates survivor space parameters.
void calculate_survivors_policy();
};
// This encapsulates a particular strategy for a g1 Collector.
//
// Start a concurrent mark when our heap size is n bytes
// greater then our heap size was at the last concurrent
// mark. Where n is a function of the CMSTriggerRatio
// and the MinHeapFreeRatio.
//
// Start a g1 collection pause when we have allocated the
// average number of bytes currently being freed in
// a collection, but only if it is at least one region
// full
//
// Resize Heap based on desired
// allocation space, where desired allocation space is
// a function of survival rate and desired future to size.
//
// Choose collection set by first picking all older regions
// which have a survival rate which beats our projected young
// survival rate. Then fill out the number of needed regions
// with young regions.
class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy {
// If the estimated is less then desirable, resize if possible.
virtual void choose_collection_set();
virtual void record_collection_pause_start(double start_time_sec,
virtual void record_full_collection_end();
public:
}
void record_collection_pause_end(bool abandoned);
// This is not needed any more, after the CSet choosing code was
// changed to use the pause prediction work. But let's leave the
// hook in just in case.
void note_change_in_marked_bytes(HeapRegion* r) { }
#ifndef PRODUCT
bool assertMarkedBytesDataOK();
#endif
};
// 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.
double n_d = (double)n;
}
// Local Variables: ***
// c-indentation-style: gnu ***
// End: ***