Wed, 21 Dec 2011 22:13:31 +0100
7113021: G1: automatically enable young gen size auto-tuning when -Xms==-Xmx
Summary: Use a percentage of -Xms as min and another percentage of -Xmx as max for the young gen size
Reviewed-by: tonyp, johnc
1.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Dec 14 13:34:57 2011 -0800 1.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Dec 21 22:13:31 2011 +0100 1.3 @@ -136,7 +136,6 @@ 1.4 _stop_world_start(0.0), 1.5 _all_stop_world_times_ms(new NumberSeq()), 1.6 _all_yield_times_ms(new NumberSeq()), 1.7 - _using_new_ratio_calculations(false), 1.8 1.9 _summary(new Summary()), 1.10 1.11 @@ -409,11 +408,7 @@ 1.12 1.13 initialize_all(); 1.14 _collectionSetChooser = new CollectionSetChooser(); 1.15 -} 1.16 - 1.17 -// Increment "i", mod "len" 1.18 -static void inc_mod(int& i, int len) { 1.19 - i++; if (i == len) i = 0; 1.20 + _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags 1.21 } 1.22 1.23 void G1CollectorPolicy::initialize_flags() { 1.24 @@ -425,71 +420,88 @@ 1.25 CollectorPolicy::initialize_flags(); 1.26 } 1.27 1.28 -// The easiest way to deal with the parsing of the NewSize / 1.29 -// MaxNewSize / etc. parameteres is to re-use the code in the 1.30 -// TwoGenerationCollectorPolicy class. This is similar to what 1.31 -// ParallelScavenge does with its GenerationSizer class (see 1.32 -// ParallelScavengeHeap::initialize()). We might change this in the 1.33 -// future, but it's a good start. 1.34 -class G1YoungGenSizer : public TwoGenerationCollectorPolicy { 1.35 -private: 1.36 - size_t size_to_region_num(size_t byte_size) { 1.37 - return MAX2((size_t) 1, byte_size / HeapRegion::GrainBytes); 1.38 - } 1.39 - 1.40 -public: 1.41 - G1YoungGenSizer() { 1.42 - initialize_flags(); 1.43 - initialize_size_info(); 1.44 - } 1.45 - size_t min_young_region_num() { 1.46 - return size_to_region_num(_min_gen0_size); 1.47 - } 1.48 - size_t initial_young_region_num() { 1.49 - return size_to_region_num(_initial_gen0_size); 1.50 - } 1.51 - size_t max_young_region_num() { 1.52 - return size_to_region_num(_max_gen0_size); 1.53 - } 1.54 -}; 1.55 - 1.56 -void G1CollectorPolicy::update_young_list_size_using_newratio(size_t number_of_heap_regions) { 1.57 - assert(number_of_heap_regions > 0, "Heap must be initialized"); 1.58 - size_t young_size = number_of_heap_regions / (NewRatio + 1); 1.59 - _min_desired_young_length = young_size; 1.60 - _max_desired_young_length = young_size; 1.61 -} 1.62 - 1.63 -void G1CollectorPolicy::init() { 1.64 - // Set aside an initial future to_space. 1.65 - _g1 = G1CollectedHeap::heap(); 1.66 - 1.67 - assert(Heap_lock->owned_by_self(), "Locking discipline."); 1.68 - 1.69 - initialize_gc_policy_counters(); 1.70 - 1.71 - G1YoungGenSizer sizer; 1.72 - _min_desired_young_length = sizer.min_young_region_num(); 1.73 - _max_desired_young_length = sizer.max_young_region_num(); 1.74 +G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true) { 1.75 + assert(G1DefaultMinNewGenPercent <= G1DefaultMaxNewGenPercent, "Min larger than max"); 1.76 + assert(G1DefaultMinNewGenPercent > 0 && G1DefaultMinNewGenPercent < 100, "Min out of bounds"); 1.77 + assert(G1DefaultMaxNewGenPercent > 0 && G1DefaultMaxNewGenPercent < 100, "Max out of bounds"); 1.78 1.79 if (FLAG_IS_CMDLINE(NewRatio)) { 1.80 if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { 1.81 warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); 1.82 } else { 1.83 - // Treat NewRatio as a fixed size that is only recalculated when the heap size changes 1.84 - update_young_list_size_using_newratio(_g1->n_regions()); 1.85 - _using_new_ratio_calculations = true; 1.86 + _sizer_kind = SizerNewRatio; 1.87 + _adaptive_size = false; 1.88 + return; 1.89 } 1.90 } 1.91 1.92 + if (FLAG_IS_CMDLINE(NewSize)) { 1.93 + _min_desired_young_length = MAX2((size_t) 1, NewSize / HeapRegion::GrainBytes); 1.94 + if (FLAG_IS_CMDLINE(MaxNewSize)) { 1.95 + _max_desired_young_length = MAX2((size_t) 1, MaxNewSize / HeapRegion::GrainBytes); 1.96 + _sizer_kind = SizerMaxAndNewSize; 1.97 + _adaptive_size = _min_desired_young_length == _max_desired_young_length; 1.98 + } else { 1.99 + _sizer_kind = SizerNewSizeOnly; 1.100 + } 1.101 + } else if (FLAG_IS_CMDLINE(MaxNewSize)) { 1.102 + _max_desired_young_length = MAX2((size_t) 1, MaxNewSize / HeapRegion::GrainBytes); 1.103 + _sizer_kind = SizerMaxNewSizeOnly; 1.104 + } 1.105 +} 1.106 + 1.107 +size_t G1YoungGenSizer::calculate_default_min_length(size_t new_number_of_heap_regions) { 1.108 + size_t default_value = (new_number_of_heap_regions * G1DefaultMinNewGenPercent) / 100; 1.109 + return MAX2((size_t)1, default_value); 1.110 +} 1.111 + 1.112 +size_t G1YoungGenSizer::calculate_default_max_length(size_t new_number_of_heap_regions) { 1.113 + size_t default_value = (new_number_of_heap_regions * G1DefaultMaxNewGenPercent) / 100; 1.114 + return MAX2((size_t)1, default_value); 1.115 +} 1.116 + 1.117 +void G1YoungGenSizer::heap_size_changed(size_t new_number_of_heap_regions) { 1.118 + assert(new_number_of_heap_regions > 0, "Heap must be initialized"); 1.119 + 1.120 + switch (_sizer_kind) { 1.121 + case SizerDefaults: 1.122 + _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); 1.123 + _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); 1.124 + break; 1.125 + case SizerNewSizeOnly: 1.126 + _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); 1.127 + _max_desired_young_length = MAX2(_min_desired_young_length, _max_desired_young_length); 1.128 + break; 1.129 + case SizerMaxNewSizeOnly: 1.130 + _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); 1.131 + _min_desired_young_length = MIN2(_min_desired_young_length, _max_desired_young_length); 1.132 + break; 1.133 + case SizerMaxAndNewSize: 1.134 + // Do nothing. Values set on the command line, don't update them at runtime. 1.135 + break; 1.136 + case SizerNewRatio: 1.137 + _min_desired_young_length = new_number_of_heap_regions / (NewRatio + 1); 1.138 + _max_desired_young_length = _min_desired_young_length; 1.139 + break; 1.140 + default: 1.141 + ShouldNotReachHere(); 1.142 + } 1.143 + 1.144 assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); 1.145 - 1.146 - set_adaptive_young_list_length(_min_desired_young_length < _max_desired_young_length); 1.147 +} 1.148 + 1.149 +void G1CollectorPolicy::init() { 1.150 + // Set aside an initial future to_space. 1.151 + _g1 = G1CollectedHeap::heap(); 1.152 + 1.153 + assert(Heap_lock->owned_by_self(), "Locking discipline."); 1.154 + 1.155 + initialize_gc_policy_counters(); 1.156 + 1.157 if (adaptive_young_list_length()) { 1.158 _young_list_fixed_length = 0; 1.159 } else { 1.160 - assert(_min_desired_young_length == _max_desired_young_length, "Min and max young size differ"); 1.161 - _young_list_fixed_length = _min_desired_young_length; 1.162 + _young_list_fixed_length = _young_gen_sizer->min_desired_young_length(); 1.163 } 1.164 _free_regions_at_end_of_collection = _g1->free_regions(); 1.165 update_young_list_target_length(); 1.166 @@ -543,11 +555,7 @@ 1.167 // smaller than 1.0) we'll get 1. 1.168 _reserve_regions = (size_t) ceil(reserve_regions_d); 1.169 1.170 - if (_using_new_ratio_calculations) { 1.171 - // -XX:NewRatio was specified so we need to update the 1.172 - // young gen length when the heap size has changed. 1.173 - update_young_list_size_using_newratio(new_number_of_regions); 1.174 - } 1.175 + _young_gen_sizer->heap_size_changed(new_number_of_regions); 1.176 } 1.177 1.178 size_t G1CollectorPolicy::calculate_young_list_desired_min_length( 1.179 @@ -565,14 +573,14 @@ 1.180 } 1.181 desired_min_length += base_min_length; 1.182 // make sure we don't go below any user-defined minimum bound 1.183 - return MAX2(_min_desired_young_length, desired_min_length); 1.184 + return MAX2(_young_gen_sizer->min_desired_young_length(), desired_min_length); 1.185 } 1.186 1.187 size_t G1CollectorPolicy::calculate_young_list_desired_max_length() { 1.188 // Here, we might want to also take into account any additional 1.189 // constraints (i.e., user-defined minimum bound). Currently, we 1.190 // effectively don't set this bound. 1.191 - return _max_desired_young_length; 1.192 + return _young_gen_sizer->max_desired_young_length(); 1.193 } 1.194 1.195 void G1CollectorPolicy::update_young_list_target_length(size_t rs_lengths) {
2.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Dec 14 13:34:57 2011 -0800 2.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Dec 21 22:13:31 2011 +0100 2.3 @@ -83,6 +83,72 @@ 2.4 virtual MainBodySummary* main_body_summary() { return this; } 2.5 }; 2.6 2.7 +// There are three command line options related to the young gen size: 2.8 +// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is 2.9 +// just a short form for NewSize==MaxNewSize). G1 will use its internal 2.10 +// heuristics to calculate the actual young gen size, so these options 2.11 +// basically only limit the range within which G1 can pick a young gen 2.12 +// size. Also, these are general options taking byte sizes. G1 will 2.13 +// internally work with a number of regions instead. So, some rounding 2.14 +// will occur. 2.15 +// 2.16 +// If nothing related to the the young gen size is set on the command 2.17 +// line we should allow the young gen to be between 2.18 +// G1DefaultMinNewGenPercent and G1DefaultMaxNewGenPercent of the 2.19 +// heap size. This means that every time the heap size changes the 2.20 +// limits for the young gen size will be updated. 2.21 +// 2.22 +// If only -XX:NewSize is set we should use the specified value as the 2.23 +// minimum size for young gen. Still using G1DefaultMaxNewGenPercent 2.24 +// of the heap as maximum. 2.25 +// 2.26 +// If only -XX:MaxNewSize is set we should use the specified value as the 2.27 +// maximum size for young gen. Still using G1DefaultMinNewGenPercent 2.28 +// of the heap as minimum. 2.29 +// 2.30 +// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values. 2.31 +// No updates when the heap size changes. There is a special case when 2.32 +// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a 2.33 +// different heuristic for calculating the collection set when we do mixed 2.34 +// collection. 2.35 +// 2.36 +// If only -XX:NewRatio is set we should use the specified ratio of the heap 2.37 +// as both min and max. This will be interpreted as "fixed" just like the 2.38 +// NewSize==MaxNewSize case above. But we will update the min and max 2.39 +// everytime the heap size changes. 2.40 +// 2.41 +// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is 2.42 +// combined with either NewSize or MaxNewSize. (A warning message is printed.) 2.43 +class G1YoungGenSizer : public CHeapObj { 2.44 +private: 2.45 + enum SizerKind { 2.46 + SizerDefaults, 2.47 + SizerNewSizeOnly, 2.48 + SizerMaxNewSizeOnly, 2.49 + SizerMaxAndNewSize, 2.50 + SizerNewRatio 2.51 + }; 2.52 + SizerKind _sizer_kind; 2.53 + size_t _min_desired_young_length; 2.54 + size_t _max_desired_young_length; 2.55 + bool _adaptive_size; 2.56 + size_t calculate_default_min_length(size_t new_number_of_heap_regions); 2.57 + size_t calculate_default_max_length(size_t new_number_of_heap_regions); 2.58 + 2.59 +public: 2.60 + G1YoungGenSizer(); 2.61 + void heap_size_changed(size_t new_number_of_heap_regions); 2.62 + size_t min_desired_young_length() { 2.63 + return _min_desired_young_length; 2.64 + } 2.65 + size_t max_desired_young_length() { 2.66 + return _max_desired_young_length; 2.67 + } 2.68 + bool adaptive_young_list_length() { 2.69 + return _adaptive_size; 2.70 + } 2.71 +}; 2.72 + 2.73 class G1CollectorPolicy: public CollectorPolicy { 2.74 private: 2.75 // either equal to the number of parallel threads, if ParallelGCThreads 2.76 @@ -167,9 +233,6 @@ 2.77 // indicates whether we are in young or mixed GC mode 2.78 bool _gcs_are_young; 2.79 2.80 - // if true, then it tries to dynamically adjust the length of the 2.81 - // young list 2.82 - bool _adaptive_young_list_length; 2.83 size_t _young_list_target_length; 2.84 size_t _young_list_fixed_length; 2.85 size_t _prev_eden_capacity; // used for logging 2.86 @@ -227,9 +290,7 @@ 2.87 2.88 TruncatedSeq* _young_gc_eff_seq; 2.89 2.90 - bool _using_new_ratio_calculations; 2.91 - size_t _min_desired_young_length; // as set on the command line or default calculations 2.92 - size_t _max_desired_young_length; // as set on the command line or default calculations 2.93 + G1YoungGenSizer* _young_gen_sizer; 2.94 2.95 size_t _eden_cset_region_length; 2.96 size_t _survivor_cset_region_length; 2.97 @@ -695,8 +756,6 @@ 2.98 // Count the number of bytes used in the CS. 2.99 void count_CS_bytes_used(); 2.100 2.101 - void update_young_list_size_using_newratio(size_t number_of_heap_regions); 2.102 - 2.103 public: 2.104 2.105 G1CollectorPolicy(); 2.106 @@ -723,8 +782,6 @@ 2.107 // This should be called after the heap is resized. 2.108 void record_new_heap_size(size_t new_number_of_regions); 2.109 2.110 -public: 2.111 - 2.112 void init(); 2.113 2.114 // Create jstat counters for the policy. 2.115 @@ -1014,10 +1071,7 @@ 2.116 } 2.117 2.118 bool adaptive_young_list_length() { 2.119 - return _adaptive_young_list_length; 2.120 - } 2.121 - void set_adaptive_young_list_length(bool adaptive_young_list_length) { 2.122 - _adaptive_young_list_length = adaptive_young_list_length; 2.123 + return _young_gen_sizer->adaptive_young_list_length(); 2.124 } 2.125 2.126 inline double get_gc_eff_factor() {
3.1 --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Dec 14 13:34:57 2011 -0800 3.2 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Dec 21 22:13:31 2011 +0100 3.3 @@ -289,7 +289,15 @@ 3.4 \ 3.5 develop(uintx, G1ConcMarkForceOverflow, 0, \ 3.6 "The number of times we'll force an overflow during " \ 3.7 - "concurrent marking") 3.8 + "concurrent marking") \ 3.9 + \ 3.10 + develop(uintx, G1DefaultMinNewGenPercent, 20, \ 3.11 + "Percentage (0-100) of the heap size to use as minimum " \ 3.12 + "young gen size.") \ 3.13 + \ 3.14 + develop(uintx, G1DefaultMaxNewGenPercent, 50, \ 3.15 + "Percentage (0-100) of the heap size to use as maximum " \ 3.16 + "young gen size.") 3.17 3.18 G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) 3.19