116 } else { |
123 } else { |
117 return NULL; |
124 return NULL; |
118 } |
125 } |
119 } |
126 } |
120 |
127 |
121 static inline int orderRegions(HeapRegion* hr1, HeapRegion* hr2) { |
128 // Even though we don't use the GC efficiency in our heuristics as |
|
129 // much as we used to, we still order according to GC efficiency. This |
|
130 // will cause regions with a lot of live objects and large RSets to |
|
131 // end up at the end of the array. Given that we might skip collecting |
|
132 // the last few old regions, if after a few mixed GCs the remaining |
|
133 // have reclaimable bytes under a certain threshold, the hope is that |
|
134 // the ones we'll skip are ones with both large RSets and a lot of |
|
135 // live objects, not the ones with just a lot of live objects if we |
|
136 // ordered according to the amount of reclaimable bytes per region. |
|
137 static int orderRegions(HeapRegion* hr1, HeapRegion* hr2) { |
122 if (hr1 == NULL) { |
138 if (hr1 == NULL) { |
123 if (hr2 == NULL) return 0; |
139 if (hr2 == NULL) { |
124 else return 1; |
140 return 0; |
|
141 } else { |
|
142 return 1; |
|
143 } |
125 } else if (hr2 == NULL) { |
144 } else if (hr2 == NULL) { |
126 return -1; |
145 return -1; |
127 } |
146 } |
128 if (hr2->gc_efficiency() < hr1->gc_efficiency()) return -1; |
147 |
129 else if (hr1->gc_efficiency() < hr2->gc_efficiency()) return 1; |
148 double gc_eff1 = hr1->gc_efficiency(); |
130 else return 0; |
149 double gc_eff2 = hr2->gc_efficiency(); |
|
150 if (gc_eff1 > gc_eff2) { |
|
151 return -1; |
|
152 } if (gc_eff1 < gc_eff2) { |
|
153 return 1; |
|
154 } else { |
|
155 return 0; |
|
156 } |
131 } |
157 } |
132 |
158 |
133 static int orderRegions(HeapRegion** hr1p, HeapRegion** hr2p) { |
159 static int orderRegions(HeapRegion** hr1p, HeapRegion** hr2p) { |
134 return orderRegions(*hr1p, *hr2p); |
160 return orderRegions(*hr1p, *hr2p); |
135 } |
161 } |
149 // |
175 // |
150 // Note: containing object is allocated on C heap since it is CHeapObj. |
176 // Note: containing object is allocated on C heap since it is CHeapObj. |
151 // |
177 // |
152 _markedRegions((ResourceObj::set_allocation_type((address)&_markedRegions, |
178 _markedRegions((ResourceObj::set_allocation_type((address)&_markedRegions, |
153 ResourceObj::C_HEAP), |
179 ResourceObj::C_HEAP), |
154 100), |
180 100), true /* C_Heap */), |
155 true), |
181 _curr_index(0), _length(0), |
156 _curMarkedIndex(0), |
182 _regionLiveThresholdBytes(0), _remainingReclaimableBytes(0), |
157 _numMarkedRegions(0), |
183 _first_par_unreserved_idx(0) { |
158 _unmarked_age_1_returned_as_new(false), |
184 _regionLiveThresholdBytes = |
159 _first_par_unreserved_idx(0) |
185 HeapRegion::GrainBytes * (size_t) G1OldCSetRegionLiveThresholdPercent / 100; |
160 {} |
186 } |
161 |
|
162 |
|
163 |
187 |
164 #ifndef PRODUCT |
188 #ifndef PRODUCT |
165 bool CollectionSetChooser::verify() { |
189 bool CollectionSetChooser::verify() { |
|
190 guarantee(_length >= 0, err_msg("_length: %d", _length)); |
|
191 guarantee(0 <= _curr_index && _curr_index <= _length, |
|
192 err_msg("_curr_index: %d _length: %d", _curr_index, _length)); |
166 int index = 0; |
193 int index = 0; |
167 guarantee(_curMarkedIndex <= _numMarkedRegions, |
194 size_t sum_of_reclaimable_bytes = 0; |
168 "_curMarkedIndex should be within bounds"); |
195 while (index < _curr_index) { |
169 while (index < _curMarkedIndex) { |
196 guarantee(_markedRegions.at(index) == NULL, |
170 guarantee(_markedRegions.at(index++) == NULL, |
197 "all entries before _curr_index should be NULL"); |
171 "all entries before _curMarkedIndex should be NULL"); |
198 index += 1; |
172 } |
199 } |
173 HeapRegion *prev = NULL; |
200 HeapRegion *prev = NULL; |
174 while (index < _numMarkedRegions) { |
201 while (index < _length) { |
175 HeapRegion *curr = _markedRegions.at(index++); |
202 HeapRegion *curr = _markedRegions.at(index++); |
176 guarantee(curr != NULL, "Regions in _markedRegions array cannot be NULL"); |
203 guarantee(curr != NULL, "Regions in _markedRegions array cannot be NULL"); |
177 int si = curr->sort_index(); |
204 int si = curr->sort_index(); |
178 guarantee(!curr->is_young(), "should not be young!"); |
205 guarantee(!curr->is_young(), "should not be young!"); |
|
206 guarantee(!curr->isHumongous(), "should not be humongous!"); |
179 guarantee(si > -1 && si == (index-1), "sort index invariant"); |
207 guarantee(si > -1 && si == (index-1), "sort index invariant"); |
180 if (prev != NULL) { |
208 if (prev != NULL) { |
181 guarantee(orderRegions(prev, curr) != 1, "regions should be sorted"); |
209 guarantee(orderRegions(prev, curr) != 1, |
182 } |
210 err_msg("GC eff prev: %1.4f GC eff curr: %1.4f", |
|
211 prev->gc_efficiency(), curr->gc_efficiency())); |
|
212 } |
|
213 sum_of_reclaimable_bytes += curr->reclaimable_bytes(); |
183 prev = curr; |
214 prev = curr; |
184 } |
215 } |
185 return _cache.verify(); |
216 guarantee(sum_of_reclaimable_bytes == _remainingReclaimableBytes, |
|
217 err_msg("reclaimable bytes inconsistent, " |
|
218 "remaining: "SIZE_FORMAT" sum: "SIZE_FORMAT, |
|
219 _remainingReclaimableBytes, sum_of_reclaimable_bytes)); |
|
220 return true; |
186 } |
221 } |
187 #endif |
222 #endif |
188 |
223 |
189 void |
224 void CollectionSetChooser::fillCache() { |
190 CollectionSetChooser::fillCache() { |
225 guarantee(false, "fillCache: don't call this any more"); |
191 while (!_cache.is_full() && (_curMarkedIndex < _numMarkedRegions)) { |
226 |
192 HeapRegion* hr = _markedRegions.at(_curMarkedIndex); |
227 while (!_cache.is_full() && (_curr_index < _length)) { |
|
228 HeapRegion* hr = _markedRegions.at(_curr_index); |
193 assert(hr != NULL, |
229 assert(hr != NULL, |
194 err_msg("Unexpected NULL hr in _markedRegions at index %d", |
230 err_msg("Unexpected NULL hr in _markedRegions at index %d", |
195 _curMarkedIndex)); |
231 _curr_index)); |
196 _curMarkedIndex += 1; |
232 _curr_index += 1; |
197 assert(!hr->is_young(), "should not be young!"); |
233 assert(!hr->is_young(), "should not be young!"); |
198 assert(hr->sort_index() == _curMarkedIndex-1, "sort_index invariant"); |
234 assert(hr->sort_index() == _curr_index-1, "sort_index invariant"); |
199 _markedRegions.at_put(hr->sort_index(), NULL); |
235 _markedRegions.at_put(hr->sort_index(), NULL); |
200 _cache.insert(hr); |
236 _cache.insert(hr); |
201 assert(!_cache.is_empty(), "cache should not be empty"); |
237 assert(!_cache.is_empty(), "cache should not be empty"); |
202 } |
238 } |
203 assert(verify(), "cache should be consistent"); |
239 assert(verify(), "cache should be consistent"); |
204 } |
240 } |
205 |
241 |
206 void |
242 void CollectionSetChooser::sortMarkedHeapRegions() { |
207 CollectionSetChooser::sortMarkedHeapRegions() { |
|
208 guarantee(_cache.is_empty(), "cache should be empty"); |
|
209 // First trim any unused portion of the top in the parallel case. |
243 // First trim any unused portion of the top in the parallel case. |
210 if (_first_par_unreserved_idx > 0) { |
244 if (_first_par_unreserved_idx > 0) { |
211 if (G1PrintParCleanupStats) { |
245 if (G1PrintParCleanupStats) { |
212 gclog_or_tty->print(" Truncating _markedRegions from %d to %d.\n", |
246 gclog_or_tty->print(" Truncating _markedRegions from %d to %d.\n", |
213 _markedRegions.length(), _first_par_unreserved_idx); |
247 _markedRegions.length(), _first_par_unreserved_idx); |
215 assert(_first_par_unreserved_idx <= _markedRegions.length(), |
249 assert(_first_par_unreserved_idx <= _markedRegions.length(), |
216 "Or we didn't reserved enough length"); |
250 "Or we didn't reserved enough length"); |
217 _markedRegions.trunc_to(_first_par_unreserved_idx); |
251 _markedRegions.trunc_to(_first_par_unreserved_idx); |
218 } |
252 } |
219 _markedRegions.sort(orderRegions); |
253 _markedRegions.sort(orderRegions); |
220 assert(_numMarkedRegions <= _markedRegions.length(), "Requirement"); |
254 assert(_length <= _markedRegions.length(), "Requirement"); |
221 assert(_numMarkedRegions == 0 |
255 assert(_length == 0 || _markedRegions.at(_length - 1) != NULL, |
222 || _markedRegions.at(_numMarkedRegions-1) != NULL, |
256 "Testing _length"); |
223 "Testing _numMarkedRegions"); |
257 assert(_length == _markedRegions.length() || |
224 assert(_numMarkedRegions == _markedRegions.length() |
258 _markedRegions.at(_length) == NULL, "Testing _length"); |
225 || _markedRegions.at(_numMarkedRegions) == NULL, |
|
226 "Testing _numMarkedRegions"); |
|
227 if (G1PrintParCleanupStats) { |
259 if (G1PrintParCleanupStats) { |
228 gclog_or_tty->print_cr(" Sorted %d marked regions.", _numMarkedRegions); |
260 gclog_or_tty->print_cr(" Sorted %d marked regions.", _length); |
229 } |
261 } |
230 for (int i = 0; i < _numMarkedRegions; i++) { |
262 for (int i = 0; i < _length; i++) { |
231 assert(_markedRegions.at(i) != NULL, "Should be true by sorting!"); |
263 assert(_markedRegions.at(i) != NULL, "Should be true by sorting!"); |
232 _markedRegions.at(i)->set_sort_index(i); |
264 _markedRegions.at(i)->set_sort_index(i); |
233 } |
265 } |
234 if (G1PrintRegionLivenessInfo) { |
266 if (G1PrintRegionLivenessInfo) { |
235 G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Sorting"); |
267 G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Sorting"); |
236 for (int i = 0; i < _numMarkedRegions; ++i) { |
268 for (int i = 0; i < _length; ++i) { |
237 HeapRegion* r = _markedRegions.at(i); |
269 HeapRegion* r = _markedRegions.at(i); |
238 cl.doHeapRegion(r); |
270 cl.doHeapRegion(r); |
239 } |
271 } |
240 } |
272 } |
241 assert(verify(), "should now be sorted"); |
273 assert(verify(), "CSet chooser verification"); |
242 } |
274 } |
243 |
275 |
244 void |
276 size_t CollectionSetChooser::calcMinOldCSetLength() { |
245 CollectionSetChooser::addMarkedHeapRegion(HeapRegion* hr) { |
277 // The min old CSet region bound is based on the maximum desired |
|
278 // number of mixed GCs after a cycle. I.e., even if some old regions |
|
279 // look expensive, we should add them to the CSet anyway to make |
|
280 // sure we go through the available old regions in no more than the |
|
281 // maximum desired number of mixed GCs. |
|
282 // |
|
283 // The calculation is based on the number of marked regions we added |
|
284 // to the CSet chooser in the first place, not how many remain, so |
|
285 // that the result is the same during all mixed GCs that follow a cycle. |
|
286 |
|
287 const size_t region_num = (size_t) _length; |
|
288 const size_t gc_num = (size_t) G1MaxMixedGCNum; |
|
289 size_t result = region_num / gc_num; |
|
290 // emulate ceiling |
|
291 if (result * gc_num < region_num) { |
|
292 result += 1; |
|
293 } |
|
294 return result; |
|
295 } |
|
296 |
|
297 size_t CollectionSetChooser::calcMaxOldCSetLength() { |
|
298 // The max old CSet region bound is based on the threshold expressed |
|
299 // as a percentage of the heap size. I.e., it should bound the |
|
300 // number of old regions added to the CSet irrespective of how many |
|
301 // of them are available. |
|
302 |
|
303 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
304 const size_t region_num = g1h->n_regions(); |
|
305 const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; |
|
306 size_t result = region_num * perc / 100; |
|
307 // emulate ceiling |
|
308 if (100 * result < region_num * perc) { |
|
309 result += 1; |
|
310 } |
|
311 return result; |
|
312 } |
|
313 |
|
314 void CollectionSetChooser::addMarkedHeapRegion(HeapRegion* hr) { |
246 assert(!hr->isHumongous(), |
315 assert(!hr->isHumongous(), |
247 "Humongous regions shouldn't be added to the collection set"); |
316 "Humongous regions shouldn't be added to the collection set"); |
248 assert(!hr->is_young(), "should not be young!"); |
317 assert(!hr->is_young(), "should not be young!"); |
249 _markedRegions.append(hr); |
318 _markedRegions.append(hr); |
250 _numMarkedRegions++; |
319 _length++; |
|
320 _remainingReclaimableBytes += hr->reclaimable_bytes(); |
251 hr->calc_gc_efficiency(); |
321 hr->calc_gc_efficiency(); |
252 } |
322 } |
253 |
323 |
254 void |
324 void CollectionSetChooser::prepareForAddMarkedHeapRegionsPar(size_t n_regions, |
255 CollectionSetChooser:: |
325 size_t chunkSize) { |
256 prepareForAddMarkedHeapRegionsPar(size_t n_regions, size_t chunkSize) { |
|
257 _first_par_unreserved_idx = 0; |
326 _first_par_unreserved_idx = 0; |
258 int n_threads = ParallelGCThreads; |
327 int n_threads = ParallelGCThreads; |
259 if (UseDynamicNumberOfGCThreads) { |
328 if (UseDynamicNumberOfGCThreads) { |
260 assert(G1CollectedHeap::heap()->workers()->active_workers() > 0, |
329 assert(G1CollectedHeap::heap()->workers()->active_workers() > 0, |
261 "Should have been set earlier"); |
330 "Should have been set earlier"); |
272 (n_regions + (chunkSize - 1)) / chunkSize * chunkSize; |
341 (n_regions + (chunkSize - 1)) / chunkSize * chunkSize; |
273 assert( aligned_n_regions % chunkSize == 0, "should be aligned" ); |
342 assert( aligned_n_regions % chunkSize == 0, "should be aligned" ); |
274 _markedRegions.at_put_grow((int)(aligned_n_regions + max_waste - 1), NULL); |
343 _markedRegions.at_put_grow((int)(aligned_n_regions + max_waste - 1), NULL); |
275 } |
344 } |
276 |
345 |
277 jint |
346 jint CollectionSetChooser::getParMarkedHeapRegionChunk(jint n_regions) { |
278 CollectionSetChooser::getParMarkedHeapRegionChunk(jint n_regions) { |
|
279 // Don't do this assert because this can be called at a point |
347 // Don't do this assert because this can be called at a point |
280 // where the loop up stream will not execute again but might |
348 // where the loop up stream will not execute again but might |
281 // try to claim more chunks (loop test has not been done yet). |
349 // try to claim more chunks (loop test has not been done yet). |
282 // assert(_markedRegions.length() > _first_par_unreserved_idx, |
350 // assert(_markedRegions.length() > _first_par_unreserved_idx, |
283 // "Striding beyond the marked regions"); |
351 // "Striding beyond the marked regions"); |
285 assert(_markedRegions.length() > res + n_regions - 1, |
353 assert(_markedRegions.length() > res + n_regions - 1, |
286 "Should already have been expanded"); |
354 "Should already have been expanded"); |
287 return res - n_regions; |
355 return res - n_regions; |
288 } |
356 } |
289 |
357 |
290 void |
358 void CollectionSetChooser::setMarkedHeapRegion(jint index, HeapRegion* hr) { |
291 CollectionSetChooser::setMarkedHeapRegion(jint index, HeapRegion* hr) { |
|
292 assert(_markedRegions.at(index) == NULL, "precondition"); |
359 assert(_markedRegions.at(index) == NULL, "precondition"); |
293 assert(!hr->is_young(), "should not be young!"); |
360 assert(!hr->is_young(), "should not be young!"); |
294 _markedRegions.at_put(index, hr); |
361 _markedRegions.at_put(index, hr); |
295 hr->calc_gc_efficiency(); |
362 hr->calc_gc_efficiency(); |
296 } |
363 } |
297 |
364 |
298 void |
365 void CollectionSetChooser::updateTotals(jint region_num, |
299 CollectionSetChooser::incNumMarkedHeapRegions(jint inc_by) { |
366 size_t reclaimable_bytes) { |
300 (void)Atomic::add(inc_by, &_numMarkedRegions); |
367 // Only take the lock if we actually need to update the totals. |
301 } |
368 if (region_num > 0) { |
302 |
369 assert(reclaimable_bytes > 0, "invariant"); |
303 void |
370 // We could have just used atomics instead of taking the |
304 CollectionSetChooser::clearMarkedHeapRegions(){ |
371 // lock. However, we currently don't have an atomic add for size_t. |
|
372 MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); |
|
373 _length += (int) region_num; |
|
374 _remainingReclaimableBytes += reclaimable_bytes; |
|
375 } else { |
|
376 assert(reclaimable_bytes == 0, "invariant"); |
|
377 } |
|
378 } |
|
379 |
|
380 void CollectionSetChooser::clearMarkedHeapRegions() { |
305 for (int i = 0; i < _markedRegions.length(); i++) { |
381 for (int i = 0; i < _markedRegions.length(); i++) { |
306 HeapRegion* r = _markedRegions.at(i); |
382 HeapRegion* r = _markedRegions.at(i); |
307 if (r != NULL) r->set_sort_index(-1); |
383 if (r != NULL) { |
|
384 r->set_sort_index(-1); |
|
385 } |
308 } |
386 } |
309 _markedRegions.clear(); |
387 _markedRegions.clear(); |
310 _curMarkedIndex = 0; |
388 _curr_index = 0; |
311 _numMarkedRegions = 0; |
389 _length = 0; |
312 _cache.clear(); |
390 _remainingReclaimableBytes = 0; |
313 }; |
391 }; |
314 |
|
315 void |
|
316 CollectionSetChooser::updateAfterFullCollection() { |
|
317 clearMarkedHeapRegions(); |
|
318 } |
|
319 |
|
320 // if time_remaining < 0.0, then this method should try to return |
|
321 // a region, whether it fits within the remaining time or not |
|
322 HeapRegion* |
|
323 CollectionSetChooser::getNextMarkedRegion(double time_remaining, |
|
324 double avg_prediction) { |
|
325 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
|
326 G1CollectorPolicy* g1p = g1h->g1_policy(); |
|
327 fillCache(); |
|
328 if (_cache.is_empty()) { |
|
329 assert(_curMarkedIndex == _numMarkedRegions, |
|
330 "if cache is empty, list should also be empty"); |
|
331 ergo_verbose0(ErgoCSetConstruction, |
|
332 "stop adding old regions to CSet", |
|
333 ergo_format_reason("cache is empty")); |
|
334 return NULL; |
|
335 } |
|
336 |
|
337 HeapRegion *hr = _cache.get_first(); |
|
338 assert(hr != NULL, "if cache not empty, first entry should be non-null"); |
|
339 double predicted_time = g1h->predict_region_elapsed_time_ms(hr, false); |
|
340 |
|
341 if (g1p->adaptive_young_list_length()) { |
|
342 if (time_remaining - predicted_time < 0.0) { |
|
343 g1h->check_if_region_is_too_expensive(predicted_time); |
|
344 ergo_verbose2(ErgoCSetConstruction, |
|
345 "stop adding old regions to CSet", |
|
346 ergo_format_reason("predicted old region time higher than remaining time") |
|
347 ergo_format_ms("predicted old region time") |
|
348 ergo_format_ms("remaining time"), |
|
349 predicted_time, time_remaining); |
|
350 return NULL; |
|
351 } |
|
352 } else { |
|
353 double threshold = 2.0 * avg_prediction; |
|
354 if (predicted_time > threshold) { |
|
355 ergo_verbose2(ErgoCSetConstruction, |
|
356 "stop adding old regions to CSet", |
|
357 ergo_format_reason("predicted old region time higher than threshold") |
|
358 ergo_format_ms("predicted old region time") |
|
359 ergo_format_ms("threshold"), |
|
360 predicted_time, threshold); |
|
361 return NULL; |
|
362 } |
|
363 } |
|
364 |
|
365 HeapRegion *hr2 = _cache.remove_first(); |
|
366 assert(hr == hr2, "cache contents should not have changed"); |
|
367 |
|
368 return hr; |
|
369 } |
|