duke@435: /* tamao@5120: * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSADAPTIVESIZEPOLICY_HPP stefank@2314: #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSADAPTIVESIZEPOLICY_HPP stefank@2314: stefank@2314: #include "gc_implementation/shared/adaptiveSizePolicy.hpp" stefank@2314: #include "gc_implementation/shared/gcStats.hpp" stefank@2314: #include "gc_implementation/shared/gcUtil.hpp" stefank@2314: #include "gc_interface/gcCause.hpp" stefank@2314: duke@435: // This class keeps statistical information and computes the duke@435: // optimal free space for both the young and old generation duke@435: // based on current application characteristics (based on gc cost duke@435: // and application footprint). duke@435: // duke@435: // It also computes an optimal tenuring threshold between the young duke@435: // and old generations, so as to equalize the cost of collections duke@435: // of those generations, as well as optimial survivor space sizes duke@435: // for the young generation. duke@435: // duke@435: // While this class is specifically intended for a generational system duke@435: // consisting of a young gen (containing an Eden and two semi-spaces) duke@435: // and a tenured gen, as well as a perm gen for reflective data, it duke@435: // makes NO references to specific generations. duke@435: // duke@435: // 05/02/2003 Update duke@435: // The 1.5 policy makes use of data gathered for the costs of GC on duke@435: // specific generations. That data does reference specific duke@435: // generation. Also diagnostics specific to generations have duke@435: // been added. duke@435: duke@435: // Forward decls duke@435: class elapsedTimer; duke@435: duke@435: class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { duke@435: friend class PSGCAdaptivePolicyCounters; duke@435: private: duke@435: // These values are used to record decisions made during the duke@435: // policy. For example, if the young generation was decreased duke@435: // to decrease the GC cost of minor collections the value duke@435: // decrease_young_gen_for_throughput_true is used. duke@435: duke@435: // Last calculated sizes, in bytes, and aligned duke@435: // NEEDS_CLEANUP should use sizes.hpp, but it works in ints, not size_t's duke@435: duke@435: // Time statistics duke@435: AdaptivePaddedAverage* _avg_major_pause; duke@435: duke@435: // Footprint statistics duke@435: AdaptiveWeightedAverage* _avg_base_footprint; duke@435: duke@435: // Statistical data gathered for GC duke@435: GCStats _gc_stats; duke@435: duke@435: size_t _survivor_size_limit; // Limit in bytes of survivor size duke@435: const double _collection_cost_margin_fraction; duke@435: duke@435: // Variable for estimating the major and minor pause times. duke@435: // These variables represent linear least-squares fits of duke@435: // the data. duke@435: // major pause time vs. old gen size duke@435: LinearLeastSquareFit* _major_pause_old_estimator; duke@435: // major pause time vs. young gen size duke@435: LinearLeastSquareFit* _major_pause_young_estimator; duke@435: duke@435: duke@435: // These record the most recent collection times. They duke@435: // are available as an alternative to using the averages duke@435: // for making ergonomic decisions. duke@435: double _latest_major_mutator_interval_seconds; duke@435: jwilhelm@6085: const size_t _space_alignment; // alignment for eden, survivors duke@435: duke@435: const double _gc_minor_pause_goal_sec; // goal for maximum minor gc pause duke@435: duke@435: // The amount of live data in the heap at the last full GC, used duke@435: // as a baseline to help us determine when we need to perform the duke@435: // next full GC. duke@435: size_t _live_at_last_full_gc; duke@435: duke@435: // decrease/increase the old generation for minor pause time duke@435: int _change_old_gen_for_min_pauses; duke@435: duke@435: // increase/decrease the young generation for major pause time duke@435: int _change_young_gen_for_maj_pauses; duke@435: duke@435: duke@435: // Flag indicating that the adaptive policy is ready to use duke@435: bool _old_gen_policy_is_ready; duke@435: duke@435: // Changing the generation sizing depends on the data that is duke@435: // gathered about the effects of changes on the pause times and duke@435: // throughput. These variable count the number of data points duke@435: // gathered. The policy may use these counters as a threshhold duke@435: // for reliable data. duke@435: julong _young_gen_change_for_major_pause_count; duke@435: duke@435: // To facilitate faster growth at start up, supplement the normal duke@435: // growth percentage for the young gen eden and the duke@435: // old gen space for promotion with these value which decay duke@435: // with increasing collections. duke@435: uint _young_gen_size_increment_supplement; duke@435: uint _old_gen_size_increment_supplement; duke@435: duke@435: // The number of bytes absorbed from eden into the old gen by moving the duke@435: // boundary over live data. duke@435: size_t _bytes_absorbed_from_eden; duke@435: duke@435: private: duke@435: duke@435: // Accessors duke@435: AdaptivePaddedAverage* avg_major_pause() const { return _avg_major_pause; } duke@435: double gc_minor_pause_goal_sec() const { return _gc_minor_pause_goal_sec; } duke@435: duke@435: // Change the young generation size to achieve a minor GC pause time goal tamao@5120: void adjust_promo_for_minor_pause_time(bool is_full_gc, duke@435: size_t* desired_promo_size_ptr, duke@435: size_t* desired_eden_size_ptr); tamao@5120: void adjust_eden_for_minor_pause_time(bool is_full_gc, tamao@5120: size_t* desired_eden_size_ptr); duke@435: // Change the generation sizes to achieve a GC pause time goal duke@435: // Returned sizes are not necessarily aligned. tamao@5120: void adjust_promo_for_pause_time(bool is_full_gc, tamao@5120: size_t* desired_promo_size_ptr, tamao@5120: size_t* desired_eden_size_ptr); tamao@5120: void adjust_eden_for_pause_time(bool is_full_gc, duke@435: size_t* desired_promo_size_ptr, duke@435: size_t* desired_eden_size_ptr); duke@435: // Change the generation sizes to achieve an application throughput goal duke@435: // Returned sizes are not necessarily aligned. tamao@5120: void adjust_promo_for_throughput(bool is_full_gc, tamao@5120: size_t* desired_promo_size_ptr); tamao@5120: void adjust_eden_for_throughput(bool is_full_gc, duke@435: size_t* desired_eden_size_ptr); duke@435: // Change the generation sizes to achieve minimum footprint duke@435: // Returned sizes are not aligned. duke@435: size_t adjust_promo_for_footprint(size_t desired_promo_size, duke@435: size_t desired_total); duke@435: size_t adjust_eden_for_footprint(size_t desired_promo_size, duke@435: size_t desired_total); duke@435: duke@435: // Size in bytes for an increment or decrement of eden. duke@435: virtual size_t eden_increment(size_t cur_eden, uint percent_change); duke@435: virtual size_t eden_decrement(size_t cur_eden); duke@435: size_t eden_decrement_aligned_down(size_t cur_eden); duke@435: size_t eden_increment_with_supplement_aligned_up(size_t cur_eden); duke@435: duke@435: // Size in bytes for an increment or decrement of the promotion area duke@435: virtual size_t promo_increment(size_t cur_promo, uint percent_change); duke@435: virtual size_t promo_decrement(size_t cur_promo); duke@435: size_t promo_decrement_aligned_down(size_t cur_promo); duke@435: size_t promo_increment_with_supplement_aligned_up(size_t cur_promo); duke@435: duke@435: // Returns a change that has been scaled down. Result duke@435: // is not aligned. (If useful, move to some shared duke@435: // location.) duke@435: size_t scale_down(size_t change, double part, double total); duke@435: duke@435: protected: duke@435: // Time accessors duke@435: duke@435: // Footprint accessors duke@435: size_t live_space() const { duke@435: return (size_t)(avg_base_footprint()->average() + duke@435: avg_young_live()->average() + duke@435: avg_old_live()->average()); duke@435: } duke@435: size_t free_space() const { duke@435: return _eden_size + _promo_size; duke@435: } duke@435: duke@435: void set_promo_size(size_t new_size) { duke@435: _promo_size = new_size; duke@435: } duke@435: void set_survivor_size(size_t new_size) { duke@435: _survivor_size = new_size; duke@435: } duke@435: duke@435: // Update estimators duke@435: void update_minor_pause_old_estimator(double minor_pause_in_ms); duke@435: duke@435: virtual GCPolicyKind kind() const { return _gc_ps_adaptive_size_policy; } duke@435: duke@435: public: duke@435: // Use by ASPSYoungGen and ASPSOldGen to limit boundary moving. duke@435: size_t eden_increment_aligned_up(size_t cur_eden); duke@435: size_t eden_increment_aligned_down(size_t cur_eden); duke@435: size_t promo_increment_aligned_up(size_t cur_promo); duke@435: size_t promo_increment_aligned_down(size_t cur_promo); duke@435: duke@435: virtual size_t eden_increment(size_t cur_eden); duke@435: virtual size_t promo_increment(size_t cur_promo); duke@435: duke@435: // Accessors for use by performance counters duke@435: AdaptivePaddedNoZeroDevAverage* avg_promoted() const { duke@435: return _gc_stats.avg_promoted(); duke@435: } duke@435: AdaptiveWeightedAverage* avg_base_footprint() const { duke@435: return _avg_base_footprint; duke@435: } duke@435: duke@435: // Input arguments are initial free space sizes for young and old duke@435: // generations, the initial survivor space size, the duke@435: // alignment values and the pause & throughput goals. duke@435: // duke@435: // NEEDS_CLEANUP this is a singleton object duke@435: PSAdaptiveSizePolicy(size_t init_eden_size, duke@435: size_t init_promo_size, duke@435: size_t init_survivor_size, jwilhelm@6085: size_t space_alignment, duke@435: double gc_pause_goal_sec, duke@435: double gc_minor_pause_goal_sec, duke@435: uint gc_time_ratio); duke@435: duke@435: // Methods indicating events of interest to the adaptive size policy, duke@435: // called by GC algorithms. It is the responsibility of users of this duke@435: // policy to call these methods at the correct times! duke@435: void major_collection_begin(); duke@435: void major_collection_end(size_t amount_live, GCCause::Cause gc_cause); duke@435: duke@435: void tenured_allocation(size_t size) { duke@435: _avg_pretenured->sample(size); duke@435: } duke@435: duke@435: // Accessors duke@435: // NEEDS_CLEANUP should use sizes.hpp duke@435: jwilhelm@6267: static size_t calculate_free_based_on_live(size_t live, uintx ratio_as_percentage); jwilhelm@6267: jwilhelm@6267: size_t calculated_old_free_size_in_bytes() const; duke@435: duke@435: size_t average_old_live_in_bytes() const { duke@435: return (size_t) avg_old_live()->average(); duke@435: } duke@435: duke@435: size_t average_promoted_in_bytes() const { duke@435: return (size_t)avg_promoted()->average(); duke@435: } duke@435: duke@435: size_t padded_average_promoted_in_bytes() const { duke@435: return (size_t)avg_promoted()->padded_average(); duke@435: } duke@435: duke@435: int change_young_gen_for_maj_pauses() { duke@435: return _change_young_gen_for_maj_pauses; duke@435: } duke@435: void set_change_young_gen_for_maj_pauses(int v) { duke@435: _change_young_gen_for_maj_pauses = v; duke@435: } duke@435: duke@435: int change_old_gen_for_min_pauses() { duke@435: return _change_old_gen_for_min_pauses; duke@435: } duke@435: void set_change_old_gen_for_min_pauses(int v) { duke@435: _change_old_gen_for_min_pauses = v; duke@435: } duke@435: duke@435: // Return true if the old generation size was changed duke@435: // to try to reach a pause time goal. duke@435: bool old_gen_changed_for_pauses() { duke@435: bool result = _change_old_gen_for_maj_pauses != 0 || duke@435: _change_old_gen_for_min_pauses != 0; duke@435: return result; duke@435: } duke@435: duke@435: // Return true if the young generation size was changed duke@435: // to try to reach a pause time goal. duke@435: bool young_gen_changed_for_pauses() { duke@435: bool result = _change_young_gen_for_min_pauses != 0 || duke@435: _change_young_gen_for_maj_pauses != 0; duke@435: return result; duke@435: } duke@435: // end flags for pause goal duke@435: duke@435: // Return true if the old generation size was changed duke@435: // to try to reach a throughput goal. duke@435: bool old_gen_changed_for_throughput() { duke@435: bool result = _change_old_gen_for_throughput != 0; duke@435: return result; duke@435: } duke@435: duke@435: // Return true if the young generation size was changed duke@435: // to try to reach a throughput goal. duke@435: bool young_gen_changed_for_throughput() { duke@435: bool result = _change_young_gen_for_throughput != 0; duke@435: return result; duke@435: } duke@435: duke@435: int decrease_for_footprint() { return _decrease_for_footprint; } duke@435: duke@435: duke@435: // Accessors for estimators. The slope of the linear fit is duke@435: // currently all that is used for making decisions. duke@435: duke@435: LinearLeastSquareFit* major_pause_old_estimator() { duke@435: return _major_pause_old_estimator; duke@435: } duke@435: duke@435: LinearLeastSquareFit* major_pause_young_estimator() { duke@435: return _major_pause_young_estimator; duke@435: } duke@435: duke@435: duke@435: virtual void clear_generation_free_space_flags(); duke@435: duke@435: float major_pause_old_slope() { return _major_pause_old_estimator->slope(); } duke@435: float major_pause_young_slope() { duke@435: return _major_pause_young_estimator->slope(); duke@435: } duke@435: float major_collection_slope() { return _major_collection_estimator->slope();} duke@435: duke@435: bool old_gen_policy_is_ready() { return _old_gen_policy_is_ready; } duke@435: duke@435: // Given the amount of live data in the heap, should we duke@435: // perform a Full GC? duke@435: bool should_full_GC(size_t live_in_old_gen); duke@435: tamao@5120: // Calculates optimal (free) space sizes for both the young and old duke@435: // generations. Stores results in _eden_size and _promo_size. duke@435: // Takes current used space in all generations as input, as well duke@435: // as an indication if a full gc has just been performed, for use duke@435: // in deciding if an OOM error should be thrown. tamao@5192: void compute_generations_free_space(size_t young_live, tamao@5192: size_t eden_live, tamao@5192: size_t old_live, tamao@5192: size_t cur_eden, // current eden in bytes tamao@5192: size_t max_old_gen_size, tamao@5192: size_t max_eden_size, tamao@5192: bool is_full_gc); tamao@5120: tamao@5120: void compute_eden_space_size(size_t young_live, tamao@5120: size_t eden_live, tamao@5120: size_t cur_eden, // current eden in bytes tamao@5120: size_t max_eden_size, tamao@5120: bool is_full_gc); tamao@5120: tamao@5120: void compute_old_gen_free_space(size_t old_live, tamao@5120: size_t cur_eden, // current eden in bytes tamao@5120: size_t max_old_gen_size, tamao@5120: bool is_full_gc); duke@435: duke@435: // Calculates new survivor space size; returns a new tenuring threshold duke@435: // value. Stores new survivor size in _survivor_size. jwilhelm@4129: uint compute_survivor_space_size_and_threshold(bool is_survivor_overflow, jwilhelm@4129: uint tenuring_threshold, jwilhelm@4129: size_t survivor_limit); duke@435: duke@435: // Return the maximum size of a survivor space if the young generation were of duke@435: // size gen_size. duke@435: size_t max_survivor_size(size_t gen_size) { duke@435: // Never allow the target survivor size to grow more than MinSurvivorRatio duke@435: // of the young generation size. We cannot grow into a two semi-space duke@435: // system, with Eden zero sized. Even if the survivor space grows, from() duke@435: // might grow by moving the bottom boundary "down" -- so from space will duke@435: // remain almost full anyway (top() will be near end(), but there will be a duke@435: // large filler object at the bottom). duke@435: const size_t sz = gen_size / MinSurvivorRatio; jwilhelm@6085: const size_t alignment = _space_alignment; duke@435: return sz > alignment ? align_size_down(sz, alignment) : alignment; duke@435: } duke@435: duke@435: size_t live_at_last_full_gc() { duke@435: return _live_at_last_full_gc; duke@435: } duke@435: duke@435: size_t bytes_absorbed_from_eden() const { return _bytes_absorbed_from_eden; } duke@435: void reset_bytes_absorbed_from_eden() { _bytes_absorbed_from_eden = 0; } duke@435: duke@435: void set_bytes_absorbed_from_eden(size_t val) { duke@435: _bytes_absorbed_from_eden = val; duke@435: } duke@435: duke@435: // Update averages that are always used (even duke@435: // if adaptive sizing is turned off). duke@435: void update_averages(bool is_survivor_overflow, duke@435: size_t survived, duke@435: size_t promoted); duke@435: duke@435: // Printing support duke@435: virtual bool print_adaptive_size_policy_on(outputStream* st) const; tamao@5120: tamao@5120: // Decay the supplemental growth additive. tamao@5120: void decay_supplemental_growth(bool is_full_gc); duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSADAPTIVESIZEPOLICY_HPP