59 _collection_set_regions(NULL), |
59 _collection_set_regions(NULL), |
60 _collection_set_cur_length(0), |
60 _collection_set_cur_length(0), |
61 _collection_set_max_length(0), |
61 _collection_set_max_length(0), |
62 _num_optional_regions(0), |
62 _num_optional_regions(0), |
63 _bytes_used_before(0), |
63 _bytes_used_before(0), |
64 _recorded_rs_lengths(0), |
64 _recorded_rs_length(0), |
65 _inc_build_state(Inactive), |
65 _inc_build_state(Inactive), |
66 _inc_part_start(0), |
66 _inc_part_start(0), |
67 _inc_bytes_used_before(0), |
67 _inc_bytes_used_before(0), |
68 _inc_recorded_rs_lengths(0), |
68 _inc_recorded_rs_length(0), |
69 _inc_recorded_rs_lengths_diffs(0), |
69 _inc_recorded_rs_length_diff(0), |
70 _inc_predicted_elapsed_time_ms(0.0), |
70 _inc_predicted_elapsed_time_ms(0.0), |
71 _inc_predicted_elapsed_time_ms_diffs(0.0) { |
71 _inc_predicted_elapsed_time_ms_diff(0.0) { |
72 } |
72 } |
73 |
73 |
74 G1CollectionSet::~G1CollectionSet() { |
74 G1CollectionSet::~G1CollectionSet() { |
75 if (_collection_set_regions != NULL) { |
75 FREE_C_HEAP_ARRAY(uint, _collection_set_regions); |
76 FREE_C_HEAP_ARRAY(uint, _collection_set_regions); |
|
77 } |
|
78 free_optional_regions(); |
76 free_optional_regions(); |
79 clear_candidates(); |
77 clear_candidates(); |
80 } |
78 } |
81 |
79 |
82 void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, |
80 void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, |
146 assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); |
144 assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); |
147 assert(_inc_build_state == Inactive, "Precondition"); |
145 assert(_inc_build_state == Inactive, "Precondition"); |
148 |
146 |
149 _inc_bytes_used_before = 0; |
147 _inc_bytes_used_before = 0; |
150 |
148 |
151 _inc_recorded_rs_lengths = 0; |
149 _inc_recorded_rs_length = 0; |
152 _inc_recorded_rs_lengths_diffs = 0; |
150 _inc_recorded_rs_length_diff = 0; |
153 _inc_predicted_elapsed_time_ms = 0.0; |
151 _inc_predicted_elapsed_time_ms = 0.0; |
154 _inc_predicted_elapsed_time_ms_diffs = 0.0; |
152 _inc_predicted_elapsed_time_ms_diff = 0.0; |
155 |
153 |
156 update_incremental_marker(); |
154 update_incremental_marker(); |
157 } |
155 } |
158 |
156 |
159 void G1CollectionSet::finalize_incremental_building() { |
157 void G1CollectionSet::finalize_incremental_building() { |
160 assert(_inc_build_state == Active, "Precondition"); |
158 assert(_inc_build_state == Active, "Precondition"); |
161 assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); |
159 assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); |
162 |
160 |
163 // The two "main" fields, _inc_recorded_rs_lengths and |
161 // The two "main" fields, _inc_recorded_rs_length and |
164 // _inc_predicted_elapsed_time_ms, are updated by the thread |
162 // _inc_predicted_elapsed_time_ms, are updated by the thread |
165 // that adds a new region to the CSet. Further updates by the |
163 // that adds a new region to the CSet. Further updates by the |
166 // concurrent refinement thread that samples the young RSet lengths |
164 // concurrent refinement thread that samples the young RSet lengths |
167 // are accumulated in the *_diffs fields. Here we add the diffs to |
165 // are accumulated in the *_diff fields. Here we add the diffs to |
168 // the "main" fields. |
166 // the "main" fields. |
169 |
167 |
170 if (_inc_recorded_rs_lengths_diffs >= 0) { |
168 if (_inc_recorded_rs_length_diff >= 0) { |
171 _inc_recorded_rs_lengths += _inc_recorded_rs_lengths_diffs; |
169 _inc_recorded_rs_length += _inc_recorded_rs_length_diff; |
172 } else { |
170 } else { |
173 // This is defensive. The diff should in theory be always positive |
171 // This is defensive. The diff should in theory be always positive |
174 // as RSets can only grow between GCs. However, given that we |
172 // as RSets can only grow between GCs. However, given that we |
175 // sample their size concurrently with other threads updating them |
173 // sample their size concurrently with other threads updating them |
176 // it's possible that we might get the wrong size back, which |
174 // it's possible that we might get the wrong size back, which |
177 // could make the calculations somewhat inaccurate. |
175 // could make the calculations somewhat inaccurate. |
178 size_t diffs = (size_t) (-_inc_recorded_rs_lengths_diffs); |
176 size_t diffs = (size_t) (-_inc_recorded_rs_length_diff); |
179 if (_inc_recorded_rs_lengths >= diffs) { |
177 if (_inc_recorded_rs_length >= diffs) { |
180 _inc_recorded_rs_lengths -= diffs; |
178 _inc_recorded_rs_length -= diffs; |
181 } else { |
179 } else { |
182 _inc_recorded_rs_lengths = 0; |
180 _inc_recorded_rs_length = 0; |
183 } |
181 } |
184 } |
182 } |
185 _inc_predicted_elapsed_time_ms += _inc_predicted_elapsed_time_ms_diffs; |
183 _inc_predicted_elapsed_time_ms += _inc_predicted_elapsed_time_ms_diff; |
186 |
184 |
187 _inc_recorded_rs_lengths_diffs = 0; |
185 _inc_recorded_rs_length_diff = 0; |
188 _inc_predicted_elapsed_time_ms_diffs = 0.0; |
186 _inc_predicted_elapsed_time_ms_diff = 0.0; |
189 } |
187 } |
190 |
188 |
191 void G1CollectionSet::clear() { |
189 void G1CollectionSet::clear() { |
192 assert_at_safepoint_on_vm_thread(); |
190 assert_at_safepoint_on_vm_thread(); |
193 _collection_set_cur_length = 0; |
191 _collection_set_cur_length = 0; |
215 bool result = cl->do_heap_region(r); |
213 bool result = cl->do_heap_region(r); |
216 guarantee(!result, "Must not cancel iteration"); |
214 guarantee(!result, "Must not cancel iteration"); |
217 } |
215 } |
218 } |
216 } |
219 |
217 |
220 void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const { |
218 void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl, |
|
219 HeapRegionClaimer* hr_claimer, |
|
220 uint worker_id, |
|
221 uint total_workers) const { |
221 assert_at_safepoint(); |
222 assert_at_safepoint(); |
222 |
223 |
223 size_t len = _collection_set_cur_length - _inc_part_start; |
224 size_t len = increment_length(); |
224 if (len == 0) { |
225 if (len == 0) { |
225 return; |
226 return; |
226 } |
227 } |
227 |
228 |
228 size_t start_pos = (worker_id * len) / total_workers; |
229 size_t start_pos = (worker_id * len) / total_workers; |
229 size_t cur_pos = start_pos; |
230 size_t cur_pos = start_pos; |
230 |
231 |
231 do { |
232 do { |
232 HeapRegion* r = _g1h->region_at(_collection_set_regions[cur_pos + _inc_part_start]); |
233 uint region_idx = _collection_set_regions[cur_pos + _inc_part_start]; |
233 bool result = cl->do_heap_region(r); |
234 if (hr_claimer == NULL || hr_claimer->claim_region(region_idx)) { |
234 guarantee(!result, "Must not cancel iteration"); |
235 HeapRegion* r = _g1h->region_at(region_idx); |
|
236 bool result = cl->do_heap_region(r); |
|
237 guarantee(!result, "Must not cancel iteration"); |
|
238 } |
235 |
239 |
236 cur_pos++; |
240 cur_pos++; |
237 if (cur_pos == len) { |
241 if (cur_pos == len) { |
238 cur_pos = 0; |
242 cur_pos = 0; |
239 } |
243 } |
244 size_t new_rs_length) { |
248 size_t new_rs_length) { |
245 // Update the CSet information that is dependent on the new RS length |
249 // Update the CSet information that is dependent on the new RS length |
246 assert(hr->is_young(), "Precondition"); |
250 assert(hr->is_young(), "Precondition"); |
247 assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint"); |
251 assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint"); |
248 |
252 |
249 // We could have updated _inc_recorded_rs_lengths and |
253 // We could have updated _inc_recorded_rs_length and |
250 // _inc_predicted_elapsed_time_ms directly but we'd need to do |
254 // _inc_predicted_elapsed_time_ms directly but we'd need to do |
251 // that atomically, as this code is executed by a concurrent |
255 // that atomically, as this code is executed by a concurrent |
252 // refinement thread, potentially concurrently with a mutator thread |
256 // refinement thread, potentially concurrently with a mutator thread |
253 // allocating a new region and also updating the same fields. To |
257 // allocating a new region and also updating the same fields. To |
254 // avoid the atomic operations we accumulate these updates on two |
258 // avoid the atomic operations we accumulate these updates on two |
255 // separate fields (*_diffs) and we'll just add them to the "main" |
259 // separate fields (*_diff) and we'll just add them to the "main" |
256 // fields at the start of a GC. |
260 // fields at the start of a GC. |
257 |
261 |
258 ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); |
262 ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); |
259 ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length; |
263 ssize_t rs_length_diff = (ssize_t) new_rs_length - old_rs_length; |
260 _inc_recorded_rs_lengths_diffs += rs_lengths_diff; |
264 _inc_recorded_rs_length_diff += rs_length_diff; |
261 |
265 |
262 double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); |
266 double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); |
263 double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr); |
267 double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr); |
264 double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; |
268 double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; |
265 _inc_predicted_elapsed_time_ms_diffs += elapsed_ms_diff; |
269 _inc_predicted_elapsed_time_ms_diff += elapsed_ms_diff; |
266 |
270 |
267 hr->set_recorded_rs_length(new_rs_length); |
271 hr->set_recorded_rs_length(new_rs_length); |
268 hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); |
272 hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); |
269 } |
273 } |
270 |
274 |
271 void G1CollectionSet::add_young_region_common(HeapRegion* hr) { |
275 void G1CollectionSet::add_young_region_common(HeapRegion* hr) { |
272 assert(hr->is_young(), "invariant"); |
276 assert(hr->is_young(), "invariant"); |
273 assert(_inc_build_state == Active, "Precondition"); |
277 assert(_inc_build_state == Active, "Precondition"); |
274 |
278 |
275 size_t collection_set_length = _collection_set_cur_length; |
279 size_t collection_set_length = _collection_set_cur_length; |
276 assert(collection_set_length <= INT_MAX, "Collection set is too large with %d entries", (int)collection_set_length); |
280 // We use UINT_MAX as "invalid" marker in verification. |
277 hr->set_young_index_in_cset((int)collection_set_length); |
281 assert(collection_set_length < (UINT_MAX - 1), |
|
282 "Collection set is too large with " SIZE_FORMAT " entries", collection_set_length); |
|
283 hr->set_young_index_in_cset((uint)collection_set_length + 1); |
278 |
284 |
279 _collection_set_regions[collection_set_length] = hr->hrm_index(); |
285 _collection_set_regions[collection_set_length] = hr->hrm_index(); |
280 // Concurrent readers must observe the store of the value in the array before an |
286 // Concurrent readers must observe the store of the value in the array before an |
281 // update to the length field. |
287 // update to the length field. |
282 OrderAccess::storestore(); |
288 OrderAccess::storestore(); |
308 // the incremental collection set, or it is updated by the |
314 // the incremental collection set, or it is updated by the |
309 // rset sampling code |
315 // rset sampling code |
310 hr->set_recorded_rs_length(rs_length); |
316 hr->set_recorded_rs_length(rs_length); |
311 hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); |
317 hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); |
312 |
318 |
313 _inc_recorded_rs_lengths += rs_length; |
319 _inc_recorded_rs_length += rs_length; |
314 _inc_predicted_elapsed_time_ms += region_elapsed_time_ms; |
320 _inc_predicted_elapsed_time_ms += region_elapsed_time_ms; |
315 _inc_bytes_used_before += hr->used(); |
321 _inc_bytes_used_before += hr->used(); |
316 } |
322 } |
317 |
323 |
318 assert(!hr->in_collection_set(), "invariant"); |
324 assert(!hr->in_collection_set(), "invariant"); |
401 finalize_incremental_building(); |
407 finalize_incremental_building(); |
402 |
408 |
403 guarantee(target_pause_time_ms > 0.0, |
409 guarantee(target_pause_time_ms > 0.0, |
404 "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); |
410 "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); |
405 |
411 |
406 size_t pending_cards = _policy->pending_cards(); |
412 size_t pending_cards = _policy->pending_cards_at_gc_start(); |
407 double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards); |
413 double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards); |
408 double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); |
414 double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); |
409 |
415 |
410 log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms", |
416 log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms", |
411 pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); |
417 pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); |
429 log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms", |
435 log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms", |
430 eden_region_length, survivor_region_length, _inc_predicted_elapsed_time_ms, target_pause_time_ms); |
436 eden_region_length, survivor_region_length, _inc_predicted_elapsed_time_ms, target_pause_time_ms); |
431 |
437 |
432 // The number of recorded young regions is the incremental |
438 // The number of recorded young regions is the incremental |
433 // collection set's current size |
439 // collection set's current size |
434 set_recorded_rs_lengths(_inc_recorded_rs_lengths); |
440 set_recorded_rs_length(_inc_recorded_rs_length); |
435 |
441 |
436 double young_end_time_sec = os::elapsedTime(); |
442 double young_end_time_sec = os::elapsedTime(); |
437 phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0); |
443 phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0); |
438 |
444 |
439 return time_remaining_ms; |
445 return time_remaining_ms; |
517 move_candidates_to_collection_set(num_selected_regions); |
523 move_candidates_to_collection_set(num_selected_regions); |
518 |
524 |
519 _num_optional_regions -= num_selected_regions; |
525 _num_optional_regions -= num_selected_regions; |
520 |
526 |
521 stop_incremental_building(); |
527 stop_incremental_building(); |
|
528 |
|
529 _g1h->verify_region_attr_remset_update(); |
|
530 |
522 return num_selected_regions > 0; |
531 return num_selected_regions > 0; |
523 } |
532 } |
524 |
533 |
525 void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* pss) { |
534 void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* pss) { |
526 for (uint i = 0; i < _num_optional_regions; i++) { |
535 for (uint i = 0; i < _num_optional_regions; i++) { |
527 HeapRegion* r = candidates()->at(candidates()->cur_idx() + i); |
536 HeapRegion* r = candidates()->at(candidates()->cur_idx() + i); |
528 pss->record_unused_optional_region(r); |
537 pss->record_unused_optional_region(r); |
|
538 // Clear collection set marker and make sure that the remembered set information |
|
539 // is correct as we still need it later. |
529 _g1h->clear_region_attr(r); |
540 _g1h->clear_region_attr(r); |
|
541 _g1h->register_region_with_region_attr(r); |
530 r->clear_index_in_opt_cset(); |
542 r->clear_index_in_opt_cset(); |
531 } |
543 } |
532 free_optional_regions(); |
544 free_optional_regions(); |
|
545 |
|
546 _g1h->verify_region_attr_remset_update(); |
533 } |
547 } |
534 |
548 |
535 #ifdef ASSERT |
549 #ifdef ASSERT |
536 class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure { |
550 class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure { |
537 private: |
551 private: |
538 size_t _young_length; |
552 size_t _young_length; |
539 int* _heap_region_indices; |
553 uint* _heap_region_indices; |
540 public: |
554 public: |
541 G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) { |
555 G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) { |
542 _heap_region_indices = NEW_C_HEAP_ARRAY(int, young_length, mtGC); |
556 _heap_region_indices = NEW_C_HEAP_ARRAY(uint, young_length + 1, mtGC); |
543 for (size_t i = 0; i < young_length; i++) { |
557 for (size_t i = 0; i < young_length + 1; i++) { |
544 _heap_region_indices[i] = -1; |
558 _heap_region_indices[i] = UINT_MAX; |
545 } |
559 } |
546 } |
560 } |
547 ~G1VerifyYoungCSetIndicesClosure() { |
561 ~G1VerifyYoungCSetIndicesClosure() { |
548 FREE_C_HEAP_ARRAY(int, _heap_region_indices); |
562 FREE_C_HEAP_ARRAY(int, _heap_region_indices); |
549 } |
563 } |
550 |
564 |
551 virtual bool do_heap_region(HeapRegion* r) { |
565 virtual bool do_heap_region(HeapRegion* r) { |
552 const int idx = r->young_index_in_cset(); |
566 const uint idx = r->young_index_in_cset(); |
553 |
567 |
554 assert(idx > -1, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index()); |
568 assert(idx > 0, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index()); |
555 assert((size_t)idx < _young_length, "Young cset index too large for region %u", r->hrm_index()); |
569 assert(idx <= _young_length, "Young cset index %u too large for region %u", idx, r->hrm_index()); |
556 |
570 |
557 assert(_heap_region_indices[idx] == -1, |
571 assert(_heap_region_indices[idx] == UINT_MAX, |
558 "Index %d used by multiple regions, first use by region %u, second by region %u", |
572 "Index %d used by multiple regions, first use by region %u, second by region %u", |
559 idx, _heap_region_indices[idx], r->hrm_index()); |
573 idx, _heap_region_indices[idx], r->hrm_index()); |
560 |
574 |
561 _heap_region_indices[idx] = r->hrm_index(); |
575 _heap_region_indices[idx] = r->hrm_index(); |
562 |
576 |