1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,392 @@ 1.4 +/* 1.5 + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 +#include "incls/_precompiled.incl" 1.28 +#include "incls/_adaptiveSizePolicy.cpp.incl" 1.29 + 1.30 +elapsedTimer AdaptiveSizePolicy::_minor_timer; 1.31 +elapsedTimer AdaptiveSizePolicy::_major_timer; 1.32 + 1.33 +// The throughput goal is implemented as 1.34 +// _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio)) 1.35 +// gc_cost_ratio is the ratio 1.36 +// application cost / gc cost 1.37 +// For example a gc_cost_ratio of 4 translates into a 1.38 +// throughput goal of .80 1.39 + 1.40 +AdaptiveSizePolicy::AdaptiveSizePolicy(size_t init_eden_size, 1.41 + size_t init_promo_size, 1.42 + size_t init_survivor_size, 1.43 + double gc_pause_goal_sec, 1.44 + uint gc_cost_ratio) : 1.45 + _eden_size(init_eden_size), 1.46 + _promo_size(init_promo_size), 1.47 + _survivor_size(init_survivor_size), 1.48 + _gc_pause_goal_sec(gc_pause_goal_sec), 1.49 + _throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))), 1.50 + _gc_time_limit_exceeded(false), 1.51 + _print_gc_time_limit_would_be_exceeded(false), 1.52 + _gc_time_limit_count(0), 1.53 + _latest_minor_mutator_interval_seconds(0), 1.54 + _threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0), 1.55 + _young_gen_change_for_minor_throughput(0), 1.56 + _old_gen_change_for_major_throughput(0) { 1.57 + _avg_minor_pause = 1.58 + new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding); 1.59 + _avg_minor_interval = new AdaptiveWeightedAverage(AdaptiveTimeWeight); 1.60 + _avg_minor_gc_cost = new AdaptiveWeightedAverage(AdaptiveTimeWeight); 1.61 + _avg_major_gc_cost = new AdaptiveWeightedAverage(AdaptiveTimeWeight); 1.62 + 1.63 + _avg_young_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight); 1.64 + _avg_old_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight); 1.65 + _avg_eden_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight); 1.66 + 1.67 + _avg_survived = new AdaptivePaddedAverage(AdaptiveSizePolicyWeight, 1.68 + SurvivorPadding); 1.69 + _avg_pretenured = new AdaptivePaddedNoZeroDevAverage( 1.70 + AdaptiveSizePolicyWeight, 1.71 + SurvivorPadding); 1.72 + 1.73 + _minor_pause_old_estimator = 1.74 + new LinearLeastSquareFit(AdaptiveSizePolicyWeight); 1.75 + _minor_pause_young_estimator = 1.76 + new LinearLeastSquareFit(AdaptiveSizePolicyWeight); 1.77 + _minor_collection_estimator = 1.78 + new LinearLeastSquareFit(AdaptiveSizePolicyWeight); 1.79 + _major_collection_estimator = 1.80 + new LinearLeastSquareFit(AdaptiveSizePolicyWeight); 1.81 + 1.82 + // Start the timers 1.83 + _minor_timer.start(); 1.84 + 1.85 + _young_gen_policy_is_ready = false; 1.86 +} 1.87 + 1.88 +bool AdaptiveSizePolicy::tenuring_threshold_change() const { 1.89 + return decrement_tenuring_threshold_for_gc_cost() || 1.90 + increment_tenuring_threshold_for_gc_cost() || 1.91 + decrement_tenuring_threshold_for_survivor_limit(); 1.92 +} 1.93 + 1.94 +void AdaptiveSizePolicy::minor_collection_begin() { 1.95 + // Update the interval time 1.96 + _minor_timer.stop(); 1.97 + // Save most recent collection time 1.98 + _latest_minor_mutator_interval_seconds = _minor_timer.seconds(); 1.99 + _minor_timer.reset(); 1.100 + _minor_timer.start(); 1.101 +} 1.102 + 1.103 +void AdaptiveSizePolicy::update_minor_pause_young_estimator( 1.104 + double minor_pause_in_ms) { 1.105 + double eden_size_in_mbytes = ((double)_eden_size)/((double)M); 1.106 + _minor_pause_young_estimator->update(eden_size_in_mbytes, 1.107 + minor_pause_in_ms); 1.108 +} 1.109 + 1.110 +void AdaptiveSizePolicy::minor_collection_end(GCCause::Cause gc_cause) { 1.111 + // Update the pause time. 1.112 + _minor_timer.stop(); 1.113 + 1.114 + if (gc_cause != GCCause::_java_lang_system_gc || 1.115 + UseAdaptiveSizePolicyWithSystemGC) { 1.116 + double minor_pause_in_seconds = _minor_timer.seconds(); 1.117 + double minor_pause_in_ms = minor_pause_in_seconds * MILLIUNITS; 1.118 + 1.119 + // Sample for performance counter 1.120 + _avg_minor_pause->sample(minor_pause_in_seconds); 1.121 + 1.122 + // Cost of collection (unit-less) 1.123 + double collection_cost = 0.0; 1.124 + if ((_latest_minor_mutator_interval_seconds > 0.0) && 1.125 + (minor_pause_in_seconds > 0.0)) { 1.126 + double interval_in_seconds = 1.127 + _latest_minor_mutator_interval_seconds + minor_pause_in_seconds; 1.128 + collection_cost = 1.129 + minor_pause_in_seconds / interval_in_seconds; 1.130 + _avg_minor_gc_cost->sample(collection_cost); 1.131 + // Sample for performance counter 1.132 + _avg_minor_interval->sample(interval_in_seconds); 1.133 + } 1.134 + 1.135 + // The policy does not have enough data until at least some 1.136 + // minor collections have been done. 1.137 + _young_gen_policy_is_ready = 1.138 + (_avg_minor_gc_cost->count() >= AdaptiveSizePolicyReadyThreshold); 1.139 + 1.140 + // Calculate variables used to estimate pause time vs. gen sizes 1.141 + double eden_size_in_mbytes = ((double)_eden_size)/((double)M); 1.142 + update_minor_pause_young_estimator(minor_pause_in_ms); 1.143 + update_minor_pause_old_estimator(minor_pause_in_ms); 1.144 + 1.145 + if (PrintAdaptiveSizePolicy && Verbose) { 1.146 + gclog_or_tty->print("AdaptiveSizePolicy::minor_collection_end: " 1.147 + "minor gc cost: %f average: %f", collection_cost, 1.148 + _avg_minor_gc_cost->average()); 1.149 + gclog_or_tty->print_cr(" minor pause: %f minor period %f", 1.150 + minor_pause_in_ms, 1.151 + _latest_minor_mutator_interval_seconds * MILLIUNITS); 1.152 + } 1.153 + 1.154 + // Calculate variable used to estimate collection cost vs. gen sizes 1.155 + assert(collection_cost >= 0.0, "Expected to be non-negative"); 1.156 + _minor_collection_estimator->update(eden_size_in_mbytes, collection_cost); 1.157 + } 1.158 + 1.159 + // Interval times use this timer to measure the mutator time. 1.160 + // Reset the timer after the GC pause. 1.161 + _minor_timer.reset(); 1.162 + _minor_timer.start(); 1.163 +} 1.164 + 1.165 +size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden, 1.166 + uint percent_change) { 1.167 + size_t eden_heap_delta; 1.168 + eden_heap_delta = cur_eden / 100 * percent_change; 1.169 + return eden_heap_delta; 1.170 +} 1.171 + 1.172 +size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden) { 1.173 + return eden_increment(cur_eden, YoungGenerationSizeIncrement); 1.174 +} 1.175 + 1.176 +size_t AdaptiveSizePolicy::eden_decrement(size_t cur_eden) { 1.177 + size_t eden_heap_delta = eden_increment(cur_eden) / 1.178 + AdaptiveSizeDecrementScaleFactor; 1.179 + return eden_heap_delta; 1.180 +} 1.181 + 1.182 +size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo, 1.183 + uint percent_change) { 1.184 + size_t promo_heap_delta; 1.185 + promo_heap_delta = cur_promo / 100 * percent_change; 1.186 + return promo_heap_delta; 1.187 +} 1.188 + 1.189 +size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo) { 1.190 + return promo_increment(cur_promo, TenuredGenerationSizeIncrement); 1.191 +} 1.192 + 1.193 +size_t AdaptiveSizePolicy::promo_decrement(size_t cur_promo) { 1.194 + size_t promo_heap_delta = promo_increment(cur_promo); 1.195 + promo_heap_delta = promo_heap_delta / AdaptiveSizeDecrementScaleFactor; 1.196 + return promo_heap_delta; 1.197 +} 1.198 + 1.199 +double AdaptiveSizePolicy::time_since_major_gc() const { 1.200 + _major_timer.stop(); 1.201 + double result = _major_timer.seconds(); 1.202 + _major_timer.start(); 1.203 + return result; 1.204 +} 1.205 + 1.206 +// Linear decay of major gc cost 1.207 +double AdaptiveSizePolicy::decaying_major_gc_cost() const { 1.208 + double major_interval = major_gc_interval_average_for_decay(); 1.209 + double major_gc_cost_average = major_gc_cost(); 1.210 + double decayed_major_gc_cost = major_gc_cost_average; 1.211 + if(time_since_major_gc() > 0.0) { 1.212 + decayed_major_gc_cost = major_gc_cost() * 1.213 + (((double) AdaptiveSizeMajorGCDecayTimeScale) * major_interval) 1.214 + / time_since_major_gc(); 1.215 + } 1.216 + 1.217 + // The decayed cost should always be smaller than the 1.218 + // average cost but the vagaries of finite arithmetic could 1.219 + // produce a larger value in decayed_major_gc_cost so protect 1.220 + // against that. 1.221 + return MIN2(major_gc_cost_average, decayed_major_gc_cost); 1.222 +} 1.223 + 1.224 +// Use a value of the major gc cost that has been decayed 1.225 +// by the factor 1.226 +// 1.227 +// average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale / 1.228 +// time-since-last-major-gc 1.229 +// 1.230 +// if the average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale 1.231 +// is less than time-since-last-major-gc. 1.232 +// 1.233 +// In cases where there are initial major gc's that 1.234 +// are of a relatively high cost but no later major 1.235 +// gc's, the total gc cost can remain high because 1.236 +// the major gc cost remains unchanged (since there are no major 1.237 +// gc's). In such a situation the value of the unchanging 1.238 +// major gc cost can keep the mutator throughput below 1.239 +// the goal when in fact the major gc cost is becoming diminishingly 1.240 +// small. Use the decaying gc cost only to decide whether to 1.241 +// adjust for throughput. Using it also to determine the adjustment 1.242 +// to be made for throughput also seems reasonable but there is 1.243 +// no test case to use to decide if it is the right thing to do 1.244 +// don't do it yet. 1.245 + 1.246 +double AdaptiveSizePolicy::decaying_gc_cost() const { 1.247 + double decayed_major_gc_cost = major_gc_cost(); 1.248 + double avg_major_interval = major_gc_interval_average_for_decay(); 1.249 + if (UseAdaptiveSizeDecayMajorGCCost && 1.250 + (AdaptiveSizeMajorGCDecayTimeScale > 0) && 1.251 + (avg_major_interval > 0.00)) { 1.252 + double time_since_last_major_gc = time_since_major_gc(); 1.253 + 1.254 + // Decay the major gc cost? 1.255 + if (time_since_last_major_gc > 1.256 + ((double) AdaptiveSizeMajorGCDecayTimeScale) * avg_major_interval) { 1.257 + 1.258 + // Decay using the time-since-last-major-gc 1.259 + decayed_major_gc_cost = decaying_major_gc_cost(); 1.260 + if (PrintGCDetails && Verbose) { 1.261 + gclog_or_tty->print_cr("\ndecaying_gc_cost: major interval average:" 1.262 + " %f time since last major gc: %f", 1.263 + avg_major_interval, time_since_last_major_gc); 1.264 + gclog_or_tty->print_cr(" major gc cost: %f decayed major gc cost: %f", 1.265 + major_gc_cost(), decayed_major_gc_cost); 1.266 + } 1.267 + } 1.268 + } 1.269 + double result = MIN2(1.0, decayed_major_gc_cost + minor_gc_cost()); 1.270 + return result; 1.271 +} 1.272 + 1.273 + 1.274 +void AdaptiveSizePolicy::clear_generation_free_space_flags() { 1.275 + set_change_young_gen_for_min_pauses(0); 1.276 + set_change_old_gen_for_maj_pauses(0); 1.277 + 1.278 + set_change_old_gen_for_throughput(0); 1.279 + set_change_young_gen_for_throughput(0); 1.280 + set_decrease_for_footprint(0); 1.281 + set_decide_at_full_gc(0); 1.282 +} 1.283 + 1.284 +// Printing 1.285 + 1.286 +bool AdaptiveSizePolicy::print_adaptive_size_policy_on(outputStream* st) const { 1.287 + 1.288 + // Should only be used with adaptive size policy turned on. 1.289 + // Otherwise, there may be variables that are undefined. 1.290 + if (!UseAdaptiveSizePolicy) return false; 1.291 + 1.292 + // Print goal for which action is needed. 1.293 + char* action = NULL; 1.294 + bool change_for_pause = false; 1.295 + if ((change_old_gen_for_maj_pauses() == 1.296 + decrease_old_gen_for_maj_pauses_true) || 1.297 + (change_young_gen_for_min_pauses() == 1.298 + decrease_young_gen_for_min_pauses_true)) { 1.299 + action = (char*) " *** pause time goal ***"; 1.300 + change_for_pause = true; 1.301 + } else if ((change_old_gen_for_throughput() == 1.302 + increase_old_gen_for_throughput_true) || 1.303 + (change_young_gen_for_throughput() == 1.304 + increase_young_gen_for_througput_true)) { 1.305 + action = (char*) " *** throughput goal ***"; 1.306 + } else if (decrease_for_footprint()) { 1.307 + action = (char*) " *** reduced footprint ***"; 1.308 + } else { 1.309 + // No actions were taken. This can legitimately be the 1.310 + // situation if not enough data has been gathered to make 1.311 + // decisions. 1.312 + return false; 1.313 + } 1.314 + 1.315 + // Pauses 1.316 + // Currently the size of the old gen is only adjusted to 1.317 + // change the major pause times. 1.318 + char* young_gen_action = NULL; 1.319 + char* tenured_gen_action = NULL; 1.320 + 1.321 + char* shrink_msg = (char*) "(attempted to shrink)"; 1.322 + char* grow_msg = (char*) "(attempted to grow)"; 1.323 + char* no_change_msg = (char*) "(no change)"; 1.324 + if (change_young_gen_for_min_pauses() == 1.325 + decrease_young_gen_for_min_pauses_true) { 1.326 + young_gen_action = shrink_msg; 1.327 + } else if (change_for_pause) { 1.328 + young_gen_action = no_change_msg; 1.329 + } 1.330 + 1.331 + if (change_old_gen_for_maj_pauses() == decrease_old_gen_for_maj_pauses_true) { 1.332 + tenured_gen_action = shrink_msg; 1.333 + } else if (change_for_pause) { 1.334 + tenured_gen_action = no_change_msg; 1.335 + } 1.336 + 1.337 + // Throughput 1.338 + if (change_old_gen_for_throughput() == increase_old_gen_for_throughput_true) { 1.339 + assert(change_young_gen_for_throughput() == 1.340 + increase_young_gen_for_througput_true, 1.341 + "Both generations should be growing"); 1.342 + young_gen_action = grow_msg; 1.343 + tenured_gen_action = grow_msg; 1.344 + } else if (change_young_gen_for_throughput() == 1.345 + increase_young_gen_for_througput_true) { 1.346 + // Only the young generation may grow at start up (before 1.347 + // enough full collections have been done to grow the old generation). 1.348 + young_gen_action = grow_msg; 1.349 + tenured_gen_action = no_change_msg; 1.350 + } 1.351 + 1.352 + // Minimum footprint 1.353 + if (decrease_for_footprint() != 0) { 1.354 + young_gen_action = shrink_msg; 1.355 + tenured_gen_action = shrink_msg; 1.356 + } 1.357 + 1.358 + st->print_cr(" UseAdaptiveSizePolicy actions to meet %s", action); 1.359 + st->print_cr(" GC overhead (%%)"); 1.360 + st->print_cr(" Young generation: %7.2f\t %s", 1.361 + 100.0 * avg_minor_gc_cost()->average(), 1.362 + young_gen_action); 1.363 + st->print_cr(" Tenured generation: %7.2f\t %s", 1.364 + 100.0 * avg_major_gc_cost()->average(), 1.365 + tenured_gen_action); 1.366 + return true; 1.367 +} 1.368 + 1.369 +bool AdaptiveSizePolicy::print_adaptive_size_policy_on( 1.370 + outputStream* st, 1.371 + int tenuring_threshold_arg) const { 1.372 + if (!AdaptiveSizePolicy::print_adaptive_size_policy_on(st)) { 1.373 + return false; 1.374 + } 1.375 + 1.376 + // Tenuring threshold 1.377 + bool tenuring_threshold_changed = true; 1.378 + if (decrement_tenuring_threshold_for_survivor_limit()) { 1.379 + st->print(" Tenuring threshold: (attempted to decrease to avoid" 1.380 + " survivor space overflow) = "); 1.381 + } else if (decrement_tenuring_threshold_for_gc_cost()) { 1.382 + st->print(" Tenuring threshold: (attempted to decrease to balance" 1.383 + " GC costs) = "); 1.384 + } else if (increment_tenuring_threshold_for_gc_cost()) { 1.385 + st->print(" Tenuring threshold: (attempted to increase to balance" 1.386 + " GC costs) = "); 1.387 + } else { 1.388 + tenuring_threshold_changed = false; 1.389 + assert(!tenuring_threshold_change(), "(no change was attempted)"); 1.390 + } 1.391 + if (tenuring_threshold_changed) { 1.392 + st->print_cr("%d", tenuring_threshold_arg); 1.393 + } 1.394 + return true; 1.395 +}