50 #include "utilities/align.hpp" |
53 #include "utilities/align.hpp" |
51 #include "utilities/globalDefinitions.hpp" |
54 #include "utilities/globalDefinitions.hpp" |
52 #include "utilities/stack.inline.hpp" |
55 #include "utilities/stack.inline.hpp" |
53 #include "utilities/ticks.hpp" |
56 #include "utilities/ticks.hpp" |
54 |
57 |
55 // Collects information about the overall remembered set scan progress during an evacuation. |
58 // Collects information about the overall heap root scan progress during an evacuation. |
|
59 // |
|
60 // Scanning the remembered sets works by first merging all sources of cards to be |
|
61 // scanned (log buffers, hcc, remembered sets) into a single data structure to remove |
|
62 // duplicates and simplify work distribution. |
|
63 // |
|
64 // During the following card scanning we not only scan this combined set of cards, but |
|
65 // also remember that these were completely scanned. The following evacuation passes |
|
66 // do not scan these cards again, and so need to be preserved across increments. |
|
67 // |
|
68 // The representation for all the cards to scan is the card table: cards can have |
|
69 // one of three states during GC: |
|
70 // - clean: these cards will not be scanned in this pass |
|
71 // - dirty: these cards will be scanned in this pass |
|
72 // - scanned: these cards have already been scanned in a previous pass |
|
73 // |
|
74 // After all evacuation is done, we reset the card table to clean. |
|
75 // |
|
76 // Work distribution occurs on "chunk" basis, i.e. contiguous ranges of cards. As an |
|
77 // additional optimization, during card merging we remember which regions and which |
|
78 // chunks actually contain cards to be scanned. Threads iterate only across these |
|
79 // regions, and only compete for chunks containing any cards. |
|
80 // |
|
81 // Within these chunks, a worker scans the card table on "blocks" of cards, i.e. |
|
82 // contiguous ranges of dirty cards to be scanned. These blocks are converted to actual |
|
83 // memory ranges and then passed on to actual scanning. |
56 class G1RemSetScanState : public CHeapObj<mtGC> { |
84 class G1RemSetScanState : public CHeapObj<mtGC> { |
|
85 class G1DirtyRegions; |
|
86 |
|
87 size_t _max_regions; |
|
88 |
|
89 // Has this region that is part of the regions in the collection set been processed yet. |
|
90 typedef bool G1RemsetIterState; |
|
91 |
|
92 G1RemsetIterState volatile* _collection_set_iter_state; |
|
93 |
|
94 // Card table iteration claim for each heap region, from 0 (completely unscanned) |
|
95 // to (>=) HeapRegion::CardsPerRegion (completely scanned). |
|
96 uint volatile* _card_table_scan_state; |
|
97 |
|
98 // Return "optimal" number of chunks per region we want to use for claiming areas |
|
99 // within a region to claim. Dependent on the region size as proxy for the heap |
|
100 // size, we limit the total number of chunks to limit memory usage and maintenance |
|
101 // effort of that table vs. granularity of distributing scanning work. |
|
102 // Testing showed that 8 for 1M/2M region, 16 for 4M/8M regions, 32 for 16/32M regions |
|
103 // seems to be such a good trade-off. |
|
104 static uint get_chunks_per_region(uint log_region_size) { |
|
105 // Limit the expected input values to current known possible values of the |
|
106 // (log) region size. Adjust as necessary after testing if changing the permissible |
|
107 // values for region size. |
|
108 assert(log_region_size >= 20 && log_region_size <= 25, |
|
109 "expected value in [20,25], but got %u", log_region_size); |
|
110 return 1u << (log_region_size / 2 - 7); |
|
111 } |
|
112 |
|
113 uint _scan_chunks_per_region; // Number of chunks per region. |
|
114 uint8_t _log_scan_chunks_per_region; // Log of number of chunks per region. |
|
115 bool* _region_scan_chunks; |
|
116 size_t _num_total_scan_chunks; // Total number of elements in _region_scan_chunks. |
|
117 uint8_t _scan_chunks_shift; // For conversion between card index and chunk index. |
|
118 public: |
|
119 uint scan_chunk_size() const { return (uint)1 << _scan_chunks_shift; } |
|
120 |
|
121 // Returns whether the chunk corresponding to the given region/card in region contain a |
|
122 // dirty card, i.e. actually needs scanning. |
|
123 bool chunk_needs_scan(uint const region_idx, uint const card_in_region) const { |
|
124 size_t const idx = ((size_t)region_idx << _log_scan_chunks_per_region) + (card_in_region >> _scan_chunks_shift); |
|
125 assert(idx < _num_total_scan_chunks, "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT, |
|
126 idx, _num_total_scan_chunks); |
|
127 return _region_scan_chunks[idx]; |
|
128 } |
|
129 |
57 private: |
130 private: |
58 class G1ClearCardTableTask : public AbstractGangTask { |
131 // The complete set of regions which card table needs to be cleared at the end of GC because |
59 G1CollectedHeap* _g1h; |
132 // we scribbled all over them. |
60 uint* _dirty_region_list; |
133 G1DirtyRegions* _all_dirty_regions; |
61 size_t _num_dirty_regions; |
134 // The set of regions which card table needs to be scanned for new dirty cards |
62 size_t _chunk_length; |
135 // in the current evacuation pass. |
63 |
136 G1DirtyRegions* _next_dirty_regions; |
64 size_t volatile _cur_dirty_regions; |
137 |
|
138 // Set of (unique) regions that can be added to concurrently. |
|
139 class G1DirtyRegions : public CHeapObj<mtGC> { |
|
140 uint* _buffer; |
|
141 uint _cur_idx; |
|
142 size_t _max_regions; |
|
143 |
|
144 bool* _contains; |
|
145 |
65 public: |
146 public: |
66 G1ClearCardTableTask(G1CollectedHeap* g1h, |
147 G1DirtyRegions(size_t max_regions) : |
67 uint* dirty_region_list, |
148 _buffer(NEW_C_HEAP_ARRAY(uint, max_regions, mtGC)), |
68 size_t num_dirty_regions, |
149 _cur_idx(0), |
69 size_t chunk_length) : |
150 _max_regions(max_regions), |
70 AbstractGangTask("G1 Clear Card Table Task"), |
151 _contains(NEW_C_HEAP_ARRAY(bool, max_regions, mtGC)) { |
71 _g1h(g1h), |
152 |
72 _dirty_region_list(dirty_region_list), |
153 reset(); |
73 _num_dirty_regions(num_dirty_regions), |
|
74 _chunk_length(chunk_length), |
|
75 _cur_dirty_regions(0) { |
|
76 |
|
77 assert(chunk_length > 0, "must be"); |
|
78 } |
154 } |
79 |
155 |
80 static size_t chunk_size() { return M; } |
156 static size_t chunk_size() { return M; } |
81 |
157 |
82 void work(uint worker_id) { |
158 ~G1DirtyRegions() { |
83 while (_cur_dirty_regions < _num_dirty_regions) { |
159 FREE_C_HEAP_ARRAY(uint, _buffer); |
84 size_t next = Atomic::add(_chunk_length, &_cur_dirty_regions) - _chunk_length; |
160 FREE_C_HEAP_ARRAY(bool, _contains); |
85 size_t max = MIN2(next + _chunk_length, _num_dirty_regions); |
161 } |
86 |
162 |
87 for (size_t i = next; i < max; i++) { |
163 void reset() { |
88 HeapRegion* r = _g1h->region_at(_dirty_region_list[i]); |
164 _cur_idx = 0; |
89 if (!r->is_survivor()) { |
165 ::memset(_contains, false, _max_regions * sizeof(bool)); |
90 r->clear_cardtable(); |
166 } |
91 } |
167 |
|
168 uint size() const { return _cur_idx; } |
|
169 |
|
170 uint at(uint idx) const { |
|
171 assert(idx < _cur_idx, "Index %u beyond valid regions", idx); |
|
172 return _buffer[idx]; |
|
173 } |
|
174 |
|
175 void add_dirty_region(uint region) { |
|
176 if (_contains[region]) { |
|
177 return; |
|
178 } |
|
179 |
|
180 bool marked_as_dirty = Atomic::cmpxchg(true, &_contains[region], false) == false; |
|
181 if (marked_as_dirty) { |
|
182 uint allocated = Atomic::add(1u, &_cur_idx) - 1; |
|
183 _buffer[allocated] = region; |
|
184 } |
|
185 } |
|
186 |
|
187 // Creates the union of this and the other G1DirtyRegions. |
|
188 void merge(const G1DirtyRegions* other) { |
|
189 for (uint i = 0; i < other->size(); i++) { |
|
190 uint region = other->at(i); |
|
191 if (!_contains[region]) { |
|
192 _buffer[_cur_idx++] = region; |
|
193 _contains[region] = true; |
92 } |
194 } |
93 } |
195 } |
94 } |
196 } |
95 }; |
197 }; |
96 |
|
97 size_t _max_regions; |
|
98 |
|
99 // Scan progress for the remembered set of a single region. Transitions from |
|
100 // Unclaimed -> Claimed -> Complete. |
|
101 // At each of the transitions the thread that does the transition needs to perform |
|
102 // some special action once. This is the reason for the extra "Claimed" state. |
|
103 typedef jint G1RemsetIterState; |
|
104 |
|
105 static const G1RemsetIterState Unclaimed = 0; // The remembered set has not been scanned yet. |
|
106 static const G1RemsetIterState Claimed = 1; // The remembered set is currently being scanned. |
|
107 static const G1RemsetIterState Complete = 2; // The remembered set has been completely scanned. |
|
108 |
|
109 G1RemsetIterState volatile* _iter_states; |
|
110 // The current location where the next thread should continue scanning in a region's |
|
111 // remembered set. |
|
112 size_t volatile* _iter_claims; |
|
113 |
|
114 // Temporary buffer holding the regions we used to store remembered set scan duplicate |
|
115 // information. These are also called "dirty". Valid entries are from [0.._cur_dirty_region) |
|
116 uint* _dirty_region_buffer; |
|
117 |
|
118 // Flag for every region whether it is in the _dirty_region_buffer already |
|
119 // to avoid duplicates. |
|
120 bool volatile* _in_dirty_region_buffer; |
|
121 size_t _cur_dirty_region; |
|
122 |
198 |
123 // Creates a snapshot of the current _top values at the start of collection to |
199 // Creates a snapshot of the current _top values at the start of collection to |
124 // filter out card marks that we do not want to scan. |
200 // filter out card marks that we do not want to scan. |
125 class G1ResetScanTopClosure : public HeapRegionClosure { |
201 class G1ResetScanTopClosure : public HeapRegionClosure { |
126 private: |
202 G1RemSetScanState* _scan_state; |
127 HeapWord** _scan_top; |
203 |
128 public: |
204 public: |
129 G1ResetScanTopClosure(HeapWord** scan_top) : _scan_top(scan_top) { } |
205 G1ResetScanTopClosure(G1RemSetScanState* scan_state) : _scan_state(scan_state) { } |
130 |
206 |
131 virtual bool do_heap_region(HeapRegion* r) { |
207 virtual bool do_heap_region(HeapRegion* r) { |
132 uint hrm_index = r->hrm_index(); |
208 uint hrm_index = r->hrm_index(); |
133 if (!r->in_collection_set() && r->is_old_or_humongous_or_archive() && !r->is_empty()) { |
209 if (r->in_collection_set()) { |
134 _scan_top[hrm_index] = r->top(); |
210 // Young regions had their card table marked as young at their allocation; |
135 } else { |
211 // we need to make sure that these marks are cleared at the end of GC, *but* |
136 _scan_top[hrm_index] = NULL; |
212 // they should not be scanned for cards. |
137 } |
213 // So directly add them to the "all_dirty_regions". |
138 return false; |
214 // Same for regions in the (initial) collection set: they may contain cards from |
139 } |
215 // the log buffers, make sure they are cleaned. |
|
216 _scan_state->add_all_dirty_region(hrm_index); |
|
217 } else if (r->is_old_or_humongous_or_archive()) { |
|
218 _scan_state->set_scan_top(hrm_index, r->top()); |
|
219 } |
|
220 return false; |
|
221 } |
140 }; |
222 }; |
141 |
|
142 // For each region, contains the maximum top() value to be used during this garbage |
223 // For each region, contains the maximum top() value to be used during this garbage |
143 // collection. Subsumes common checks like filtering out everything but old and |
224 // collection. Subsumes common checks like filtering out everything but old and |
144 // humongous regions outside the collection set. |
225 // humongous regions outside the collection set. |
145 // This is valid because we are not interested in scanning stray remembered set |
226 // This is valid because we are not interested in scanning stray remembered set |
146 // entries from free or archive regions. |
227 // entries from free or archive regions. |
147 HeapWord** _scan_top; |
228 HeapWord** _scan_top; |
|
229 |
|
230 class G1ClearCardTableTask : public AbstractGangTask { |
|
231 G1CollectedHeap* _g1h; |
|
232 G1DirtyRegions* _regions; |
|
233 uint _chunk_length; |
|
234 |
|
235 uint volatile _cur_dirty_regions; |
|
236 |
|
237 G1RemSetScanState* _scan_state; |
|
238 |
|
239 public: |
|
240 G1ClearCardTableTask(G1CollectedHeap* g1h, |
|
241 G1DirtyRegions* regions, |
|
242 uint chunk_length, |
|
243 G1RemSetScanState* scan_state) : |
|
244 AbstractGangTask("G1 Clear Card Table Task"), |
|
245 _g1h(g1h), |
|
246 _regions(regions), |
|
247 _chunk_length(chunk_length), |
|
248 _cur_dirty_regions(0), |
|
249 _scan_state(scan_state) { |
|
250 |
|
251 assert(chunk_length > 0, "must be"); |
|
252 } |
|
253 |
|
254 static uint chunk_size() { return M; } |
|
255 |
|
256 void work(uint worker_id) { |
|
257 while (_cur_dirty_regions < _regions->size()) { |
|
258 uint next = Atomic::add(_chunk_length, &_cur_dirty_regions) - _chunk_length; |
|
259 uint max = MIN2(next + _chunk_length, _regions->size()); |
|
260 |
|
261 for (uint i = next; i < max; i++) { |
|
262 HeapRegion* r = _g1h->region_at(_regions->at(i)); |
|
263 if (!r->is_survivor()) { |
|
264 r->clear_cardtable(); |
|
265 } |
|
266 } |
|
267 } |
|
268 } |
|
269 }; |
|
270 |
|
271 // Clear the card table of "dirty" regions. |
|
272 void clear_card_table(WorkGang* workers) { |
|
273 uint num_regions = _all_dirty_regions->size(); |
|
274 |
|
275 if (num_regions == 0) { |
|
276 return; |
|
277 } |
|
278 |
|
279 uint const num_chunks = (uint)(align_up((size_t)num_regions << HeapRegion::LogCardsPerRegion, G1ClearCardTableTask::chunk_size()) / G1ClearCardTableTask::chunk_size()); |
|
280 uint const num_workers = MIN2(num_chunks, workers->active_workers()); |
|
281 uint const chunk_length = G1ClearCardTableTask::chunk_size() / (uint)HeapRegion::CardsPerRegion; |
|
282 |
|
283 // Iterate over the dirty cards region list. |
|
284 G1ClearCardTableTask cl(G1CollectedHeap::heap(), _all_dirty_regions, chunk_length, this); |
|
285 |
|
286 log_debug(gc, ergo)("Running %s using %u workers for %u " |
|
287 "units of work for %u regions.", |
|
288 cl.name(), num_workers, num_chunks, num_regions); |
|
289 workers->run_task(&cl, num_workers); |
|
290 |
|
291 #ifndef PRODUCT |
|
292 G1CollectedHeap::heap()->verifier()->verify_card_table_cleanup(); |
|
293 #endif |
|
294 } |
|
295 |
148 public: |
296 public: |
149 G1RemSetScanState() : |
297 G1RemSetScanState() : |
150 _max_regions(0), |
298 _max_regions(0), |
151 _iter_states(NULL), |
299 _collection_set_iter_state(NULL), |
152 _iter_claims(NULL), |
300 _card_table_scan_state(NULL), |
153 _dirty_region_buffer(NULL), |
301 _scan_chunks_per_region(get_chunks_per_region(HeapRegion::LogOfHRGrainBytes)), |
154 _in_dirty_region_buffer(NULL), |
302 _log_scan_chunks_per_region(log2_uint(_scan_chunks_per_region)), |
155 _cur_dirty_region(0), |
303 _region_scan_chunks(NULL), |
|
304 _num_total_scan_chunks(0), |
|
305 _scan_chunks_shift(0), |
|
306 _all_dirty_regions(NULL), |
|
307 _next_dirty_regions(NULL), |
156 _scan_top(NULL) { |
308 _scan_top(NULL) { |
157 } |
309 } |
158 |
310 |
159 ~G1RemSetScanState() { |
311 ~G1RemSetScanState() { |
160 if (_iter_states != NULL) { |
312 FREE_C_HEAP_ARRAY(G1RemsetIterState, _collection_set_iter_state); |
161 FREE_C_HEAP_ARRAY(G1RemsetIterState, _iter_states); |
313 FREE_C_HEAP_ARRAY(uint, _card_table_scan_state); |
162 } |
314 FREE_C_HEAP_ARRAY(bool, _region_scan_chunks); |
163 if (_iter_claims != NULL) { |
315 FREE_C_HEAP_ARRAY(HeapWord*, _scan_top); |
164 FREE_C_HEAP_ARRAY(size_t, _iter_claims); |
316 } |
165 } |
317 |
166 if (_dirty_region_buffer != NULL) { |
318 void initialize(size_t max_regions) { |
167 FREE_C_HEAP_ARRAY(uint, _dirty_region_buffer); |
319 assert(_collection_set_iter_state == NULL, "Must not be initialized twice"); |
168 } |
|
169 if (_in_dirty_region_buffer != NULL) { |
|
170 FREE_C_HEAP_ARRAY(bool, _in_dirty_region_buffer); |
|
171 } |
|
172 if (_scan_top != NULL) { |
|
173 FREE_C_HEAP_ARRAY(HeapWord*, _scan_top); |
|
174 } |
|
175 } |
|
176 |
|
177 void initialize(uint max_regions) { |
|
178 assert(_iter_states == NULL, "Must not be initialized twice"); |
|
179 assert(_iter_claims == NULL, "Must not be initialized twice"); |
|
180 _max_regions = max_regions; |
320 _max_regions = max_regions; |
181 _iter_states = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC); |
321 _collection_set_iter_state = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC); |
182 _iter_claims = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC); |
322 _card_table_scan_state = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); |
183 _dirty_region_buffer = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); |
323 _num_total_scan_chunks = max_regions * _scan_chunks_per_region; |
184 _in_dirty_region_buffer = NEW_C_HEAP_ARRAY(bool, max_regions, mtGC); |
324 _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, _num_total_scan_chunks, mtGC); |
|
325 |
|
326 _scan_chunks_shift = (uint8_t)log2_intptr(HeapRegion::CardsPerRegion / _scan_chunks_per_region); |
185 _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC); |
327 _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC); |
186 } |
328 } |
187 |
329 |
188 void reset() { |
330 void prepare() { |
189 for (uint i = 0; i < _max_regions; i++) { |
331 for (size_t i = 0; i < _max_regions; i++) { |
190 _iter_states[i] = Unclaimed; |
332 _collection_set_iter_state[i] = false; |
191 clear_scan_top(i); |
333 clear_scan_top((uint)i); |
192 } |
334 } |
193 |
335 |
194 G1ResetScanTopClosure cl(_scan_top); |
336 _all_dirty_regions = new G1DirtyRegions(_max_regions); |
|
337 _next_dirty_regions = new G1DirtyRegions(_max_regions); |
|
338 |
|
339 G1ResetScanTopClosure cl(this); |
195 G1CollectedHeap::heap()->heap_region_iterate(&cl); |
340 G1CollectedHeap::heap()->heap_region_iterate(&cl); |
196 |
341 } |
197 memset((void*)_iter_claims, 0, _max_regions * sizeof(size_t)); |
342 |
198 memset((void*)_in_dirty_region_buffer, false, _max_regions * sizeof(bool)); |
343 void prepare_for_merge_heap_roots() { |
199 _cur_dirty_region = 0; |
344 _all_dirty_regions->merge(_next_dirty_regions); |
200 } |
345 |
201 |
346 _next_dirty_regions->reset(); |
202 // Attempt to claim the remembered set of the region for iteration. Returns true |
347 for (size_t i = 0; i < _max_regions; i++) { |
|
348 _card_table_scan_state[i] = 0; |
|
349 } |
|
350 |
|
351 ::memset(_region_scan_chunks, false, _num_total_scan_chunks * sizeof(*_region_scan_chunks)); |
|
352 } |
|
353 |
|
354 // Returns whether the given region contains cards we need to scan. The remembered |
|
355 // set and other sources may contain cards that |
|
356 // - are in uncommitted regions |
|
357 // - are located in the collection set |
|
358 // - are located in free regions |
|
359 // as we do not clean up remembered sets before merging heap roots. |
|
360 bool contains_cards_to_process(uint const region_idx) const { |
|
361 HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx); |
|
362 return (hr != NULL && !hr->in_collection_set() && hr->is_old_or_humongous_or_archive()); |
|
363 } |
|
364 |
|
365 size_t num_visited_cards() const { |
|
366 size_t result = 0; |
|
367 for (uint i = 0; i < _num_total_scan_chunks; i++) { |
|
368 if (_region_scan_chunks[i]) { |
|
369 result++; |
|
370 } |
|
371 } |
|
372 return result * (HeapRegion::CardsPerRegion / _scan_chunks_per_region); |
|
373 } |
|
374 |
|
375 size_t num_cards_in_dirty_regions() const { |
|
376 return _next_dirty_regions->size() * HeapRegion::CardsPerRegion; |
|
377 } |
|
378 |
|
379 void set_chunk_region_dirty(size_t const region_card_idx) { |
|
380 size_t chunk_idx = region_card_idx >> _scan_chunks_shift; |
|
381 for (uint i = 0; i < _scan_chunks_per_region; i++) { |
|
382 _region_scan_chunks[chunk_idx++] = true; |
|
383 } |
|
384 } |
|
385 |
|
386 void set_chunk_dirty(size_t const card_idx) { |
|
387 assert((card_idx >> _scan_chunks_shift) < _num_total_scan_chunks, |
|
388 "Trying to access index " SIZE_FORMAT " out of bounds " SIZE_FORMAT, |
|
389 card_idx >> _scan_chunks_shift, _num_total_scan_chunks); |
|
390 size_t const chunk_idx = card_idx >> _scan_chunks_shift; |
|
391 if (!_region_scan_chunks[chunk_idx]) { |
|
392 _region_scan_chunks[chunk_idx] = true; |
|
393 } |
|
394 } |
|
395 |
|
396 void cleanup(WorkGang* workers) { |
|
397 _all_dirty_regions->merge(_next_dirty_regions); |
|
398 |
|
399 clear_card_table(workers); |
|
400 |
|
401 delete _all_dirty_regions; |
|
402 _all_dirty_regions = NULL; |
|
403 |
|
404 delete _next_dirty_regions; |
|
405 _next_dirty_regions = NULL; |
|
406 } |
|
407 |
|
408 void iterate_dirty_regions_from(HeapRegionClosure* cl, uint worker_id) { |
|
409 uint num_regions = _next_dirty_regions->size(); |
|
410 |
|
411 if (num_regions == 0) { |
|
412 return; |
|
413 } |
|
414 |
|
415 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
416 |
|
417 WorkGang* workers = g1h->workers(); |
|
418 uint const max_workers = workers->active_workers(); |
|
419 |
|
420 uint const start_pos = num_regions * worker_id / max_workers; |
|
421 uint cur = start_pos; |
|
422 |
|
423 do { |
|
424 bool result = cl->do_heap_region(g1h->region_at(_next_dirty_regions->at(cur))); |
|
425 guarantee(!result, "Not allowed to ask for early termination."); |
|
426 cur++; |
|
427 if (cur == _next_dirty_regions->size()) { |
|
428 cur = 0; |
|
429 } |
|
430 } while (cur != start_pos); |
|
431 } |
|
432 |
|
433 // Attempt to claim the given region in the collection set for iteration. Returns true |
203 // if this call caused the transition from Unclaimed to Claimed. |
434 // if this call caused the transition from Unclaimed to Claimed. |
204 inline bool claim_iter(uint region) { |
435 inline bool claim_collection_set_region(uint region) { |
205 assert(region < _max_regions, "Tried to access invalid region %u", region); |
436 assert(region < _max_regions, "Tried to access invalid region %u", region); |
206 if (_iter_states[region] != Unclaimed) { |
437 if (_collection_set_iter_state[region]) { |
207 return false; |
438 return false; |
208 } |
439 } |
209 G1RemsetIterState res = Atomic::cmpxchg(Claimed, &_iter_states[region], Unclaimed); |
440 return !Atomic::cmpxchg(true, &_collection_set_iter_state[region], false); |
210 return (res == Unclaimed); |
441 } |
211 } |
442 |
212 |
443 bool has_cards_to_scan(uint region) { |
213 // Try to atomically sets the iteration state to "complete". Returns true for the |
|
214 // thread that caused the transition. |
|
215 inline bool set_iter_complete(uint region) { |
|
216 if (iter_is_complete(region)) { |
|
217 return false; |
|
218 } |
|
219 G1RemsetIterState res = Atomic::cmpxchg(Complete, &_iter_states[region], Claimed); |
|
220 return (res == Claimed); |
|
221 } |
|
222 |
|
223 // Returns true if the region's iteration is complete. |
|
224 inline bool iter_is_complete(uint region) const { |
|
225 assert(region < _max_regions, "Tried to access invalid region %u", region); |
444 assert(region < _max_regions, "Tried to access invalid region %u", region); |
226 return _iter_states[region] == Complete; |
445 return _card_table_scan_state[region] < HeapRegion::CardsPerRegion; |
227 } |
446 } |
228 |
447 |
229 // The current position within the remembered set of the given region. |
448 uint claim_cards_to_scan(uint region, uint increment) { |
230 inline size_t iter_claimed(uint region) const { |
|
231 assert(region < _max_regions, "Tried to access invalid region %u", region); |
449 assert(region < _max_regions, "Tried to access invalid region %u", region); |
232 return _iter_claims[region]; |
450 return Atomic::add(increment, &_card_table_scan_state[region]) - increment; |
233 } |
451 } |
234 |
452 |
235 // Claim the next block of cards within the remembered set of the region with |
453 void add_dirty_region(uint const region) { |
236 // step size. |
454 #ifdef ASSERT |
237 inline size_t iter_claimed_next(uint region, size_t step) { |
455 HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); |
238 return Atomic::add(step, &_iter_claims[region]) - step; |
456 assert(!hr->in_collection_set() && hr->is_old_or_humongous_or_archive(), |
239 } |
457 "Region %u is not suitable for scanning, is %sin collection set or %s", |
240 |
458 hr->hrm_index(), hr->in_collection_set() ? "" : "not ", hr->get_short_type_str()); |
241 void add_dirty_region(uint region) { |
459 #endif |
242 if (_in_dirty_region_buffer[region]) { |
460 _next_dirty_regions->add_dirty_region(region); |
243 return; |
461 } |
244 } |
462 |
245 |
463 void add_all_dirty_region(uint region) { |
246 if (!Atomic::cmpxchg(true, &_in_dirty_region_buffer[region], false)) { |
464 #ifdef ASSERT |
247 size_t allocated = Atomic::add(1u, &_cur_dirty_region) - 1; |
465 HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); |
248 _dirty_region_buffer[allocated] = region; |
466 assert(hr->in_collection_set(), |
249 } |
467 "Only add young regions to all dirty regions directly but %u is %s", |
|
468 hr->hrm_index(), hr->get_short_type_str()); |
|
469 #endif |
|
470 _all_dirty_regions->add_dirty_region(region); |
|
471 } |
|
472 |
|
473 void set_scan_top(uint region_idx, HeapWord* value) { |
|
474 _scan_top[region_idx] = value; |
250 } |
475 } |
251 |
476 |
252 HeapWord* scan_top(uint region_idx) const { |
477 HeapWord* scan_top(uint region_idx) const { |
253 return _scan_top[region_idx]; |
478 return _scan_top[region_idx]; |
254 } |
479 } |
255 |
480 |
256 void clear_scan_top(uint region_idx) { |
481 void clear_scan_top(uint region_idx) { |
257 _scan_top[region_idx] = NULL; |
482 set_scan_top(region_idx, NULL); |
258 } |
|
259 |
|
260 // Clear the card table of "dirty" regions. |
|
261 void clear_card_table(WorkGang* workers) { |
|
262 if (_cur_dirty_region == 0) { |
|
263 return; |
|
264 } |
|
265 |
|
266 size_t const num_chunks = align_up(_cur_dirty_region * HeapRegion::CardsPerRegion, G1ClearCardTableTask::chunk_size()) / G1ClearCardTableTask::chunk_size(); |
|
267 uint const num_workers = (uint)MIN2(num_chunks, (size_t)workers->active_workers()); |
|
268 size_t const chunk_length = G1ClearCardTableTask::chunk_size() / HeapRegion::CardsPerRegion; |
|
269 |
|
270 // Iterate over the dirty cards region list. |
|
271 G1ClearCardTableTask cl(G1CollectedHeap::heap(), _dirty_region_buffer, _cur_dirty_region, chunk_length); |
|
272 |
|
273 log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " " |
|
274 "units of work for " SIZE_FORMAT " regions.", |
|
275 cl.name(), num_workers, num_chunks, _cur_dirty_region); |
|
276 workers->run_task(&cl, num_workers); |
|
277 |
|
278 #ifndef PRODUCT |
|
279 G1CollectedHeap::heap()->verifier()->verify_card_table_cleanup(); |
|
280 #endif |
|
281 } |
483 } |
282 }; |
484 }; |
283 |
485 |
284 G1RemSet::G1RemSet(G1CollectedHeap* g1h, |
486 G1RemSet::G1RemSet(G1CollectedHeap* g1h, |
285 G1CardTable* ct, |
487 G1CardTable* ct, |
286 G1HotCardCache* hot_card_cache) : |
488 G1HotCardCache* hot_card_cache) : |
287 _scan_state(new G1RemSetScanState()), |
489 _scan_state(new G1RemSetScanState()), |
288 _prev_period_summary(), |
490 _prev_period_summary(false), |
289 _g1h(g1h), |
491 _g1h(g1h), |
290 _num_conc_refined_cards(0), |
|
291 _ct(ct), |
492 _ct(ct), |
292 _g1p(_g1h->policy()), |
493 _g1p(_g1h->policy()), |
293 _hot_card_cache(hot_card_cache) { |
494 _hot_card_cache(hot_card_cache) { |
294 } |
495 } |
295 |
496 |
296 G1RemSet::~G1RemSet() { |
497 G1RemSet::~G1RemSet() { |
297 if (_scan_state != NULL) { |
498 delete _scan_state; |
298 delete _scan_state; |
|
299 } |
|
300 } |
499 } |
301 |
500 |
302 uint G1RemSet::num_par_rem_sets() { |
501 uint G1RemSet::num_par_rem_sets() { |
303 return G1DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::max_num_threads() + MAX2(ConcGCThreads, ParallelGCThreads); |
502 return G1DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::max_num_threads() + MAX2(ConcGCThreads, ParallelGCThreads); |
304 } |
503 } |
306 void G1RemSet::initialize(size_t capacity, uint max_regions) { |
505 void G1RemSet::initialize(size_t capacity, uint max_regions) { |
307 G1FromCardCache::initialize(num_par_rem_sets(), max_regions); |
506 G1FromCardCache::initialize(num_par_rem_sets(), max_regions); |
308 _scan_state->initialize(max_regions); |
507 _scan_state->initialize(max_regions); |
309 } |
508 } |
310 |
509 |
311 class G1ScanRSForRegionClosure : public HeapRegionClosure { |
510 // Helper class to scan and detect ranges of cards that need to be scanned on the |
|
511 // card table. |
|
512 class G1CardTableScanner : public StackObj { |
|
513 public: |
|
514 typedef CardTable::CardValue CardValue; |
|
515 |
|
516 private: |
|
517 CardValue* const _base_addr; |
|
518 |
|
519 CardValue* _cur_addr; |
|
520 CardValue* const _end_addr; |
|
521 |
|
522 static const size_t ToScanMask = G1CardTable::g1_card_already_scanned; |
|
523 static const size_t ExpandedToScanMask = G1CardTable::WordAlreadyScanned; |
|
524 |
|
525 bool cur_addr_aligned() const { |
|
526 return ((uintptr_t)_cur_addr) % sizeof(size_t) == 0; |
|
527 } |
|
528 |
|
529 bool cur_card_is_dirty() const { |
|
530 CardValue value = *_cur_addr; |
|
531 return (value & ToScanMask) == 0; |
|
532 } |
|
533 |
|
534 bool cur_word_of_cards_contains_any_dirty_card() const { |
|
535 assert(cur_addr_aligned(), "Current address should be aligned"); |
|
536 size_t const value = *(size_t*)_cur_addr; |
|
537 return (~value & ExpandedToScanMask) != 0; |
|
538 } |
|
539 |
|
540 bool cur_word_of_cards_all_dirty_cards() const { |
|
541 size_t const value = *(size_t*)_cur_addr; |
|
542 return value == G1CardTable::WordAllDirty; |
|
543 } |
|
544 |
|
545 size_t get_and_advance_pos() { |
|
546 _cur_addr++; |
|
547 return pointer_delta(_cur_addr, _base_addr, sizeof(CardValue)) - 1; |
|
548 } |
|
549 |
|
550 public: |
|
551 G1CardTableScanner(CardValue* start_card, size_t size) : |
|
552 _base_addr(start_card), |
|
553 _cur_addr(start_card), |
|
554 _end_addr(start_card + size) { |
|
555 |
|
556 assert(is_aligned(start_card, sizeof(size_t)), "Unaligned start addr " PTR_FORMAT, p2i(start_card)); |
|
557 assert(is_aligned(size, sizeof(size_t)), "Unaligned size " SIZE_FORMAT, size); |
|
558 } |
|
559 |
|
560 size_t find_next_dirty() { |
|
561 while (!cur_addr_aligned()) { |
|
562 if (cur_card_is_dirty()) { |
|
563 return get_and_advance_pos(); |
|
564 } |
|
565 _cur_addr++; |
|
566 } |
|
567 |
|
568 assert(cur_addr_aligned(), "Current address should be aligned now."); |
|
569 while (_cur_addr != _end_addr) { |
|
570 if (cur_word_of_cards_contains_any_dirty_card()) { |
|
571 for (size_t i = 0; i < sizeof(size_t); i++) { |
|
572 if (cur_card_is_dirty()) { |
|
573 return get_and_advance_pos(); |
|
574 } |
|
575 _cur_addr++; |
|
576 } |
|
577 assert(false, "Should not reach here given we detected a dirty card in the word."); |
|
578 } |
|
579 _cur_addr += sizeof(size_t); |
|
580 } |
|
581 return get_and_advance_pos(); |
|
582 } |
|
583 |
|
584 size_t find_next_non_dirty() { |
|
585 assert(_cur_addr <= _end_addr, "Not allowed to search for marks after area."); |
|
586 |
|
587 while (!cur_addr_aligned()) { |
|
588 if (!cur_card_is_dirty()) { |
|
589 return get_and_advance_pos(); |
|
590 } |
|
591 _cur_addr++; |
|
592 } |
|
593 |
|
594 assert(cur_addr_aligned(), "Current address should be aligned now."); |
|
595 while (_cur_addr != _end_addr) { |
|
596 if (!cur_word_of_cards_all_dirty_cards()) { |
|
597 for (size_t i = 0; i < sizeof(size_t); i++) { |
|
598 if (!cur_card_is_dirty()) { |
|
599 return get_and_advance_pos(); |
|
600 } |
|
601 _cur_addr++; |
|
602 } |
|
603 assert(false, "Should not reach here given we detected a non-dirty card in the word."); |
|
604 } |
|
605 _cur_addr += sizeof(size_t); |
|
606 } |
|
607 return get_and_advance_pos(); |
|
608 } |
|
609 }; |
|
610 |
|
611 // Helper class to claim dirty chunks within the card table. |
|
612 class G1CardTableChunkClaimer { |
|
613 G1RemSetScanState* _scan_state; |
|
614 uint _region_idx; |
|
615 uint _cur_claim; |
|
616 |
|
617 public: |
|
618 G1CardTableChunkClaimer(G1RemSetScanState* scan_state, uint region_idx) : |
|
619 _scan_state(scan_state), |
|
620 _region_idx(region_idx), |
|
621 _cur_claim(0) { |
|
622 guarantee(size() <= HeapRegion::CardsPerRegion, "Should not claim more space than possible."); |
|
623 } |
|
624 |
|
625 bool has_next() { |
|
626 while (true) { |
|
627 _cur_claim = _scan_state->claim_cards_to_scan(_region_idx, size()); |
|
628 if (_cur_claim >= HeapRegion::CardsPerRegion) { |
|
629 return false; |
|
630 } |
|
631 if (_scan_state->chunk_needs_scan(_region_idx, _cur_claim)) { |
|
632 return true; |
|
633 } |
|
634 } |
|
635 } |
|
636 |
|
637 uint value() const { return _cur_claim; } |
|
638 uint size() const { return _scan_state->scan_chunk_size(); } |
|
639 }; |
|
640 |
|
641 // Scans a heap region for dirty cards. |
|
642 class G1ScanHRForRegionClosure : public HeapRegionClosure { |
312 G1CollectedHeap* _g1h; |
643 G1CollectedHeap* _g1h; |
313 G1CardTable *_ct; |
644 G1CardTable* _ct; |
|
645 G1BlockOffsetTable* _bot; |
314 |
646 |
315 G1ParScanThreadState* _pss; |
647 G1ParScanThreadState* _pss; |
316 G1ScanCardClosure* _scan_objs_on_card_cl; |
|
317 |
648 |
318 G1RemSetScanState* _scan_state; |
649 G1RemSetScanState* _scan_state; |
319 |
650 |
320 G1GCPhaseTimes::GCParPhases _phase; |
651 G1GCPhaseTimes::GCParPhases _phase; |
321 |
652 |
322 uint _worker_i; |
653 uint _worker_id; |
|
654 |
|
655 size_t _cards_scanned; |
|
656 size_t _blocks_scanned; |
|
657 size_t _chunks_claimed; |
|
658 |
|
659 Tickspan _rem_set_root_scan_time; |
|
660 Tickspan _rem_set_trim_partially_time; |
|
661 |
|
662 // The address to which this thread already scanned (walked the heap) up to during |
|
663 // card scanning (exclusive). |
|
664 HeapWord* _scanned_to; |
|
665 |
|
666 HeapWord* scan_memregion(uint region_idx_for_card, MemRegion mr) { |
|
667 HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); |
|
668 G1ScanCardClosure card_cl(_g1h, _pss); |
|
669 |
|
670 HeapWord* const scanned_to = card_region->oops_on_memregion_seq_iterate_careful<true>(mr, &card_cl); |
|
671 assert(scanned_to != NULL, "Should be able to scan range"); |
|
672 assert(scanned_to >= mr.end(), "Scanned to " PTR_FORMAT " less than range " PTR_FORMAT, p2i(scanned_to), p2i(mr.end())); |
|
673 |
|
674 _pss->trim_queue_partially(); |
|
675 return scanned_to; |
|
676 } |
|
677 |
|
678 void do_claimed_block(uint const region_idx_for_card, size_t const first_card, size_t const num_cards) { |
|
679 HeapWord* const card_start = _bot->address_for_index_raw(first_card); |
|
680 #ifdef ASSERT |
|
681 HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); |
|
682 assert(hr == NULL || hr->is_in_reserved(card_start), |
|
683 "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); |
|
684 #endif |
|
685 HeapWord* const top = _scan_state->scan_top(region_idx_for_card); |
|
686 if (card_start >= top) { |
|
687 return; |
|
688 } |
|
689 |
|
690 HeapWord* scan_end = MIN2(card_start + (num_cards << BOTConstants::LogN_words), top); |
|
691 if (_scanned_to >= scan_end) { |
|
692 return; |
|
693 } |
|
694 MemRegion mr(MAX2(card_start, _scanned_to), scan_end); |
|
695 _scanned_to = scan_memregion(region_idx_for_card, mr); |
|
696 |
|
697 _cards_scanned += num_cards; |
|
698 } |
|
699 |
|
700 ALWAYSINLINE void do_card_block(uint const region_idx, size_t const first_card, size_t const num_cards) { |
|
701 _ct->mark_as_scanned(first_card, num_cards); |
|
702 do_claimed_block(region_idx, first_card, num_cards); |
|
703 _blocks_scanned++; |
|
704 } |
|
705 |
|
706 void scan_heap_roots(HeapRegion* r) { |
|
707 EventGCPhaseParallel event; |
|
708 uint const region_idx = r->hrm_index(); |
|
709 |
|
710 ResourceMark rm; |
|
711 |
|
712 G1CardTableChunkClaimer claim(_scan_state, region_idx); |
|
713 |
|
714 // Set the current scan "finger" to NULL for every heap region to scan. Since |
|
715 // the claim value is monotonically increasing, the check to not scan below this |
|
716 // will filter out objects spanning chunks within the region too then, as opposed |
|
717 // to resetting this value for every claim. |
|
718 _scanned_to = NULL; |
|
719 |
|
720 while (claim.has_next()) { |
|
721 size_t const region_card_base_idx = ((size_t)region_idx << HeapRegion::LogCardsPerRegion) + claim.value(); |
|
722 CardTable::CardValue* const base_addr = _ct->byte_for_index(region_card_base_idx); |
|
723 |
|
724 G1CardTableScanner scan(base_addr, claim.size()); |
|
725 |
|
726 size_t first_scan_idx = scan.find_next_dirty(); |
|
727 while (first_scan_idx != claim.size()) { |
|
728 assert(*_ct->byte_for_index(region_card_base_idx + first_scan_idx) <= 0x1, "is %d at region %u idx " SIZE_FORMAT, *_ct->byte_for_index(region_card_base_idx + first_scan_idx), region_idx, first_scan_idx); |
|
729 |
|
730 size_t const last_scan_idx = scan.find_next_non_dirty(); |
|
731 size_t const len = last_scan_idx - first_scan_idx; |
|
732 |
|
733 do_card_block(region_idx, region_card_base_idx + first_scan_idx, len); |
|
734 |
|
735 if (last_scan_idx == claim.size()) { |
|
736 break; |
|
737 } |
|
738 |
|
739 first_scan_idx = scan.find_next_dirty(); |
|
740 } |
|
741 _chunks_claimed++; |
|
742 } |
|
743 |
|
744 event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ScanHR)); |
|
745 } |
|
746 |
|
747 public: |
|
748 G1ScanHRForRegionClosure(G1RemSetScanState* scan_state, |
|
749 G1ParScanThreadState* pss, |
|
750 uint worker_id, |
|
751 G1GCPhaseTimes::GCParPhases phase) : |
|
752 _g1h(G1CollectedHeap::heap()), |
|
753 _ct(_g1h->card_table()), |
|
754 _bot(_g1h->bot()), |
|
755 _pss(pss), |
|
756 _scan_state(scan_state), |
|
757 _phase(phase), |
|
758 _worker_id(worker_id), |
|
759 _cards_scanned(0), |
|
760 _blocks_scanned(0), |
|
761 _chunks_claimed(0), |
|
762 _rem_set_root_scan_time(), |
|
763 _rem_set_trim_partially_time(), |
|
764 _scanned_to(NULL) { |
|
765 } |
|
766 |
|
767 bool do_heap_region(HeapRegion* r) { |
|
768 assert(!r->in_collection_set() && r->is_old_or_humongous_or_archive(), |
|
769 "Should only be called on old gen non-collection set regions but region %u is not.", |
|
770 r->hrm_index()); |
|
771 uint const region_idx = r->hrm_index(); |
|
772 |
|
773 if (_scan_state->has_cards_to_scan(region_idx)) { |
|
774 G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); |
|
775 scan_heap_roots(r); |
|
776 } |
|
777 return false; |
|
778 } |
|
779 |
|
780 Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; } |
|
781 Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; } |
|
782 |
|
783 size_t cards_scanned() const { return _cards_scanned; } |
|
784 size_t blocks_scanned() const { return _blocks_scanned; } |
|
785 size_t chunks_claimed() const { return _chunks_claimed; } |
|
786 }; |
|
787 |
|
788 void G1RemSet::scan_heap_roots(G1ParScanThreadState* pss, |
|
789 uint worker_id, |
|
790 G1GCPhaseTimes::GCParPhases scan_phase, |
|
791 G1GCPhaseTimes::GCParPhases objcopy_phase) { |
|
792 G1ScanHRForRegionClosure cl(_scan_state, pss, worker_id, scan_phase); |
|
793 _scan_state->iterate_dirty_regions_from(&cl, worker_id); |
|
794 |
|
795 G1GCPhaseTimes* p = _g1p->phase_times(); |
|
796 |
|
797 p->record_or_add_time_secs(objcopy_phase, worker_id, cl.rem_set_trim_partially_time().seconds()); |
|
798 |
|
799 p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_root_scan_time().seconds()); |
|
800 p->record_or_add_thread_work_item(scan_phase, worker_id, cl.cards_scanned(), G1GCPhaseTimes::ScanHRScannedCards); |
|
801 p->record_or_add_thread_work_item(scan_phase, worker_id, cl.blocks_scanned(), G1GCPhaseTimes::ScanHRScannedBlocks); |
|
802 p->record_or_add_thread_work_item(scan_phase, worker_id, cl.chunks_claimed(), G1GCPhaseTimes::ScanHRClaimedChunks); |
|
803 } |
|
804 |
|
805 // Heap region closure to be applied to all regions in the current collection set |
|
806 // increment to fix up non-card related roots. |
|
807 class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { |
|
808 G1ParScanThreadState* _pss; |
|
809 G1RemSetScanState* _scan_state; |
|
810 |
|
811 G1GCPhaseTimes::GCParPhases _scan_phase; |
|
812 G1GCPhaseTimes::GCParPhases _code_roots_phase; |
|
813 |
|
814 uint _worker_id; |
323 |
815 |
324 size_t _opt_refs_scanned; |
816 size_t _opt_refs_scanned; |
325 size_t _opt_refs_memory_used; |
817 size_t _opt_refs_memory_used; |
326 |
818 |
327 size_t _cards_scanned; |
|
328 size_t _cards_claimed; |
|
329 size_t _cards_skipped; |
|
330 |
|
331 Tickspan _rem_set_root_scan_time; |
|
332 Tickspan _rem_set_trim_partially_time; |
|
333 |
|
334 Tickspan _strong_code_root_scan_time; |
819 Tickspan _strong_code_root_scan_time; |
335 Tickspan _strong_code_trim_partially_time; |
820 Tickspan _strong_code_trim_partially_time; |
336 |
821 |
337 void claim_card(size_t card_index, const uint region_idx_for_card) { |
822 Tickspan _rem_set_opt_root_scan_time; |
338 _ct->set_card_claimed(card_index); |
823 Tickspan _rem_set_opt_trim_partially_time; |
339 _scan_state->add_dirty_region(region_idx_for_card); |
|
340 } |
|
341 |
|
342 void scan_card(MemRegion mr, uint region_idx_for_card) { |
|
343 HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); |
|
344 assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card); |
|
345 card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl); |
|
346 _scan_objs_on_card_cl->trim_queue_partially(); |
|
347 _cards_scanned++; |
|
348 } |
|
349 |
824 |
350 void scan_opt_rem_set_roots(HeapRegion* r) { |
825 void scan_opt_rem_set_roots(HeapRegion* r) { |
351 EventGCPhaseParallel event; |
826 EventGCPhaseParallel event; |
352 |
827 |
353 G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); |
828 G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); |
354 |
829 |
355 G1ScanCardClosure scan_cl(_g1h, _pss); |
830 G1ScanCardClosure scan_cl(G1CollectedHeap::heap(), _pss); |
356 G1ScanRSForOptionalClosure cl(_g1h, &scan_cl); |
831 G1ScanRSForOptionalClosure cl(G1CollectedHeap::heap(), &scan_cl); |
357 _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops()); |
832 _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->strong_oops()); |
358 _opt_refs_memory_used += opt_rem_set_list->used_memory(); |
833 _opt_refs_memory_used += opt_rem_set_list->used_memory(); |
359 |
834 |
360 event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); |
835 event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_scan_phase)); |
361 } |
|
362 |
|
363 void scan_rem_set_roots(HeapRegion* r) { |
|
364 EventGCPhaseParallel event; |
|
365 uint const region_idx = r->hrm_index(); |
|
366 |
|
367 if (_scan_state->claim_iter(region_idx)) { |
|
368 // If we ever free the collection set concurrently, we should also |
|
369 // clear the card table concurrently therefore we won't need to |
|
370 // add regions of the collection set to the dirty cards region. |
|
371 _scan_state->add_dirty_region(region_idx); |
|
372 } |
|
373 |
|
374 if (r->rem_set()->cardset_is_empty()) { |
|
375 return; |
|
376 } |
|
377 |
|
378 // We claim cards in blocks so as to reduce the contention. |
|
379 size_t const block_size = G1RSetScanBlockSize; |
|
380 |
|
381 HeapRegionRemSetIterator iter(r->rem_set()); |
|
382 size_t card_index; |
|
383 |
|
384 size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); |
|
385 for (size_t current_card = 0; iter.has_next(card_index); current_card++) { |
|
386 if (current_card >= claimed_card_block + block_size) { |
|
387 claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); |
|
388 } |
|
389 if (current_card < claimed_card_block) { |
|
390 _cards_skipped++; |
|
391 continue; |
|
392 } |
|
393 _cards_claimed++; |
|
394 |
|
395 HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); |
|
396 uint const region_idx_for_card = _g1h->addr_to_region(card_start); |
|
397 |
|
398 #ifdef ASSERT |
|
399 HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); |
|
400 assert(hr == NULL || hr->is_in_reserved(card_start), |
|
401 "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); |
|
402 #endif |
|
403 HeapWord* const top = _scan_state->scan_top(region_idx_for_card); |
|
404 if (card_start >= top) { |
|
405 continue; |
|
406 } |
|
407 |
|
408 // If the card is dirty, then G1 will scan it during Update RS. |
|
409 if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { |
|
410 continue; |
|
411 } |
|
412 |
|
413 // We claim lazily (so races are possible but they're benign), which reduces the |
|
414 // number of duplicate scans (the rsets of the regions in the cset can intersect). |
|
415 // Claim the card after checking bounds above: the remembered set may contain |
|
416 // random cards into current survivor, and we would then have an incorrectly |
|
417 // claimed card in survivor space. Card table clear does not reset the card table |
|
418 // of survivor space regions. |
|
419 claim_card(card_index, region_idx_for_card); |
|
420 |
|
421 MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top)); |
|
422 |
|
423 scan_card(mr, region_idx_for_card); |
|
424 } |
|
425 event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); |
|
426 } |
|
427 |
|
428 void scan_strong_code_roots(HeapRegion* r) { |
|
429 EventGCPhaseParallel event; |
|
430 // We pass a weak code blobs closure to the remembered set scanning because we want to avoid |
|
431 // treating the nmethods visited to act as roots for concurrent marking. |
|
432 // We only want to make sure that the oops in the nmethods are adjusted with regard to the |
|
433 // objects copied by the current evacuation. |
|
434 r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); |
|
435 event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots)); |
|
436 } |
836 } |
437 |
837 |
438 public: |
838 public: |
439 G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, |
839 G1ScanCollectionSetRegionClosure(G1RemSetScanState* scan_state, |
440 G1ScanCardClosure* scan_obj_on_card, |
840 G1ParScanThreadState* pss, |
441 G1ParScanThreadState* pss, |
841 uint worker_id, |
442 G1GCPhaseTimes::GCParPhases phase, |
842 G1GCPhaseTimes::GCParPhases scan_phase, |
443 uint worker_i) : |
843 G1GCPhaseTimes::GCParPhases code_roots_phase) : |
444 _g1h(G1CollectedHeap::heap()), |
|
445 _ct(_g1h->card_table()), |
|
446 _pss(pss), |
844 _pss(pss), |
447 _scan_objs_on_card_cl(scan_obj_on_card), |
|
448 _scan_state(scan_state), |
845 _scan_state(scan_state), |
449 _phase(phase), |
846 _scan_phase(scan_phase), |
450 _worker_i(worker_i), |
847 _code_roots_phase(code_roots_phase), |
|
848 _worker_id(worker_id), |
451 _opt_refs_scanned(0), |
849 _opt_refs_scanned(0), |
452 _opt_refs_memory_used(0), |
850 _opt_refs_memory_used(0), |
453 _cards_scanned(0), |
|
454 _cards_claimed(0), |
|
455 _cards_skipped(0), |
|
456 _rem_set_root_scan_time(), |
|
457 _rem_set_trim_partially_time(), |
|
458 _strong_code_root_scan_time(), |
851 _strong_code_root_scan_time(), |
459 _strong_code_trim_partially_time() { } |
852 _strong_code_trim_partially_time(), |
|
853 _rem_set_opt_root_scan_time(), |
|
854 _rem_set_opt_trim_partially_time() { } |
460 |
855 |
461 bool do_heap_region(HeapRegion* r) { |
856 bool do_heap_region(HeapRegion* r) { |
462 assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index()); |
|
463 uint const region_idx = r->hrm_index(); |
857 uint const region_idx = r->hrm_index(); |
464 |
858 |
465 // The individual references for the optional remembered set are per-worker, so we |
859 // The individual references for the optional remembered set are per-worker, so we |
466 // always need to scan them. |
860 // always need to scan them. |
467 if (r->has_index_in_opt_cset()) { |
861 if (r->has_index_in_opt_cset()) { |
468 G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); |
862 G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_opt_root_scan_time, _rem_set_opt_trim_partially_time); |
469 scan_opt_rem_set_roots(r); |
863 scan_opt_rem_set_roots(r); |
470 } |
864 } |
471 |
865 |
472 // Do an early out if we know we are complete. |
866 if (_scan_state->claim_collection_set_region(region_idx)) { |
473 if (_scan_state->iter_is_complete(region_idx)) { |
867 EventGCPhaseParallel event; |
474 return false; |
868 |
475 } |
|
476 |
|
477 { |
|
478 G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); |
|
479 scan_rem_set_roots(r); |
|
480 } |
|
481 |
|
482 if (_scan_state->set_iter_complete(region_idx)) { |
|
483 G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); |
869 G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); |
484 // Scan the strong code root list attached to the current region |
870 // Scan the strong code root list attached to the current region |
485 scan_strong_code_roots(r); |
871 r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); |
486 } |
872 |
|
873 event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_code_roots_phase)); |
|
874 } |
|
875 |
487 return false; |
876 return false; |
488 } |
877 } |
489 |
|
490 Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; } |
|
491 Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; } |
|
492 |
878 |
493 Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } |
879 Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } |
494 Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } |
880 Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } |
495 |
881 |
496 size_t cards_scanned() const { return _cards_scanned; } |
882 Tickspan rem_set_opt_root_scan_time() const { return _rem_set_opt_root_scan_time; } |
497 size_t cards_claimed() const { return _cards_claimed; } |
883 Tickspan rem_set_opt_trim_partially_time() const { return _rem_set_opt_trim_partially_time; } |
498 size_t cards_skipped() const { return _cards_skipped; } |
|
499 |
884 |
500 size_t opt_refs_scanned() const { return _opt_refs_scanned; } |
885 size_t opt_refs_scanned() const { return _opt_refs_scanned; } |
501 size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } |
886 size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } |
502 }; |
887 }; |
503 |
888 |
504 void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, |
889 void G1RemSet::scan_collection_set_regions(G1ParScanThreadState* pss, |
505 uint worker_i, |
890 uint worker_id, |
506 G1GCPhaseTimes::GCParPhases scan_phase, |
891 G1GCPhaseTimes::GCParPhases scan_phase, |
507 G1GCPhaseTimes::GCParPhases objcopy_phase, |
892 G1GCPhaseTimes::GCParPhases coderoots_phase, |
508 G1GCPhaseTimes::GCParPhases coderoots_phase) { |
893 G1GCPhaseTimes::GCParPhases objcopy_phase) { |
509 assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering."); |
894 G1ScanCollectionSetRegionClosure cl(_scan_state, pss, worker_id, scan_phase, coderoots_phase); |
510 |
895 _g1h->collection_set_iterate_increment_from(&cl, worker_id); |
511 G1ScanCardClosure scan_cl(_g1h, pss); |
896 |
512 G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i); |
897 G1GCPhaseTimes* p = _g1h->phase_times(); |
513 _g1h->collection_set_iterate_increment_from(&cl, worker_i); |
898 |
514 |
899 p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_root_scan_time().seconds()); |
515 G1GCPhaseTimes* p = _g1p->phase_times(); |
900 p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_trim_partially_time().seconds()); |
516 |
901 |
517 p->record_or_add_time_secs(objcopy_phase, worker_i, cl.rem_set_trim_partially_time().seconds()); |
902 p->record_or_add_time_secs(coderoots_phase, worker_id, cl.strong_code_root_scan_time().seconds()); |
518 |
903 p->add_time_secs(objcopy_phase, worker_id, cl.strong_code_root_trim_partially_time().seconds()); |
519 p->record_or_add_time_secs(scan_phase, worker_i, cl.rem_set_root_scan_time().seconds()); |
904 |
520 p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); |
905 // At this time we record some metrics only for the evacuations after the initial one. |
521 p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); |
906 if (scan_phase == G1GCPhaseTimes::OptScanHR) { |
522 p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); |
907 p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanHRScannedOptRefs); |
523 // At this time we only record some metrics for the optional remembered set. |
908 p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanHRUsedMemory); |
524 if (scan_phase == G1GCPhaseTimes::OptScanRS) { |
909 } |
525 p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanRSScannedOptRefs); |
|
526 p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanRSUsedMemory); |
|
527 } |
|
528 |
|
529 p->record_or_add_time_secs(coderoots_phase, worker_i, cl.strong_code_root_scan_time().seconds()); |
|
530 p->add_time_secs(objcopy_phase, worker_i, cl.strong_code_root_trim_partially_time().seconds()); |
|
531 } |
910 } |
532 |
911 |
533 // Closure used for updating rem sets. Only called during an evacuation pause. |
912 void G1RemSet::prepare_for_scan_heap_roots() { |
534 class G1RefineCardClosure: public G1CardTableEntryClosure { |
913 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); |
535 G1RemSet* _g1rs; |
914 dcqs.concatenate_logs(); |
536 G1ScanCardClosure* _update_rs_cl; |
915 |
537 |
916 _scan_state->prepare(); |
538 size_t _cards_scanned; |
917 } |
539 size_t _cards_skipped; |
918 |
|
919 class G1MergeHeapRootsTask : public AbstractGangTask { |
|
920 |
|
921 // Visitor for remembered sets, dropping entries onto the card table. |
|
922 class G1MergeCardSetClosure : public HeapRegionClosure { |
|
923 G1RemSetScanState* _scan_state; |
|
924 G1CardTable* _ct; |
|
925 |
|
926 uint _merged_sparse; |
|
927 uint _merged_fine; |
|
928 uint _merged_coarse; |
|
929 |
|
930 // Returns if the region contains cards we need to scan. If so, remember that |
|
931 // region in the current set of dirty regions. |
|
932 bool remember_if_interesting(uint const region_idx) { |
|
933 if (!_scan_state->contains_cards_to_process(region_idx)) { |
|
934 return false; |
|
935 } |
|
936 _scan_state->add_dirty_region(region_idx); |
|
937 return true; |
|
938 } |
|
939 public: |
|
940 G1MergeCardSetClosure(G1RemSetScanState* scan_state) : |
|
941 _scan_state(scan_state), |
|
942 _ct(G1CollectedHeap::heap()->card_table()), |
|
943 _merged_sparse(0), |
|
944 _merged_fine(0), |
|
945 _merged_coarse(0) { } |
|
946 |
|
947 void next_coarse_prt(uint const region_idx) { |
|
948 if (!remember_if_interesting(region_idx)) { |
|
949 return; |
|
950 } |
|
951 |
|
952 _merged_coarse++; |
|
953 |
|
954 size_t region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; |
|
955 _ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion); |
|
956 _scan_state->set_chunk_region_dirty(region_base_idx); |
|
957 } |
|
958 |
|
959 void next_fine_prt(uint const region_idx, BitMap* bm) { |
|
960 if (!remember_if_interesting(region_idx)) { |
|
961 return; |
|
962 } |
|
963 |
|
964 _merged_fine++; |
|
965 |
|
966 size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; |
|
967 BitMap::idx_t cur = bm->get_next_one_offset(0); |
|
968 while (cur != bm->size()) { |
|
969 _ct->mark_clean_as_dirty(region_base_idx + cur); |
|
970 _scan_state->set_chunk_dirty(region_base_idx + cur); |
|
971 cur = bm->get_next_one_offset(cur + 1); |
|
972 } |
|
973 } |
|
974 |
|
975 void next_sparse_prt(uint const region_idx, SparsePRTEntry::card_elem_t* cards, uint const num_cards) { |
|
976 if (!remember_if_interesting(region_idx)) { |
|
977 return; |
|
978 } |
|
979 |
|
980 _merged_sparse++; |
|
981 |
|
982 size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; |
|
983 for (uint i = 0; i < num_cards; i++) { |
|
984 size_t card_idx = region_base_idx + cards[i]; |
|
985 _ct->mark_clean_as_dirty(card_idx); |
|
986 _scan_state->set_chunk_dirty(card_idx); |
|
987 } |
|
988 } |
|
989 |
|
990 virtual bool do_heap_region(HeapRegion* r) { |
|
991 assert(r->in_collection_set() || r->is_starts_humongous(), "must be"); |
|
992 |
|
993 HeapRegionRemSet* rem_set = r->rem_set(); |
|
994 if (!rem_set->is_empty()) { |
|
995 rem_set->iterate_prts(*this); |
|
996 } |
|
997 |
|
998 return false; |
|
999 } |
|
1000 |
|
1001 size_t merged_sparse() const { return _merged_sparse; } |
|
1002 size_t merged_fine() const { return _merged_fine; } |
|
1003 size_t merged_coarse() const { return _merged_coarse; } |
|
1004 }; |
|
1005 |
|
1006 // Visitor for the remembered sets of humongous candidate regions to merge their |
|
1007 // remembered set into the card table. |
|
1008 class G1FlushHumongousCandidateRemSets : public HeapRegionClosure { |
|
1009 G1MergeCardSetClosure _cl; |
|
1010 |
|
1011 public: |
|
1012 G1FlushHumongousCandidateRemSets(G1RemSetScanState* scan_state) : _cl(scan_state) { } |
|
1013 |
|
1014 virtual bool do_heap_region(HeapRegion* r) { |
|
1015 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
1016 |
|
1017 if (!r->is_starts_humongous() || |
|
1018 !g1h->region_attr(r->hrm_index()).is_humongous() || |
|
1019 r->rem_set()->is_empty()) { |
|
1020 return false; |
|
1021 } |
|
1022 |
|
1023 guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), |
|
1024 "Found a not-small remembered set here. This is inconsistent with previous assumptions."); |
|
1025 |
|
1026 _cl.do_heap_region(r); |
|
1027 |
|
1028 // We should only clear the card based remembered set here as we will not |
|
1029 // implicitly rebuild anything else during eager reclaim. Note that at the moment |
|
1030 // (and probably never) we do not enter this path if there are other kind of |
|
1031 // remembered sets for this region. |
|
1032 r->rem_set()->clear_locked(true /* only_cardset */); |
|
1033 // Clear_locked() above sets the state to Empty. However we want to continue |
|
1034 // collecting remembered set entries for humongous regions that were not |
|
1035 // reclaimed. |
|
1036 r->rem_set()->set_state_complete(); |
|
1037 #ifdef ASSERT |
|
1038 G1HeapRegionAttr region_attr = g1h->region_attr(r->hrm_index()); |
|
1039 assert(region_attr.needs_remset_update(), "must be"); |
|
1040 #endif |
|
1041 assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); |
|
1042 |
|
1043 return false; |
|
1044 } |
|
1045 |
|
1046 size_t merged_sparse() const { return _cl.merged_sparse(); } |
|
1047 size_t merged_fine() const { return _cl.merged_fine(); } |
|
1048 size_t merged_coarse() const { return _cl.merged_coarse(); } |
|
1049 }; |
|
1050 |
|
1051 // Visitor for the log buffer entries to merge them into the card table. |
|
1052 class G1MergeLogBufferCardsClosure : public G1CardTableEntryClosure { |
|
1053 G1RemSetScanState* _scan_state; |
|
1054 G1CardTable* _ct; |
|
1055 |
|
1056 size_t _cards_dirty; |
|
1057 size_t _cards_skipped; |
|
1058 public: |
|
1059 G1MergeLogBufferCardsClosure(G1CollectedHeap* g1h, G1RemSetScanState* scan_state) : |
|
1060 _scan_state(scan_state), _ct(g1h->card_table()), _cards_dirty(0), _cards_skipped(0) |
|
1061 {} |
|
1062 |
|
1063 void do_card_ptr(CardValue* card_ptr, uint worker_id) { |
|
1064 // The only time we care about recording cards that |
|
1065 // contain references that point into the collection set |
|
1066 // is during RSet updating within an evacuation pause. |
|
1067 // In this case worker_id should be the id of a GC worker thread. |
|
1068 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); |
|
1069 |
|
1070 uint const region_idx = _ct->region_idx_for(card_ptr); |
|
1071 |
|
1072 // The second clause must come after - the log buffers might contain cards to uncommited |
|
1073 // regions. |
|
1074 // This code may count duplicate entries in the log buffers (even if rare) multiple |
|
1075 // times. |
|
1076 if (_scan_state->contains_cards_to_process(region_idx) && (*card_ptr == G1CardTable::dirty_card_val())) { |
|
1077 _scan_state->add_dirty_region(region_idx); |
|
1078 _scan_state->set_chunk_dirty(_ct->index_for_cardvalue(card_ptr)); |
|
1079 _cards_dirty++; |
|
1080 } else { |
|
1081 // We may have had dirty cards in the (initial) collection set (or the |
|
1082 // young regions which are always in the initial collection set). We do |
|
1083 // not fix their cards here: we already added these regions to the set of |
|
1084 // regions to clear the card table at the end during the prepare() phase. |
|
1085 _cards_skipped++; |
|
1086 } |
|
1087 } |
|
1088 |
|
1089 size_t cards_dirty() const { return _cards_dirty; } |
|
1090 size_t cards_skipped() const { return _cards_skipped; } |
|
1091 }; |
|
1092 |
|
1093 HeapRegionClaimer _hr_claimer; |
|
1094 G1RemSetScanState* _scan_state; |
|
1095 BufferNode::Stack _dirty_card_buffers; |
|
1096 bool _initial_evacuation; |
|
1097 |
|
1098 volatile bool _fast_reclaim_handled; |
|
1099 |
|
1100 void apply_closure_to_dirty_card_buffers(G1MergeLogBufferCardsClosure* cl, uint worker_id) { |
|
1101 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); |
|
1102 size_t buffer_size = dcqs.buffer_size(); |
|
1103 while (BufferNode* node = _dirty_card_buffers.pop()) { |
|
1104 cl->apply_to_buffer(node, buffer_size, worker_id); |
|
1105 dcqs.deallocate_buffer(node); |
|
1106 } |
|
1107 } |
|
1108 |
540 public: |
1109 public: |
541 G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanCardClosure* update_rs_cl) : |
1110 G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool initial_evacuation) : |
542 _g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0) |
1111 AbstractGangTask("G1 Merge Heap Roots"), |
543 {} |
1112 _hr_claimer(num_workers), |
544 |
1113 _scan_state(scan_state), |
545 bool do_card_ptr(CardValue* card_ptr, uint worker_i) { |
1114 _dirty_card_buffers(), |
546 // The only time we care about recording cards that |
1115 _initial_evacuation(initial_evacuation), |
547 // contain references that point into the collection set |
1116 _fast_reclaim_handled(false) |
548 // is during RSet updating within an evacuation pause. |
1117 { |
549 // In this case worker_i should be the id of a GC worker thread. |
1118 if (initial_evacuation) { |
550 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); |
1119 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); |
551 |
1120 G1BufferNodeList buffers = dcqs.take_all_completed_buffers(); |
552 bool card_scanned = _g1rs->refine_card_during_gc(card_ptr, _update_rs_cl); |
1121 if (buffers._entry_count != 0) { |
553 |
1122 _dirty_card_buffers.prepend(*buffers._head, *buffers._tail); |
554 if (card_scanned) { |
1123 } |
555 _update_rs_cl->trim_queue_partially(); |
1124 } |
556 _cards_scanned++; |
1125 } |
|
1126 |
|
1127 virtual void work(uint worker_id) { |
|
1128 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
1129 G1GCPhaseTimes* p = g1h->phase_times(); |
|
1130 |
|
1131 G1GCPhaseTimes::GCParPhases merge_remset_phase = _initial_evacuation ? |
|
1132 G1GCPhaseTimes::MergeRS : |
|
1133 G1GCPhaseTimes::OptMergeRS; |
|
1134 |
|
1135 // We schedule flushing the remembered sets of humongous fast reclaim candidates |
|
1136 // onto the card table first to allow the remaining parallelized tasks hide it. |
|
1137 if (_initial_evacuation && |
|
1138 p->fast_reclaim_humongous_candidates() > 0 && |
|
1139 !_fast_reclaim_handled && |
|
1140 !Atomic::cmpxchg(true, &_fast_reclaim_handled, false)) { |
|
1141 |
|
1142 G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeER, worker_id); |
|
1143 |
|
1144 G1FlushHumongousCandidateRemSets cl(_scan_state); |
|
1145 g1h->heap_region_iterate(&cl); |
|
1146 |
|
1147 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse); |
|
1148 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine); |
|
1149 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse); |
|
1150 } |
|
1151 |
|
1152 // Merge remembered sets of current candidates. |
|
1153 { |
|
1154 G1GCParPhaseTimesTracker x(p, merge_remset_phase, worker_id, _initial_evacuation /* must_record */); |
|
1155 G1MergeCardSetClosure cl(_scan_state); |
|
1156 g1h->collection_set_iterate_increment_from(&cl, &_hr_claimer, worker_id); |
|
1157 |
|
1158 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse); |
|
1159 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine); |
|
1160 p->record_or_add_thread_work_item(merge_remset_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse); |
|
1161 } |
|
1162 |
|
1163 // Apply closure to log entries in the HCC. |
|
1164 if (_initial_evacuation && G1HotCardCache::default_use_cache()) { |
|
1165 assert(merge_remset_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase"); |
|
1166 G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id); |
|
1167 G1MergeLogBufferCardsClosure cl(g1h, _scan_state); |
|
1168 g1h->iterate_hcc_closure(&cl, worker_id); |
|
1169 |
|
1170 p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeHCCDirtyCards); |
|
1171 p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeHCCSkippedCards); |
|
1172 } |
|
1173 |
|
1174 // Now apply the closure to all remaining log entries. |
|
1175 if (_initial_evacuation) { |
|
1176 assert(merge_remset_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase"); |
|
1177 G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeLB, worker_id); |
|
1178 |
|
1179 G1MergeLogBufferCardsClosure cl(g1h, _scan_state); |
|
1180 apply_closure_to_dirty_card_buffers(&cl, worker_id); |
|
1181 |
|
1182 p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeLBDirtyCards); |
|
1183 p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeLBSkippedCards); |
|
1184 } |
|
1185 } |
|
1186 }; |
|
1187 |
|
1188 void G1RemSet::print_merge_heap_roots_stats() { |
|
1189 size_t num_visited_cards = _scan_state->num_visited_cards(); |
|
1190 |
|
1191 size_t total_dirty_region_cards = _scan_state->num_cards_in_dirty_regions(); |
|
1192 |
|
1193 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
1194 size_t total_old_region_cards = |
|
1195 (g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * HeapRegion::CardsPerRegion; |
|
1196 |
|
1197 log_debug(gc,remset)("Visited cards " SIZE_FORMAT " Total dirty " SIZE_FORMAT " (%.2lf%%) Total old " SIZE_FORMAT " (%.2lf%%)", |
|
1198 num_visited_cards, |
|
1199 total_dirty_region_cards, |
|
1200 percent_of(num_visited_cards, total_dirty_region_cards), |
|
1201 total_old_region_cards, |
|
1202 percent_of(num_visited_cards, total_old_region_cards)); |
|
1203 } |
|
1204 |
|
1205 void G1RemSet::merge_heap_roots(bool initial_evacuation) { |
|
1206 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
1207 |
|
1208 { |
|
1209 Ticks start = Ticks::now(); |
|
1210 |
|
1211 _scan_state->prepare_for_merge_heap_roots(); |
|
1212 |
|
1213 Tickspan total = Ticks::now() - start; |
|
1214 if (initial_evacuation) { |
|
1215 g1h->phase_times()->record_prepare_merge_heap_roots_time(total.seconds() * 1000.0); |
557 } else { |
1216 } else { |
558 _cards_skipped++; |
1217 g1h->phase_times()->record_or_add_optional_prepare_merge_heap_roots_time(total.seconds() * 1000.0); |
559 } |
1218 } |
560 return true; |
1219 } |
561 } |
1220 |
562 |
1221 WorkGang* workers = g1h->workers(); |
563 size_t cards_scanned() const { return _cards_scanned; } |
1222 size_t const increment_length = g1h->collection_set()->increment_length(); |
564 size_t cards_skipped() const { return _cards_skipped; } |
1223 |
565 }; |
1224 uint const num_workers = initial_evacuation ? workers->active_workers() : |
566 |
1225 MIN2(workers->active_workers(), (uint)increment_length); |
567 void G1RemSet::update_rem_set(G1ParScanThreadState* pss, uint worker_i) { |
1226 |
568 G1GCPhaseTimes* p = _g1p->phase_times(); |
|
569 |
|
570 // Apply closure to log entries in the HCC. |
|
571 if (G1HotCardCache::default_use_cache()) { |
|
572 G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i); |
|
573 |
|
574 G1ScanCardClosure scan_hcc_cl(_g1h, pss); |
|
575 G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl); |
|
576 _g1h->iterate_hcc_closure(&refine_card_cl, worker_i); |
|
577 } |
|
578 |
|
579 // Now apply the closure to all remaining log entries. |
|
580 { |
1227 { |
581 G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i); |
1228 G1MergeHeapRootsTask cl(_scan_state, num_workers, initial_evacuation); |
582 |
1229 log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " regions", |
583 G1ScanCardClosure update_rs_cl(_g1h, pss); |
1230 cl.name(), num_workers, increment_length); |
584 G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl); |
1231 workers->run_task(&cl, num_workers); |
585 _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i); |
1232 } |
586 |
1233 |
587 p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards); |
1234 if (log_is_enabled(Debug, gc, remset)) { |
588 p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards); |
1235 print_merge_heap_roots_stats(); |
589 } |
1236 } |
590 } |
1237 } |
591 |
1238 |
592 void G1RemSet::prepare_for_scan_rem_set() { |
1239 void G1RemSet::prepare_for_scan_heap_roots(uint region_idx) { |
593 G1BarrierSet::dirty_card_queue_set().concatenate_logs(); |
|
594 _scan_state->reset(); |
|
595 } |
|
596 |
|
597 void G1RemSet::prepare_for_scan_rem_set(uint region_idx) { |
|
598 _scan_state->clear_scan_top(region_idx); |
1240 _scan_state->clear_scan_top(region_idx); |
599 } |
1241 } |
600 |
1242 |
601 void G1RemSet::cleanup_after_scan_rem_set() { |
1243 void G1RemSet::cleanup_after_scan_heap_roots() { |
602 G1GCPhaseTimes* phase_times = _g1h->phase_times(); |
1244 G1GCPhaseTimes* phase_times = _g1h->phase_times(); |
603 |
1245 |
604 // Set all cards back to clean. |
1246 // Set all cards back to clean. |
605 double start = os::elapsedTime(); |
1247 double start = os::elapsedTime(); |
606 _scan_state->clear_card_table(_g1h->workers()); |
1248 _scan_state->cleanup(_g1h->workers()); |
607 phase_times->record_clear_ct_time((os::elapsedTime() - start) * 1000.0); |
1249 phase_times->record_clear_ct_time((os::elapsedTime() - start) * 1000.0); |
608 } |
1250 } |
609 |
1251 |
610 inline void check_card_ptr(CardTable::CardValue* card_ptr, G1CardTable* ct) { |
1252 inline void check_card_ptr(CardTable::CardValue* card_ptr, G1CardTable* ct) { |
611 #ifdef ASSERT |
1253 #ifdef ASSERT |