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.
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;
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 }
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 }
|
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 G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl() :
37 _cg1r(NULL),
38 _threads(NULL),
39 _num_max_threads(0)
40 {
41 }
42
43 G1ConcurrentRefineThreadControl::~G1ConcurrentRefineThreadControl() {
44 for (uint i = 0; i < _num_max_threads; i++) {
45 G1ConcurrentRefineThread* t = _threads[i];
46 if (t != NULL) {
47 delete t;
48 }
49 }
50 FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
51 }
52
53 void G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cg1r, uint num_max_threads) {
54 assert(cg1r != NULL, "Passed g1ConcurrentRefine must not be NULL");
55 _cg1r = cg1r;
56 _num_max_threads = num_max_threads;
57 _threads = NEW_C_HEAP_ARRAY(G1ConcurrentRefineThread*, num_max_threads, mtGC);
58 for (uint i = 0; i < num_max_threads; i++) {
59 if (UseDynamicNumberOfGCThreads) {
60 _threads[i] = NULL;
61 } else {
62 _threads[i] = new G1ConcurrentRefineThread(_cg1r, i);
63 }
64 }
65 }
66
67 void G1ConcurrentRefineThreadControl::maybe_activate_next(uint cur_worker_id) {
68 assert(cur_worker_id < _num_max_threads, "Tried to activate from impossible thread %u", cur_worker_id);
69 if (cur_worker_id == (_num_max_threads - 1)) {
70 // Already the last thread, there is no more thread to activate.
71 return;
72 }
73
74 uint worker_id = cur_worker_id + 1;
75 G1ConcurrentRefineThread* thread_to_activate = _threads[worker_id];
76 if (thread_to_activate == NULL) {
77 // Still need to create the thread...
78 _threads[worker_id] = new G1ConcurrentRefineThread(_cg1r, worker_id);
79 thread_to_activate = _threads[worker_id];
80 }
81 thread_to_activate->activate();
82 }
83
84 void G1ConcurrentRefineThreadControl::print_on(outputStream* st) const {
85 for (uint i = 0; i < _num_max_threads; ++i) {
86 if (_threads[i] != NULL) {
87 _threads[i]->print_on(st);
88 st->cr();
89 }
90 }
91 }
92
93 void G1ConcurrentRefineThreadControl::worker_threads_do(ThreadClosure* tc) {
94 for (uint i = 0; i < _num_max_threads; i++) {
95 if (_threads[i] != NULL) {
96 tc->do_thread(_threads[i]);
97 }
98 }
99 }
100
101 void G1ConcurrentRefineThreadControl::stop() {
102 for (uint i = 0; i < _num_max_threads; i++) {
103 if (_threads[i] != NULL) {
104 _threads[i]->stop();
105 }
106 }
107 }
108
109 // Arbitrary but large limits, to simplify some of the zone calculations.
110 // The general idea is to allow expressions like
111 // MIN2(x OP y, max_XXX_zone)
112 // without needing to check for overflow in "x OP y", because the
113 // ranges for x and y have been restricted.
114 STATIC_ASSERT(sizeof(LP64_ONLY(jint) NOT_LP64(jshort)) <= (sizeof(size_t)/2));
115 const size_t max_yellow_zone = LP64_ONLY(max_jint) NOT_LP64(max_jshort);
116 const size_t max_green_zone = max_yellow_zone / 2;
117 const size_t max_red_zone = INT_MAX; // For dcqs.set_max_completed_queue.
118 STATIC_ASSERT(max_yellow_zone <= max_red_zone);
119
120 // Range check assertions for green zone values.
121 #define assert_zone_constraints_g(green) \
122 do { \
123 size_t azc_g_green = (green); \
124 assert(azc_g_green <= max_green_zone, \
125 "green exceeds max: " SIZE_FORMAT, azc_g_green); \
126 } while (0)
127
128 // Range check assertions for green and yellow zone values.
152 azc_gyr_yellow, azc_gyr_red); \
153 } while (0)
154
155 // Logging tag sequence for refinement control updates.
156 #define CTRL_TAGS gc, ergo, refine
157
158 // For logging zone values, ensuring consistency of level and tags.
159 #define LOG_ZONES(...) log_debug( CTRL_TAGS )(__VA_ARGS__)
160
161 // Package for pair of refinement thread activation and deactivation
162 // thresholds. The activation and deactivation levels are resp. the first
163 // and second values of the pair.
164 typedef Pair<size_t, size_t> Thresholds;
165 inline size_t activation_level(const Thresholds& t) { return t.first; }
166 inline size_t deactivation_level(const Thresholds& t) { return t.second; }
167
168 static Thresholds calc_thresholds(size_t green_zone,
169 size_t yellow_zone,
170 uint worker_i) {
171 double yellow_size = yellow_zone - green_zone;
172 double step = yellow_size / G1ConcurrentRefine::max_num_threads();
173 if (worker_i == 0) {
174 // Potentially activate worker 0 more aggressively, to keep
175 // available buffers near green_zone value. When yellow_size is
176 // large we don't want to allow a full step to accumulate before
177 // doing any processing, as that might lead to significantly more
178 // than green_zone buffers to be processed by update_rs.
179 step = MIN2(step, ParallelGCThreads / 2.0);
180 }
181 size_t activate_offset = static_cast<size_t>(ceil(step * (worker_i + 1)));
182 size_t deactivate_offset = static_cast<size_t>(floor(step * worker_i));
183 return Thresholds(green_zone + activate_offset,
184 green_zone + deactivate_offset);
185 }
186
187 G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
188 size_t yellow_zone,
189 size_t red_zone,
190 size_t min_yellow_zone_size) :
191 _thread_control(),
192 _green_zone(green_zone),
193 _yellow_zone(yellow_zone),
194 _red_zone(red_zone),
195 _min_yellow_zone_size(min_yellow_zone_size)
196 {
197 assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone);
198 _thread_control.initialize(this, max_num_threads());
199 }
200
201 static size_t calc_min_yellow_zone_size() {
202 size_t step = G1ConcRefinementThresholdStep;
203 uint n_workers = G1ConcurrentRefine::max_num_threads();
204 if ((max_yellow_zone / step) < n_workers) {
205 return max_yellow_zone;
206 } else {
207 return step * n_workers;
208 }
209 }
210
211 static size_t calc_init_green_zone() {
212 size_t green = G1ConcRefinementGreenZone;
213 if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
214 green = ParallelGCThreads;
215 }
216 return MIN2(green, max_green_zone);
217 }
218
219 static size_t calc_init_yellow_zone(size_t green, size_t min_size) {
220 size_t config = G1ConcRefinementYellowZone;
221 size_t size = 0;
222 if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) {
223 size = green * 2;
247 size_t red_zone = calc_init_red_zone(green_zone, yellow_zone);
248
249 LOG_ZONES("Initial Refinement Zones: "
250 "green: " SIZE_FORMAT ", "
251 "yellow: " SIZE_FORMAT ", "
252 "red: " SIZE_FORMAT ", "
253 "min yellow size: " SIZE_FORMAT,
254 green_zone, yellow_zone, red_zone, min_yellow_zone_size);
255
256 G1ConcurrentRefine* cr = new G1ConcurrentRefine(green_zone,
257 yellow_zone,
258 red_zone,
259 min_yellow_zone_size);
260
261 if (cr == NULL) {
262 *ecode = JNI_ENOMEM;
263 vm_shutdown_during_initialization("Could not create G1ConcurrentRefine");
264 return NULL;
265 }
266
267 *ecode = JNI_OK;
268 return cr;
269 }
270
271 void G1ConcurrentRefine::stop() {
272 _thread_control.stop();
273 }
274
275 G1ConcurrentRefine::~G1ConcurrentRefine() {
276 }
277
278 void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
279 _thread_control.worker_threads_do(tc);
280 }
281
282 uint G1ConcurrentRefine::max_num_threads() {
283 return G1ConcRefinementThreads;
284 }
285
286 void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
287 _thread_control.print_on(st);
288 }
289
290 static size_t calc_new_green_zone(size_t green,
291 double update_rs_time,
292 size_t update_rs_processed_buffers,
293 double goal_ms) {
294 // Adjust green zone based on whether we're meeting the time goal.
295 // Limit to max_green_zone.
296 const double inc_k = 1.1, dec_k = 0.9;
297 if (update_rs_time > goal_ms) {
298 if (green > 0) {
299 green = static_cast<size_t>(green * dec_k);
300 }
301 } else if (update_rs_time < goal_ms &&
302 update_rs_processed_buffers > green) {
303 green = static_cast<size_t>(MAX2(green * inc_k, green + 1.0));
304 green = MIN2(green, max_green_zone);
305 }
306 return green;
307 }
332 update_rs_processed_buffers,
333 goal_ms);
334 _yellow_zone = calc_new_yellow_zone(_green_zone, _min_yellow_zone_size);
335 _red_zone = calc_new_red_zone(_green_zone, _yellow_zone);
336
337 assert_zone_constraints_gyr(_green_zone, _yellow_zone, _red_zone);
338 LOG_ZONES("Updated Refinement Zones: "
339 "green: " SIZE_FORMAT ", "
340 "yellow: " SIZE_FORMAT ", "
341 "red: " SIZE_FORMAT,
342 _green_zone, _yellow_zone, _red_zone);
343 }
344
345 void G1ConcurrentRefine::adjust(double update_rs_time,
346 size_t update_rs_processed_buffers,
347 double goal_ms) {
348 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
349
350 if (G1UseAdaptiveConcRefinement) {
351 update_zones(update_rs_time, update_rs_processed_buffers, goal_ms);
352
353 // Change the barrier params
354 if (max_num_threads() == 0) {
355 // Disable dcqs notification when there are no threads to notify.
356 dcqs.set_process_completed_threshold(INT_MAX);
357 } else {
358 // Worker 0 is the primary; wakeup is via dcqs notification.
359 STATIC_ASSERT(max_yellow_zone <= INT_MAX);
360 size_t activate = activation_threshold(0);
361 dcqs.set_process_completed_threshold((int)activate);
362 }
363 dcqs.set_max_completed_queue((int)red_zone());
364 }
365
366 size_t curr_queue_size = dcqs.completed_buffers_num();
367 if (curr_queue_size >= yellow_zone()) {
368 dcqs.set_completed_queue_padding(curr_queue_size);
369 } else {
370 dcqs.set_completed_queue_padding(0);
371 }
372 dcqs.notify_if_necessary();
373 }
374
375 size_t G1ConcurrentRefine::activation_threshold(uint worker_id) const {
376 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
377 return activation_level(thresholds);
378 }
379
380 size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const {
381 Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
382 return deactivation_level(thresholds);
383 }
384
385 uint G1ConcurrentRefine::worker_id_offset() {
386 return DirtyCardQueueSet::num_par_ids();
387 }
388
389 void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers) {
390 if (activation_threshold(worker_id + 1) > num_cur_buffers) {
391 _thread_control.maybe_activate_next(worker_id);
392 }
393 }
394
395 bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
396 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
397
398 size_t curr_buffer_num = dcqs.completed_buffers_num();
399 // If the number of the buffers falls down into the yellow zone,
400 // that means that the transition period after the evacuation pause has ended.
401 // Since the value written to the DCQS is the same for all threads, there is no
402 // need to synchronize.
403 if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= yellow_zone()) {
404 dcqs.set_completed_queue_padding(0);
405 }
406
407 maybe_activate_more_threads(worker_id, curr_buffer_num);
408
409 // Process the next buffer, if there are enough left.
410 return dcqs.refine_completed_buffer_concurrently(worker_id + worker_id_offset(),
411 deactivation_threshold(worker_id));
412 }
|