1 /* 2 * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "gc/g1/g1ConcurrentRefine.hpp" 27 #include "gc/g1/g1ConcurrentRefineThread.hpp" 28 #include "logging/log.hpp" 29 #include "runtime/java.hpp" 30 #include "runtime/thread.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 #include "utilities/pair.hpp" 34 #include <math.h> 35 36 // Arbitrary but large limits, to simplify some of the zone calculations. 37 // The general idea is to allow expressions like 38 // MIN2(x OP y, max_XXX_zone) 39 // without needing to check for overflow in "x OP y", because the 40 // ranges for x and y have been restricted. 41 STATIC_ASSERT(sizeof(LP64_ONLY(jint) NOT_LP64(jshort)) <= (sizeof(size_t)/2)); 42 const size_t max_yellow_zone = LP64_ONLY(max_jint) NOT_LP64(max_jshort); 43 const size_t max_green_zone = max_yellow_zone / 2; 44 const size_t max_red_zone = INT_MAX; // For dcqs.set_max_completed_queue. 45 STATIC_ASSERT(max_yellow_zone <= max_red_zone); 46 47 // Range check assertions for green zone values. 48 #define assert_zone_constraints_g(green) \ 49 do { \ 50 size_t azc_g_green = (green); \ 51 assert(azc_g_green <= max_green_zone, \ 52 "green exceeds max: " SIZE_FORMAT, azc_g_green); \ 53 } while (0) 54 55 // Range check assertions for green and yellow zone values. 56 #define assert_zone_constraints_gy(green, yellow) \ 57 do { \ 58 size_t azc_gy_green = (green); \ 59 size_t azc_gy_yellow = (yellow); \ 60 assert_zone_constraints_g(azc_gy_green); \ 61 assert(azc_gy_yellow <= max_yellow_zone, \ 62 "yellow exceeds max: " SIZE_FORMAT, azc_gy_yellow); \ 63 assert(azc_gy_green <= azc_gy_yellow, \ 64 "green (" SIZE_FORMAT ") exceeds yellow (" SIZE_FORMAT ")", \ 65 azc_gy_green, azc_gy_yellow); \ 66 } while (0) 67 68 // Range check assertions for green, yellow, and red zone values. 69 #define assert_zone_constraints_gyr(green, yellow, red) \ 70 do { \ 71 size_t azc_gyr_green = (green); \ 72 size_t azc_gyr_yellow = (yellow); \ 73 size_t azc_gyr_red = (red); \ 74 assert_zone_constraints_gy(azc_gyr_green, azc_gyr_yellow); \ 75 assert(azc_gyr_red <= max_red_zone, \ 76 "red exceeds max: " SIZE_FORMAT, azc_gyr_red); \ 77 assert(azc_gyr_yellow <= azc_gyr_red, \ 78 "yellow (" SIZE_FORMAT ") exceeds red (" SIZE_FORMAT ")", \ 79 azc_gyr_yellow, azc_gyr_red); \ 80 } while (0) 81 82 // Logging tag sequence for refinement control updates. 83 #define CTRL_TAGS gc, ergo, refine 84 85 // For logging zone values, ensuring consistency of level and tags. 86 #define LOG_ZONES(...) log_debug( CTRL_TAGS )(__VA_ARGS__) 87 88 // Package for pair of refinement thread activation and deactivation 89 // thresholds. The activation and deactivation levels are resp. the first 90 // and second values of the pair. 91 typedef Pair<size_t, size_t> Thresholds; 92 inline size_t activation_level(const Thresholds& t) { return t.first; } 93 inline size_t deactivation_level(const Thresholds& t) { return t.second; } 94 95 static Thresholds calc_thresholds(size_t green_zone, 96 size_t yellow_zone, 97 uint worker_i) { 98 double yellow_size = yellow_zone - green_zone; 99 double step = yellow_size / G1ConcurrentRefine::thread_num(); 100 if (worker_i == 0) { 101 // Potentially activate worker 0 more aggressively, to keep 102 // available buffers near green_zone value. When yellow_size is 103 // large we don't want to allow a full step to accumulate before 104 // doing any processing, as that might lead to significantly more 105 // than green_zone buffers to be processed by update_rs. 106 step = MIN2(step, ParallelGCThreads / 2.0); 107 } 108 size_t activate_offset = static_cast<size_t>(ceil(step * (worker_i + 1))); 109 size_t deactivate_offset = static_cast<size_t>(floor(step * worker_i)); 110 return Thresholds(green_zone + activate_offset, 111 green_zone + deactivate_offset); 112 } 113 114 G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone, 115 size_t yellow_zone, 116 size_t red_zone, 117 size_t min_yellow_zone_size) : 118 _threads(NULL), 119 _n_worker_threads(thread_num()), 120 _green_zone(green_zone), 121 _yellow_zone(yellow_zone), 122 _red_zone(red_zone), 123 _min_yellow_zone_size(min_yellow_zone_size) 124 { 125 assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone); 126 } 127 128 static size_t calc_min_yellow_zone_size() { 129 size_t step = G1ConcRefinementThresholdStep; 130 uint n_workers = G1ConcurrentRefine::thread_num(); 131 if ((max_yellow_zone / step) < n_workers) { 132 return max_yellow_zone; 133 } else { 134 return step * n_workers; 135 } 136 } 137 138 static size_t calc_init_green_zone() { 139 size_t green = G1ConcRefinementGreenZone; 140 if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { 141 green = ParallelGCThreads; 142 } 143 return MIN2(green, max_green_zone); 144 } 145 146 static size_t calc_init_yellow_zone(size_t green, size_t min_size) { 147 size_t config = G1ConcRefinementYellowZone; 148 size_t size = 0; 149 if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) { 150 size = green * 2; 151 } else if (green < config) { 152 size = config - green; 153 } 154 size = MAX2(size, min_size); 155 size = MIN2(size, max_yellow_zone); 156 return MIN2(green + size, max_yellow_zone); 157 } 158 159 static size_t calc_init_red_zone(size_t green, size_t yellow) { 160 size_t size = yellow - green; 161 if (!FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) { 162 size_t config = G1ConcRefinementRedZone; 163 if (yellow < config) { 164 size = MAX2(size, config - yellow); 165 } 166 } 167 return MIN2(yellow + size, max_red_zone); 168 } 169 170 G1ConcurrentRefine* G1ConcurrentRefine::create(jint* ecode) { 171 size_t min_yellow_zone_size = calc_min_yellow_zone_size(); 172 size_t green_zone = calc_init_green_zone(); 173 size_t yellow_zone = calc_init_yellow_zone(green_zone, min_yellow_zone_size); 174 size_t red_zone = calc_init_red_zone(green_zone, yellow_zone); 175 176 LOG_ZONES("Initial Refinement Zones: " 177 "green: " SIZE_FORMAT ", " 178 "yellow: " SIZE_FORMAT ", " 179 "red: " SIZE_FORMAT ", " 180 "min yellow size: " SIZE_FORMAT, 181 green_zone, yellow_zone, red_zone, min_yellow_zone_size); 182 183 G1ConcurrentRefine* cr = new G1ConcurrentRefine(green_zone, 184 yellow_zone, 185 red_zone, 186 min_yellow_zone_size); 187 188 if (cr == NULL) { 189 *ecode = JNI_ENOMEM; 190 vm_shutdown_during_initialization("Could not create G1ConcurrentRefine"); 191 return NULL; 192 } 193 194 cr->_threads = NEW_C_HEAP_ARRAY_RETURN_NULL(G1ConcurrentRefineThread*, cr->_n_worker_threads, mtGC); 195 if (cr->_threads == NULL) { 196 *ecode = JNI_ENOMEM; 197 vm_shutdown_during_initialization("Could not allocate an array for G1ConcurrentRefineThread"); 198 return NULL; 199 } 200 201 uint worker_id_offset = DirtyCardQueueSet::num_par_ids(); 202 203 G1ConcurrentRefineThread *next = NULL; 204 for (uint i = cr->_n_worker_threads - 1; i != UINT_MAX; i--) { 205 Thresholds thresholds = calc_thresholds(green_zone, yellow_zone, i); 206 G1ConcurrentRefineThread* t = 207 new G1ConcurrentRefineThread(cr, 208 next, 209 worker_id_offset, 210 i, 211 activation_level(thresholds), 212 deactivation_level(thresholds)); 213 assert(t != NULL, "Conc refine should have been created"); 214 if (t->osthread() == NULL) { 215 *ecode = JNI_ENOMEM; 216 vm_shutdown_during_initialization("Could not create G1ConcurrentRefineThread"); 217 return NULL; 218 } 219 220 assert(t->cr() == cr, "Conc refine thread should refer to this"); 221 cr->_threads[i] = t; 222 next = t; 223 } 224 225 *ecode = JNI_OK; 226 return cr; 227 } 228 229 void G1ConcurrentRefine::stop() { 230 for (uint i = 0; i < _n_worker_threads; i++) { 231 _threads[i]->stop(); 232 } 233 } 234 235 void G1ConcurrentRefine::update_thread_thresholds() { 236 for (uint i = 0; i < _n_worker_threads; i++) { 237 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, i); 238 _threads[i]->update_thresholds(activation_level(thresholds), 239 deactivation_level(thresholds)); 240 } 241 } 242 243 G1ConcurrentRefine::~G1ConcurrentRefine() { 244 for (uint i = 0; i < _n_worker_threads; i++) { 245 delete _threads[i]; 246 } 247 FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads); 248 } 249 250 void G1ConcurrentRefine::threads_do(ThreadClosure *tc) { 251 for (uint i = 0; i < _n_worker_threads; i++) { 252 tc->do_thread(_threads[i]); 253 } 254 } 255 256 uint G1ConcurrentRefine::thread_num() { 257 return G1ConcRefinementThreads; 258 } 259 260 void G1ConcurrentRefine::print_threads_on(outputStream* st) const { 261 for (uint i = 0; i < _n_worker_threads; ++i) { 262 _threads[i]->print_on(st); 263 st->cr(); 264 } 265 } 266 267 static size_t calc_new_green_zone(size_t green, 268 double update_rs_time, 269 size_t update_rs_processed_buffers, 270 double goal_ms) { 271 // Adjust green zone based on whether we're meeting the time goal. 272 // Limit to max_green_zone. 273 const double inc_k = 1.1, dec_k = 0.9; 274 if (update_rs_time > goal_ms) { 275 if (green > 0) { 276 green = static_cast<size_t>(green * dec_k); 277 } 278 } else if (update_rs_time < goal_ms && 279 update_rs_processed_buffers > green) { 280 green = static_cast<size_t>(MAX2(green * inc_k, green + 1.0)); 281 green = MIN2(green, max_green_zone); 282 } 283 return green; 284 } 285 286 static size_t calc_new_yellow_zone(size_t green, size_t min_yellow_size) { 287 size_t size = green * 2; 288 size = MAX2(size, min_yellow_size); 289 return MIN2(green + size, max_yellow_zone); 290 } 291 292 static size_t calc_new_red_zone(size_t green, size_t yellow) { 293 return MIN2(yellow + (yellow - green), max_red_zone); 294 } 295 296 void G1ConcurrentRefine::update_zones(double update_rs_time, 297 size_t update_rs_processed_buffers, 298 double goal_ms) { 299 log_trace( CTRL_TAGS )("Updating Refinement Zones: " 300 "update_rs time: %.3fms, " 301 "update_rs buffers: " SIZE_FORMAT ", " 302 "update_rs goal time: %.3fms", 303 update_rs_time, 304 update_rs_processed_buffers, 305 goal_ms); 306 307 _green_zone = calc_new_green_zone(_green_zone, 308 update_rs_time, 309 update_rs_processed_buffers, 310 goal_ms); 311 _yellow_zone = calc_new_yellow_zone(_green_zone, _min_yellow_zone_size); 312 _red_zone = calc_new_red_zone(_green_zone, _yellow_zone); 313 314 assert_zone_constraints_gyr(_green_zone, _yellow_zone, _red_zone); 315 LOG_ZONES("Updated Refinement Zones: " 316 "green: " SIZE_FORMAT ", " 317 "yellow: " SIZE_FORMAT ", " 318 "red: " SIZE_FORMAT, 319 _green_zone, _yellow_zone, _red_zone); 320 } 321 322 void G1ConcurrentRefine::adjust(double update_rs_time, 323 size_t update_rs_processed_buffers, 324 double goal_ms) { 325 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 326 327 if (G1UseAdaptiveConcRefinement) { 328 update_zones(update_rs_time, update_rs_processed_buffers, goal_ms); 329 update_thread_thresholds(); 330 331 // Change the barrier params 332 if (_n_worker_threads == 0) { 333 // Disable dcqs notification when there are no threads to notify. 334 dcqs.set_process_completed_threshold(INT_MAX); 335 } else { 336 // Worker 0 is the primary; wakeup is via dcqs notification. 337 STATIC_ASSERT(max_yellow_zone <= INT_MAX); 338 size_t activate = _threads[0]->activation_threshold(); 339 dcqs.set_process_completed_threshold((int)activate); 340 } 341 dcqs.set_max_completed_queue((int)red_zone()); 342 } 343 344 size_t curr_queue_size = dcqs.completed_buffers_num(); 345 if (curr_queue_size >= yellow_zone()) { 346 dcqs.set_completed_queue_padding(curr_queue_size); 347 } else { 348 dcqs.set_completed_queue_padding(0); 349 } 350 dcqs.notify_if_necessary(); 351 }