128 }
129 }
130 }
131
132 void G1ConcurrentRefineThreadControl::stop() {
133 for (uint i = 0; i < _num_max_threads; i++) {
134 if (_threads[i] != NULL) {
135 _threads[i]->stop();
136 }
137 }
138 }
139
140 // Arbitrary but large limits, to simplify some of the zone calculations.
141 // The general idea is to allow expressions like
142 // MIN2(x OP y, max_XXX_zone)
143 // without needing to check for overflow in "x OP y", because the
144 // ranges for x and y have been restricted.
145 STATIC_ASSERT(sizeof(LP64_ONLY(jint) NOT_LP64(jshort)) <= (sizeof(size_t)/2));
146 const size_t max_yellow_zone = LP64_ONLY(max_jint) NOT_LP64(max_jshort);
147 const size_t max_green_zone = max_yellow_zone / 2;
148 const size_t max_red_zone = INT_MAX; // For dcqs.set_max_completed_buffers.
149 STATIC_ASSERT(max_yellow_zone <= max_red_zone);
150
151 // Range check assertions for green zone values.
152 #define assert_zone_constraints_g(green) \
153 do { \
154 size_t azc_g_green = (green); \
155 assert(azc_g_green <= max_green_zone, \
156 "green exceeds max: " SIZE_FORMAT, azc_g_green); \
157 } while (0)
158
159 // Range check assertions for green and yellow zone values.
160 #define assert_zone_constraints_gy(green, yellow) \
161 do { \
162 size_t azc_gy_green = (green); \
163 size_t azc_gy_yellow = (yellow); \
164 assert_zone_constraints_g(azc_gy_green); \
165 assert(azc_gy_yellow <= max_yellow_zone, \
166 "yellow exceeds max: " SIZE_FORMAT, azc_gy_yellow); \
167 assert(azc_gy_green <= azc_gy_yellow, \
168 "green (" SIZE_FORMAT ") exceeds yellow (" SIZE_FORMAT ")", \
215 green_zone + deactivate_offset);
216 }
217
218 G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
219 size_t yellow_zone,
220 size_t red_zone,
221 size_t min_yellow_zone_size) :
222 _thread_control(),
223 _green_zone(green_zone),
224 _yellow_zone(yellow_zone),
225 _red_zone(red_zone),
226 _min_yellow_zone_size(min_yellow_zone_size)
227 {
228 assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone);
229 }
230
231 jint G1ConcurrentRefine::initialize() {
232 return _thread_control.initialize(this, max_num_threads());
233 }
234
235 static size_t calc_min_yellow_zone_size() {
236 size_t step = G1ConcRefinementThresholdStep;
237 uint n_workers = G1ConcurrentRefine::max_num_threads();
238 if ((max_yellow_zone / step) < n_workers) {
239 return max_yellow_zone;
240 } else {
241 return step * n_workers;
242 }
243 }
244
245 static size_t calc_init_green_zone() {
246 size_t green = G1ConcRefinementGreenZone;
247 if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
248 green = ParallelGCThreads;
249 }
250 return MIN2(green, max_green_zone);
251 }
252
253 static size_t calc_init_yellow_zone(size_t green, size_t min_size) {
254 size_t config = G1ConcRefinementYellowZone;
255 size_t size = 0;
256 if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) {
257 size = green * 2;
258 } else if (green < config) {
259 size = config - green;
260 }
261 size = MAX2(size, min_size);
262 size = MIN2(size, max_yellow_zone);
263 return MIN2(green + size, max_yellow_zone);
264 }
265
266 static size_t calc_init_red_zone(size_t green, size_t yellow) {
267 size_t size = yellow - green;
268 if (!FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) {
269 size_t config = G1ConcRefinementRedZone;
270 if (yellow < config) {
271 size = MAX2(size, config - yellow);
272 }
273 }
274 return MIN2(yellow + size, max_red_zone);
275 }
276
277 G1ConcurrentRefine* G1ConcurrentRefine::create(jint* ecode) {
278 size_t min_yellow_zone_size = calc_min_yellow_zone_size();
279 size_t green_zone = calc_init_green_zone();
280 size_t yellow_zone = calc_init_yellow_zone(green_zone, min_yellow_zone_size);
281 size_t red_zone = calc_init_red_zone(green_zone, yellow_zone);
282
283 LOG_ZONES("Initial Refinement Zones: "
284 "green: " SIZE_FORMAT ", "
285 "yellow: " SIZE_FORMAT ", "
286 "red: " SIZE_FORMAT ", "
287 "min yellow size: " SIZE_FORMAT,
288 green_zone, yellow_zone, red_zone, min_yellow_zone_size);
289
305 void G1ConcurrentRefine::stop() {
306 _thread_control.stop();
307 }
308
309 G1ConcurrentRefine::~G1ConcurrentRefine() {
310 }
311
312 void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
313 _thread_control.worker_threads_do(tc);
314 }
315
316 uint G1ConcurrentRefine::max_num_threads() {
317 return G1ConcRefinementThreads;
318 }
319
320 void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
321 _thread_control.print_on(st);
322 }
323
324 static size_t calc_new_green_zone(size_t green,
325 double log_buffer_scan_time,
326 size_t processed_log_buffers,
327 double goal_ms) {
328 // Adjust green zone based on whether we're meeting the time goal.
329 // Limit to max_green_zone.
330 const double inc_k = 1.1, dec_k = 0.9;
331 if (log_buffer_scan_time > goal_ms) {
332 if (green > 0) {
333 green = static_cast<size_t>(green * dec_k);
334 }
335 } else if (log_buffer_scan_time < goal_ms &&
336 processed_log_buffers > green) {
337 green = static_cast<size_t>(MAX2(green * inc_k, green + 1.0));
338 green = MIN2(green, max_green_zone);
339 }
340 return green;
341 }
342
343 static size_t calc_new_yellow_zone(size_t green, size_t min_yellow_size) {
344 size_t size = green * 2;
345 size = MAX2(size, min_yellow_size);
346 return MIN2(green + size, max_yellow_zone);
347 }
348
349 static size_t calc_new_red_zone(size_t green, size_t yellow) {
350 return MIN2(yellow + (yellow - green), max_red_zone);
351 }
352
353 void G1ConcurrentRefine::update_zones(double log_buffer_scan_time,
354 size_t processed_log_buffers,
355 double goal_ms) {
356 log_trace( CTRL_TAGS )("Updating Refinement Zones: "
357 "log buffer scan time: %.3fms, "
358 "processed buffers: " SIZE_FORMAT ", "
359 "goal time: %.3fms",
360 log_buffer_scan_time,
361 processed_log_buffers,
362 goal_ms);
363
364 _green_zone = calc_new_green_zone(_green_zone,
365 log_buffer_scan_time,
366 processed_log_buffers,
367 goal_ms);
368 _yellow_zone = calc_new_yellow_zone(_green_zone, _min_yellow_zone_size);
369 _red_zone = calc_new_red_zone(_green_zone, _yellow_zone);
370
371 assert_zone_constraints_gyr(_green_zone, _yellow_zone, _red_zone);
372 LOG_ZONES("Updated Refinement Zones: "
373 "green: " SIZE_FORMAT ", "
374 "yellow: " SIZE_FORMAT ", "
375 "red: " SIZE_FORMAT,
376 _green_zone, _yellow_zone, _red_zone);
377 }
378
379 void G1ConcurrentRefine::adjust(double log_buffer_scan_time,
380 size_t processed_log_buffers,
381 double goal_ms) {
382 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
383
384 if (G1UseAdaptiveConcRefinement) {
385 update_zones(log_buffer_scan_time, processed_log_buffers, goal_ms);
386
387 // Change the barrier params
388 if (max_num_threads() == 0) {
389 // Disable dcqs notification when there are no threads to notify.
390 dcqs.set_process_completed_buffers_threshold(G1DirtyCardQueueSet::ProcessCompletedBuffersThresholdNever);
391 } else {
392 // Worker 0 is the primary; wakeup is via dcqs notification.
393 STATIC_ASSERT(max_yellow_zone <= INT_MAX);
394 size_t activate = activation_threshold(0);
395 dcqs.set_process_completed_buffers_threshold(activate);
396 }
397 dcqs.set_max_completed_buffers(red_zone());
398 }
399
400 size_t curr_queue_size = dcqs.num_completed_buffers();
401 if ((dcqs.max_completed_buffers() > 0) &&
402 (curr_queue_size >= yellow_zone())) {
403 dcqs.set_completed_buffers_padding(curr_queue_size);
404 } else {
405 dcqs.set_completed_buffers_padding(0);
406 }
407 dcqs.notify_if_necessary();
408 }
409
410 size_t G1ConcurrentRefine::activation_threshold(uint worker_id) const {
411 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
412 return activation_level(thresholds);
413 }
414
415 size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const {
416 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
417 return deactivation_level(thresholds);
418 }
419
420 uint G1ConcurrentRefine::worker_id_offset() {
421 return G1DirtyCardQueueSet::num_par_ids();
422 }
423
424 void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers) {
425 if (num_cur_buffers > activation_threshold(worker_id + 1)) {
426 _thread_control.maybe_activate_next(worker_id);
427 }
428 }
429
430 bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
431 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
432
433 size_t curr_buffer_num = dcqs.num_completed_buffers();
434 // If the number of the buffers falls down into the yellow zone,
435 // that means that the transition period after the evacuation pause has ended.
436 // Since the value written to the DCQS is the same for all threads, there is no
437 // need to synchronize.
438 if (dcqs.completed_buffers_padding() > 0 && curr_buffer_num <= yellow_zone()) {
439 dcqs.set_completed_buffers_padding(0);
440 }
441
442 maybe_activate_more_threads(worker_id, curr_buffer_num);
443
444 // Process the next buffer, if there are enough left.
445 return dcqs.refine_completed_buffer_concurrently(worker_id + worker_id_offset(),
446 deactivation_threshold(worker_id));
447 }
|
128 }
129 }
130 }
131
132 void G1ConcurrentRefineThreadControl::stop() {
133 for (uint i = 0; i < _num_max_threads; i++) {
134 if (_threads[i] != NULL) {
135 _threads[i]->stop();
136 }
137 }
138 }
139
140 // Arbitrary but large limits, to simplify some of the zone calculations.
141 // The general idea is to allow expressions like
142 // MIN2(x OP y, max_XXX_zone)
143 // without needing to check for overflow in "x OP y", because the
144 // ranges for x and y have been restricted.
145 STATIC_ASSERT(sizeof(LP64_ONLY(jint) NOT_LP64(jshort)) <= (sizeof(size_t)/2));
146 const size_t max_yellow_zone = LP64_ONLY(max_jint) NOT_LP64(max_jshort);
147 const size_t max_green_zone = max_yellow_zone / 2;
148 const size_t max_red_zone = INT_MAX; // For dcqs.set_max_cards.
149 STATIC_ASSERT(max_yellow_zone <= max_red_zone);
150
151 // Range check assertions for green zone values.
152 #define assert_zone_constraints_g(green) \
153 do { \
154 size_t azc_g_green = (green); \
155 assert(azc_g_green <= max_green_zone, \
156 "green exceeds max: " SIZE_FORMAT, azc_g_green); \
157 } while (0)
158
159 // Range check assertions for green and yellow zone values.
160 #define assert_zone_constraints_gy(green, yellow) \
161 do { \
162 size_t azc_gy_green = (green); \
163 size_t azc_gy_yellow = (yellow); \
164 assert_zone_constraints_g(azc_gy_green); \
165 assert(azc_gy_yellow <= max_yellow_zone, \
166 "yellow exceeds max: " SIZE_FORMAT, azc_gy_yellow); \
167 assert(azc_gy_green <= azc_gy_yellow, \
168 "green (" SIZE_FORMAT ") exceeds yellow (" SIZE_FORMAT ")", \
215 green_zone + deactivate_offset);
216 }
217
218 G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
219 size_t yellow_zone,
220 size_t red_zone,
221 size_t min_yellow_zone_size) :
222 _thread_control(),
223 _green_zone(green_zone),
224 _yellow_zone(yellow_zone),
225 _red_zone(red_zone),
226 _min_yellow_zone_size(min_yellow_zone_size)
227 {
228 assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone);
229 }
230
231 jint G1ConcurrentRefine::initialize() {
232 return _thread_control.initialize(this, max_num_threads());
233 }
234
235 static size_t buffers_to_cards(size_t value) {
236 return value * G1UpdateBufferSize;
237 }
238
239 static size_t calc_min_yellow_zone_size() {
240 size_t step = buffers_to_cards(G1ConcRefinementThresholdStep);
241 uint n_workers = G1ConcurrentRefine::max_num_threads();
242 if ((max_yellow_zone / step) < n_workers) {
243 return max_yellow_zone;
244 } else {
245 return step * n_workers;
246 }
247 }
248
249 static size_t calc_init_green_zone() {
250 size_t green = G1ConcRefinementGreenZone;
251 if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
252 green = ParallelGCThreads;
253 }
254 green = buffers_to_cards(green);
255 return MIN2(green, max_green_zone);
256 }
257
258 static size_t calc_init_yellow_zone(size_t green, size_t min_size) {
259 size_t config = buffers_to_cards(G1ConcRefinementYellowZone);
260 size_t size = 0;
261 if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) {
262 size = green * 2;
263 } else if (green < config) {
264 size = config - green;
265 }
266 size = MAX2(size, min_size);
267 size = MIN2(size, max_yellow_zone);
268 return MIN2(green + size, max_yellow_zone);
269 }
270
271 static size_t calc_init_red_zone(size_t green, size_t yellow) {
272 size_t size = yellow - green;
273 if (!FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) {
274 size_t config = buffers_to_cards(G1ConcRefinementRedZone);
275 if (yellow < config) {
276 size = MAX2(size, config - yellow);
277 }
278 }
279 return MIN2(yellow + size, max_red_zone);
280 }
281
282 G1ConcurrentRefine* G1ConcurrentRefine::create(jint* ecode) {
283 size_t min_yellow_zone_size = calc_min_yellow_zone_size();
284 size_t green_zone = calc_init_green_zone();
285 size_t yellow_zone = calc_init_yellow_zone(green_zone, min_yellow_zone_size);
286 size_t red_zone = calc_init_red_zone(green_zone, yellow_zone);
287
288 LOG_ZONES("Initial Refinement Zones: "
289 "green: " SIZE_FORMAT ", "
290 "yellow: " SIZE_FORMAT ", "
291 "red: " SIZE_FORMAT ", "
292 "min yellow size: " SIZE_FORMAT,
293 green_zone, yellow_zone, red_zone, min_yellow_zone_size);
294
310 void G1ConcurrentRefine::stop() {
311 _thread_control.stop();
312 }
313
314 G1ConcurrentRefine::~G1ConcurrentRefine() {
315 }
316
317 void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
318 _thread_control.worker_threads_do(tc);
319 }
320
321 uint G1ConcurrentRefine::max_num_threads() {
322 return G1ConcRefinementThreads;
323 }
324
325 void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
326 _thread_control.print_on(st);
327 }
328
329 static size_t calc_new_green_zone(size_t green,
330 double logged_cards_scan_time,
331 size_t processed_logged_cards,
332 double goal_ms) {
333 // Adjust green zone based on whether we're meeting the time goal.
334 // Limit to max_green_zone.
335 const double inc_k = 1.1, dec_k = 0.9;
336 if (logged_cards_scan_time > goal_ms) {
337 if (green > 0) {
338 green = static_cast<size_t>(green * dec_k);
339 }
340 } else if (logged_cards_scan_time < goal_ms &&
341 processed_logged_cards > green) {
342 green = static_cast<size_t>(MAX2(green * inc_k, green + 1.0));
343 green = MIN2(green, max_green_zone);
344 }
345 return green;
346 }
347
348 static size_t calc_new_yellow_zone(size_t green, size_t min_yellow_size) {
349 size_t size = green * 2;
350 size = MAX2(size, min_yellow_size);
351 return MIN2(green + size, max_yellow_zone);
352 }
353
354 static size_t calc_new_red_zone(size_t green, size_t yellow) {
355 return MIN2(yellow + (yellow - green), max_red_zone);
356 }
357
358 void G1ConcurrentRefine::update_zones(double logged_cards_scan_time,
359 size_t processed_logged_cards,
360 double goal_ms) {
361 log_trace( CTRL_TAGS )("Updating Refinement Zones: "
362 "logged cards scan time: %.3fms, "
363 "processed cards: " SIZE_FORMAT ", "
364 "goal time: %.3fms",
365 logged_cards_scan_time,
366 processed_logged_cards,
367 goal_ms);
368
369 _green_zone = calc_new_green_zone(_green_zone,
370 logged_cards_scan_time,
371 processed_logged_cards,
372 goal_ms);
373 _yellow_zone = calc_new_yellow_zone(_green_zone, _min_yellow_zone_size);
374 _red_zone = calc_new_red_zone(_green_zone, _yellow_zone);
375
376 assert_zone_constraints_gyr(_green_zone, _yellow_zone, _red_zone);
377 LOG_ZONES("Updated Refinement Zones: "
378 "green: " SIZE_FORMAT ", "
379 "yellow: " SIZE_FORMAT ", "
380 "red: " SIZE_FORMAT,
381 _green_zone, _yellow_zone, _red_zone);
382 }
383
384 void G1ConcurrentRefine::adjust(double logged_cards_scan_time,
385 size_t processed_logged_cards,
386 double goal_ms) {
387 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
388
389 if (G1UseAdaptiveConcRefinement) {
390 update_zones(logged_cards_scan_time, processed_logged_cards, goal_ms);
391
392 // Change the barrier params
393 if (max_num_threads() == 0) {
394 // Disable dcqs notification when there are no threads to notify.
395 dcqs.set_process_cards_threshold(G1DirtyCardQueueSet::ProcessCardsThresholdNever);
396 } else {
397 // Worker 0 is the primary; wakeup is via dcqs notification.
398 STATIC_ASSERT(max_yellow_zone <= INT_MAX);
399 size_t activate = activation_threshold(0);
400 dcqs.set_process_cards_threshold(activate);
401 }
402 dcqs.set_max_cards(red_zone());
403 }
404
405 size_t curr_queue_size = dcqs.num_cards();
406 if ((dcqs.max_cards() > 0) &&
407 (curr_queue_size >= yellow_zone())) {
408 dcqs.set_max_cards_padding(curr_queue_size);
409 } else {
410 dcqs.set_max_cards_padding(0);
411 }
412 dcqs.notify_if_necessary();
413 }
414
415 size_t G1ConcurrentRefine::activation_threshold(uint worker_id) const {
416 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
417 return activation_level(thresholds);
418 }
419
420 size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const {
421 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
422 return deactivation_level(thresholds);
423 }
424
425 uint G1ConcurrentRefine::worker_id_offset() {
426 return G1DirtyCardQueueSet::num_par_ids();
427 }
428
429 void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers) {
430 if (num_cur_buffers > activation_threshold(worker_id + 1)) {
431 _thread_control.maybe_activate_next(worker_id);
432 }
433 }
434
435 bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
436 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
437
438 size_t curr_cards = dcqs.num_cards();
439 // If the number of the cards falls down into the yellow zone,
440 // that means that the transition period after the evacuation pause has ended.
441 // Since the value written to the DCQS is the same for all threads, there is no
442 // need to synchronize.
443 if (dcqs.max_cards_padding() > 0 && curr_cards <= yellow_zone()) {
444 dcqs.set_max_cards_padding(0);
445 }
446
447 maybe_activate_more_threads(worker_id, curr_cards);
448
449 // Process the next buffer, if there are enough left.
450 return dcqs.refine_completed_buffer_concurrently(worker_id + worker_id_offset(),
451 deactivation_threshold(worker_id));
452 }
|