Mon, 03 Aug 2009 12:59:30 -0700
6865703: G1: Parallelize hot card cache cleanup
Summary: Have the GC worker threads clear the hot card cache in parallel by having each worker thread claim a chunk of the card cache and process the cards in that chunk. The size of the chunks that each thread will claim is determined at VM initialization from the size of the card cache and the number of worker threads.
Reviewed-by: jmasa, tonyp
ysr@777 | 1 | /* |
xdono@1279 | 2 | * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. |
ysr@777 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ysr@777 | 4 | * |
ysr@777 | 5 | * This code is free software; you can redistribute it and/or modify it |
ysr@777 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ysr@777 | 7 | * published by the Free Software Foundation. |
ysr@777 | 8 | * |
ysr@777 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ysr@777 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ysr@777 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ysr@777 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
ysr@777 | 13 | * accompanied this code). |
ysr@777 | 14 | * |
ysr@777 | 15 | * You should have received a copy of the GNU General Public License version |
ysr@777 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
ysr@777 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ysr@777 | 18 | * |
ysr@777 | 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
ysr@777 | 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
ysr@777 | 21 | * have any questions. |
ysr@777 | 22 | * |
ysr@777 | 23 | */ |
ysr@777 | 24 | |
ysr@777 | 25 | # include "incls/_precompiled.incl" |
ysr@777 | 26 | # include "incls/_collectionSetChooser.cpp.incl" |
ysr@777 | 27 | |
ysr@777 | 28 | CSetChooserCache::CSetChooserCache() { |
ysr@777 | 29 | for (int i = 0; i < CacheLength; ++i) |
ysr@777 | 30 | _cache[i] = NULL; |
ysr@777 | 31 | clear(); |
ysr@777 | 32 | } |
ysr@777 | 33 | |
ysr@777 | 34 | void CSetChooserCache::clear() { |
ysr@777 | 35 | _occupancy = 0; |
ysr@777 | 36 | _first = 0; |
ysr@777 | 37 | for (int i = 0; i < CacheLength; ++i) { |
ysr@777 | 38 | HeapRegion *hr = _cache[i]; |
ysr@777 | 39 | if (hr != NULL) |
ysr@777 | 40 | hr->set_sort_index(-1); |
ysr@777 | 41 | _cache[i] = NULL; |
ysr@777 | 42 | } |
ysr@777 | 43 | } |
ysr@777 | 44 | |
ysr@777 | 45 | #ifndef PRODUCT |
ysr@777 | 46 | bool CSetChooserCache::verify() { |
ysr@777 | 47 | int index = _first; |
ysr@777 | 48 | HeapRegion *prev = NULL; |
ysr@777 | 49 | for (int i = 0; i < _occupancy; ++i) { |
ysr@777 | 50 | guarantee(_cache[index] != NULL, "cache entry should not be empty"); |
ysr@777 | 51 | HeapRegion *hr = _cache[index]; |
ysr@777 | 52 | guarantee(!hr->is_young(), "should not be young!"); |
ysr@777 | 53 | if (prev != NULL) { |
ysr@777 | 54 | guarantee(prev->gc_efficiency() >= hr->gc_efficiency(), |
ysr@777 | 55 | "cache should be correctly ordered"); |
ysr@777 | 56 | } |
ysr@777 | 57 | guarantee(hr->sort_index() == get_sort_index(index), |
ysr@777 | 58 | "sort index should be correct"); |
ysr@777 | 59 | index = trim_index(index + 1); |
ysr@777 | 60 | prev = hr; |
ysr@777 | 61 | } |
ysr@777 | 62 | |
ysr@777 | 63 | for (int i = 0; i < (CacheLength - _occupancy); ++i) { |
ysr@777 | 64 | guarantee(_cache[index] == NULL, "cache entry should be empty"); |
ysr@777 | 65 | index = trim_index(index + 1); |
ysr@777 | 66 | } |
ysr@777 | 67 | |
ysr@777 | 68 | guarantee(index == _first, "we should have reached where we started from"); |
ysr@777 | 69 | return true; |
ysr@777 | 70 | } |
ysr@777 | 71 | #endif // PRODUCT |
ysr@777 | 72 | |
ysr@777 | 73 | void CSetChooserCache::insert(HeapRegion *hr) { |
ysr@777 | 74 | assert(!is_full(), "cache should not be empty"); |
ysr@777 | 75 | hr->calc_gc_efficiency(); |
ysr@777 | 76 | |
ysr@777 | 77 | int empty_index; |
ysr@777 | 78 | if (_occupancy == 0) { |
ysr@777 | 79 | empty_index = _first; |
ysr@777 | 80 | } else { |
ysr@777 | 81 | empty_index = trim_index(_first + _occupancy); |
ysr@777 | 82 | assert(_cache[empty_index] == NULL, "last slot should be empty"); |
ysr@777 | 83 | int last_index = trim_index(empty_index - 1); |
ysr@777 | 84 | HeapRegion *last = _cache[last_index]; |
ysr@777 | 85 | assert(last != NULL,"as the cache is not empty, last should not be empty"); |
ysr@777 | 86 | while (empty_index != _first && |
ysr@777 | 87 | last->gc_efficiency() < hr->gc_efficiency()) { |
ysr@777 | 88 | _cache[empty_index] = last; |
ysr@777 | 89 | last->set_sort_index(get_sort_index(empty_index)); |
ysr@777 | 90 | empty_index = last_index; |
ysr@777 | 91 | last_index = trim_index(last_index - 1); |
ysr@777 | 92 | last = _cache[last_index]; |
ysr@777 | 93 | } |
ysr@777 | 94 | } |
ysr@777 | 95 | _cache[empty_index] = hr; |
ysr@777 | 96 | hr->set_sort_index(get_sort_index(empty_index)); |
ysr@777 | 97 | |
ysr@777 | 98 | ++_occupancy; |
ysr@777 | 99 | assert(verify(), "cache should be consistent"); |
ysr@777 | 100 | } |
ysr@777 | 101 | |
ysr@777 | 102 | HeapRegion *CSetChooserCache::remove_first() { |
ysr@777 | 103 | if (_occupancy > 0) { |
ysr@777 | 104 | assert(_cache[_first] != NULL, "cache should have at least one region"); |
ysr@777 | 105 | HeapRegion *ret = _cache[_first]; |
ysr@777 | 106 | _cache[_first] = NULL; |
ysr@777 | 107 | ret->set_sort_index(-1); |
ysr@777 | 108 | --_occupancy; |
ysr@777 | 109 | _first = trim_index(_first + 1); |
ysr@777 | 110 | assert(verify(), "cache should be consistent"); |
ysr@777 | 111 | return ret; |
ysr@777 | 112 | } else { |
ysr@777 | 113 | return NULL; |
ysr@777 | 114 | } |
ysr@777 | 115 | } |
ysr@777 | 116 | |
ysr@777 | 117 | // this is a bit expensive... but we expect that it should not be called |
ysr@777 | 118 | // to often. |
ysr@777 | 119 | void CSetChooserCache::remove(HeapRegion *hr) { |
ysr@777 | 120 | assert(_occupancy > 0, "cache should not be empty"); |
ysr@777 | 121 | assert(hr->sort_index() < -1, "should already be in the cache"); |
ysr@777 | 122 | int index = get_index(hr->sort_index()); |
ysr@777 | 123 | assert(_cache[index] == hr, "index should be correct"); |
ysr@777 | 124 | int next_index = trim_index(index + 1); |
ysr@777 | 125 | int last_index = trim_index(_first + _occupancy - 1); |
ysr@777 | 126 | while (index != last_index) { |
ysr@777 | 127 | assert(_cache[next_index] != NULL, "should not be null"); |
ysr@777 | 128 | _cache[index] = _cache[next_index]; |
ysr@777 | 129 | _cache[index]->set_sort_index(get_sort_index(index)); |
ysr@777 | 130 | |
ysr@777 | 131 | index = next_index; |
ysr@777 | 132 | next_index = trim_index(next_index+1); |
ysr@777 | 133 | } |
ysr@777 | 134 | assert(index == last_index, "should have reached the last one"); |
ysr@777 | 135 | _cache[index] = NULL; |
ysr@777 | 136 | hr->set_sort_index(-1); |
ysr@777 | 137 | --_occupancy; |
ysr@777 | 138 | assert(verify(), "cache should be consistent"); |
ysr@777 | 139 | } |
ysr@777 | 140 | |
ysr@777 | 141 | static inline int orderRegions(HeapRegion* hr1, HeapRegion* hr2) { |
ysr@777 | 142 | if (hr1 == NULL) { |
ysr@777 | 143 | if (hr2 == NULL) return 0; |
ysr@777 | 144 | else return 1; |
ysr@777 | 145 | } else if (hr2 == NULL) { |
ysr@777 | 146 | return -1; |
ysr@777 | 147 | } |
ysr@777 | 148 | if (hr2->gc_efficiency() < hr1->gc_efficiency()) return -1; |
ysr@777 | 149 | else if (hr1->gc_efficiency() < hr2->gc_efficiency()) return 1; |
ysr@777 | 150 | else return 0; |
ysr@777 | 151 | } |
ysr@777 | 152 | |
ysr@777 | 153 | static int orderRegions(HeapRegion** hr1p, HeapRegion** hr2p) { |
ysr@777 | 154 | return orderRegions(*hr1p, *hr2p); |
ysr@777 | 155 | } |
ysr@777 | 156 | |
ysr@777 | 157 | CollectionSetChooser::CollectionSetChooser() : |
ysr@777 | 158 | // The line below is the worst bit of C++ hackery I've ever written |
ysr@777 | 159 | // (Detlefs, 11/23). You should think of it as equivalent to |
ysr@777 | 160 | // "_regions(100, true)": initialize the growable array and inform it |
ysr@777 | 161 | // that it should allocate its elem array(s) on the C heap. The first |
ysr@777 | 162 | // argument, however, is actually a comma expression (new-expr, 100). |
ysr@777 | 163 | // The purpose of the new_expr is to inform the growable array that it |
ysr@777 | 164 | // is *already* allocated on the C heap: it uses the placement syntax to |
ysr@777 | 165 | // keep it from actually doing any allocation. |
ysr@777 | 166 | _markedRegions((ResourceObj::operator new (sizeof(GrowableArray<HeapRegion*>), |
ysr@777 | 167 | (void*)&_markedRegions, |
ysr@777 | 168 | ResourceObj::C_HEAP), |
ysr@777 | 169 | 100), |
ysr@777 | 170 | true), |
ysr@777 | 171 | _curMarkedIndex(0), |
ysr@777 | 172 | _numMarkedRegions(0), |
ysr@777 | 173 | _unmarked_age_1_returned_as_new(false), |
ysr@777 | 174 | _first_par_unreserved_idx(0) |
ysr@777 | 175 | {} |
ysr@777 | 176 | |
ysr@777 | 177 | |
ysr@777 | 178 | |
ysr@777 | 179 | #ifndef PRODUCT |
ysr@777 | 180 | bool CollectionSetChooser::verify() { |
ysr@777 | 181 | int index = 0; |
ysr@777 | 182 | guarantee(_curMarkedIndex <= _numMarkedRegions, |
ysr@777 | 183 | "_curMarkedIndex should be within bounds"); |
ysr@777 | 184 | while (index < _curMarkedIndex) { |
ysr@777 | 185 | guarantee(_markedRegions.at(index++) == NULL, |
ysr@777 | 186 | "all entries before _curMarkedIndex should be NULL"); |
ysr@777 | 187 | } |
ysr@777 | 188 | HeapRegion *prev = NULL; |
ysr@777 | 189 | while (index < _numMarkedRegions) { |
ysr@777 | 190 | HeapRegion *curr = _markedRegions.at(index++); |
ysr@777 | 191 | if (curr != NULL) { |
ysr@777 | 192 | int si = curr->sort_index(); |
ysr@777 | 193 | guarantee(!curr->is_young(), "should not be young!"); |
ysr@777 | 194 | guarantee(si > -1 && si == (index-1), "sort index invariant"); |
ysr@777 | 195 | if (prev != NULL) { |
ysr@777 | 196 | guarantee(orderRegions(prev, curr) != 1, "regions should be sorted"); |
ysr@777 | 197 | } |
ysr@777 | 198 | prev = curr; |
ysr@777 | 199 | } |
ysr@777 | 200 | } |
ysr@777 | 201 | return _cache.verify(); |
ysr@777 | 202 | } |
ysr@777 | 203 | #endif |
ysr@777 | 204 | |
ysr@777 | 205 | bool |
ysr@777 | 206 | CollectionSetChooser::addRegionToCache() { |
ysr@777 | 207 | assert(!_cache.is_full(), "cache should not be full"); |
ysr@777 | 208 | |
ysr@777 | 209 | HeapRegion *hr = NULL; |
ysr@777 | 210 | while (hr == NULL && _curMarkedIndex < _numMarkedRegions) { |
ysr@777 | 211 | hr = _markedRegions.at(_curMarkedIndex++); |
ysr@777 | 212 | } |
ysr@777 | 213 | if (hr == NULL) |
ysr@777 | 214 | return false; |
ysr@777 | 215 | assert(!hr->is_young(), "should not be young!"); |
ysr@777 | 216 | assert(hr->sort_index() == _curMarkedIndex-1, "sort_index invariant"); |
ysr@777 | 217 | _markedRegions.at_put(hr->sort_index(), NULL); |
ysr@777 | 218 | _cache.insert(hr); |
ysr@777 | 219 | assert(!_cache.is_empty(), "cache should not be empty"); |
ysr@777 | 220 | assert(verify(), "cache should be consistent"); |
ysr@777 | 221 | return false; |
ysr@777 | 222 | } |
ysr@777 | 223 | |
ysr@777 | 224 | void |
ysr@777 | 225 | CollectionSetChooser::fillCache() { |
ysr@777 | 226 | while (!_cache.is_full() && addRegionToCache()) { |
ysr@777 | 227 | } |
ysr@777 | 228 | } |
ysr@777 | 229 | |
ysr@777 | 230 | void |
ysr@777 | 231 | CollectionSetChooser::sortMarkedHeapRegions() { |
ysr@777 | 232 | guarantee(_cache.is_empty(), "cache should be empty"); |
ysr@777 | 233 | // First trim any unused portion of the top in the parallel case. |
ysr@777 | 234 | if (_first_par_unreserved_idx > 0) { |
ysr@777 | 235 | if (G1PrintParCleanupStats) { |
ysr@777 | 236 | gclog_or_tty->print(" Truncating _markedRegions from %d to %d.\n", |
ysr@777 | 237 | _markedRegions.length(), _first_par_unreserved_idx); |
ysr@777 | 238 | } |
ysr@777 | 239 | assert(_first_par_unreserved_idx <= _markedRegions.length(), |
ysr@777 | 240 | "Or we didn't reserved enough length"); |
ysr@777 | 241 | _markedRegions.trunc_to(_first_par_unreserved_idx); |
ysr@777 | 242 | } |
ysr@777 | 243 | _markedRegions.sort(orderRegions); |
ysr@777 | 244 | assert(_numMarkedRegions <= _markedRegions.length(), "Requirement"); |
ysr@777 | 245 | assert(_numMarkedRegions == 0 |
ysr@777 | 246 | || _markedRegions.at(_numMarkedRegions-1) != NULL, |
ysr@777 | 247 | "Testing _numMarkedRegions"); |
ysr@777 | 248 | assert(_numMarkedRegions == _markedRegions.length() |
ysr@777 | 249 | || _markedRegions.at(_numMarkedRegions) == NULL, |
ysr@777 | 250 | "Testing _numMarkedRegions"); |
ysr@777 | 251 | if (G1PrintParCleanupStats) { |
ysr@777 | 252 | gclog_or_tty->print_cr(" Sorted %d marked regions.", _numMarkedRegions); |
ysr@777 | 253 | } |
ysr@777 | 254 | for (int i = 0; i < _numMarkedRegions; i++) { |
ysr@777 | 255 | assert(_markedRegions.at(i) != NULL, "Should be true by sorting!"); |
ysr@777 | 256 | _markedRegions.at(i)->set_sort_index(i); |
ysr@777 | 257 | if (G1PrintRegionLivenessInfo > 0) { |
ysr@777 | 258 | if (i == 0) gclog_or_tty->print_cr("Sorted marked regions:"); |
ysr@777 | 259 | if (i < G1PrintRegionLivenessInfo || |
ysr@777 | 260 | (_numMarkedRegions-i) < G1PrintRegionLivenessInfo) { |
ysr@777 | 261 | HeapRegion* hr = _markedRegions.at(i); |
ysr@777 | 262 | size_t u = hr->used(); |
ysr@777 | 263 | gclog_or_tty->print_cr(" Region %d: %d used, %d max live, %5.2f%%.", |
ysr@777 | 264 | i, u, hr->max_live_bytes(), |
ysr@777 | 265 | 100.0*(float)hr->max_live_bytes()/(float)u); |
ysr@777 | 266 | } |
ysr@777 | 267 | } |
ysr@777 | 268 | } |
ysr@777 | 269 | if (G1PolicyVerbose > 1) |
ysr@777 | 270 | printSortedHeapRegions(); |
ysr@777 | 271 | assert(verify(), "should now be sorted"); |
ysr@777 | 272 | } |
ysr@777 | 273 | |
ysr@777 | 274 | void |
ysr@777 | 275 | printHeapRegion(HeapRegion *hr) { |
ysr@777 | 276 | if (hr->isHumongous()) |
ysr@777 | 277 | gclog_or_tty->print("H: "); |
ysr@777 | 278 | if (hr->in_collection_set()) |
ysr@777 | 279 | gclog_or_tty->print("CS: "); |
ysr@777 | 280 | gclog_or_tty->print_cr("Region " PTR_FORMAT " (%s%s) " |
ysr@777 | 281 | "[" PTR_FORMAT ", " PTR_FORMAT"] " |
ysr@777 | 282 | "Used: " SIZE_FORMAT "K, garbage: " SIZE_FORMAT "K.", |
ysr@777 | 283 | hr, hr->is_young() ? "Y " : " ", |
ysr@777 | 284 | hr->is_marked()? "M1" : "M0", |
ysr@777 | 285 | hr->bottom(), hr->end(), |
ysr@777 | 286 | hr->used()/K, hr->garbage_bytes()/K); |
ysr@777 | 287 | } |
ysr@777 | 288 | |
ysr@777 | 289 | void |
ysr@777 | 290 | CollectionSetChooser::addMarkedHeapRegion(HeapRegion* hr) { |
ysr@777 | 291 | assert(!hr->isHumongous(), |
ysr@777 | 292 | "Humongous regions shouldn't be added to the collection set"); |
ysr@777 | 293 | assert(!hr->is_young(), "should not be young!"); |
ysr@777 | 294 | _markedRegions.append(hr); |
ysr@777 | 295 | _numMarkedRegions++; |
ysr@777 | 296 | hr->calc_gc_efficiency(); |
ysr@777 | 297 | } |
ysr@777 | 298 | |
ysr@777 | 299 | void |
ysr@777 | 300 | CollectionSetChooser:: |
ysr@777 | 301 | prepareForAddMarkedHeapRegionsPar(size_t n_regions, size_t chunkSize) { |
ysr@777 | 302 | _first_par_unreserved_idx = 0; |
ysr@777 | 303 | size_t max_waste = ParallelGCThreads * chunkSize; |
ysr@777 | 304 | // it should be aligned with respect to chunkSize |
ysr@777 | 305 | size_t aligned_n_regions = |
ysr@777 | 306 | (n_regions + (chunkSize - 1)) / chunkSize * chunkSize; |
ysr@777 | 307 | assert( aligned_n_regions % chunkSize == 0, "should be aligned" ); |
ysr@777 | 308 | _markedRegions.at_put_grow((int)(aligned_n_regions + max_waste - 1), NULL); |
ysr@777 | 309 | } |
ysr@777 | 310 | |
ysr@777 | 311 | jint |
ysr@777 | 312 | CollectionSetChooser::getParMarkedHeapRegionChunk(jint n_regions) { |
ysr@777 | 313 | jint res = Atomic::add(n_regions, &_first_par_unreserved_idx); |
ysr@777 | 314 | assert(_markedRegions.length() > res + n_regions - 1, |
ysr@777 | 315 | "Should already have been expanded"); |
ysr@777 | 316 | return res - n_regions; |
ysr@777 | 317 | } |
ysr@777 | 318 | |
ysr@777 | 319 | void |
ysr@777 | 320 | CollectionSetChooser::setMarkedHeapRegion(jint index, HeapRegion* hr) { |
ysr@777 | 321 | assert(_markedRegions.at(index) == NULL, "precondition"); |
ysr@777 | 322 | assert(!hr->is_young(), "should not be young!"); |
ysr@777 | 323 | _markedRegions.at_put(index, hr); |
ysr@777 | 324 | hr->calc_gc_efficiency(); |
ysr@777 | 325 | } |
ysr@777 | 326 | |
ysr@777 | 327 | void |
ysr@777 | 328 | CollectionSetChooser::incNumMarkedHeapRegions(jint inc_by) { |
ysr@777 | 329 | (void)Atomic::add(inc_by, &_numMarkedRegions); |
ysr@777 | 330 | } |
ysr@777 | 331 | |
ysr@777 | 332 | void |
ysr@777 | 333 | CollectionSetChooser::clearMarkedHeapRegions(){ |
ysr@777 | 334 | for (int i = 0; i < _markedRegions.length(); i++) { |
ysr@777 | 335 | HeapRegion* r = _markedRegions.at(i); |
ysr@777 | 336 | if (r != NULL) r->set_sort_index(-1); |
ysr@777 | 337 | } |
ysr@777 | 338 | _markedRegions.clear(); |
ysr@777 | 339 | _curMarkedIndex = 0; |
ysr@777 | 340 | _numMarkedRegions = 0; |
ysr@777 | 341 | _cache.clear(); |
ysr@777 | 342 | }; |
ysr@777 | 343 | |
ysr@777 | 344 | void |
ysr@777 | 345 | CollectionSetChooser::updateAfterFullCollection() { |
ysr@777 | 346 | G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
ysr@777 | 347 | clearMarkedHeapRegions(); |
ysr@777 | 348 | } |
ysr@777 | 349 | |
ysr@777 | 350 | void |
ysr@777 | 351 | CollectionSetChooser::printSortedHeapRegions() { |
ysr@777 | 352 | gclog_or_tty->print_cr("Printing %d Heap Regions sorted by amount of known garbage", |
ysr@777 | 353 | _numMarkedRegions); |
ysr@777 | 354 | for (int i = 0; i < _markedRegions.length(); i++) { |
ysr@777 | 355 | printHeapRegion(_markedRegions.at(i)); |
ysr@777 | 356 | } |
ysr@777 | 357 | gclog_or_tty->print_cr("Done sorted heap region print"); |
ysr@777 | 358 | } |
ysr@777 | 359 | |
ysr@777 | 360 | void CollectionSetChooser::removeRegion(HeapRegion *hr) { |
ysr@777 | 361 | int si = hr->sort_index(); |
ysr@777 | 362 | assert(si == -1 || hr->is_marked(), "Sort index not valid."); |
ysr@777 | 363 | if (si > -1) { |
ysr@777 | 364 | assert(_markedRegions.at(si) == hr, "Sort index not valid." ); |
ysr@777 | 365 | _markedRegions.at_put(si, NULL); |
ysr@777 | 366 | } else if (si < -1) { |
ysr@777 | 367 | assert(_cache.region_in_cache(hr), "should be in the cache"); |
ysr@777 | 368 | _cache.remove(hr); |
ysr@777 | 369 | assert(hr->sort_index() == -1, "sort index invariant"); |
ysr@777 | 370 | } |
ysr@777 | 371 | hr->set_sort_index(-1); |
ysr@777 | 372 | } |
ysr@777 | 373 | |
ysr@777 | 374 | // if time_remaining < 0.0, then this method should try to return |
ysr@777 | 375 | // a region, whether it fits within the remaining time or not |
ysr@777 | 376 | HeapRegion* |
ysr@777 | 377 | CollectionSetChooser::getNextMarkedRegion(double time_remaining, |
ysr@777 | 378 | double avg_prediction) { |
ysr@777 | 379 | G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
ysr@777 | 380 | G1CollectorPolicy* g1p = g1h->g1_policy(); |
ysr@777 | 381 | fillCache(); |
ysr@777 | 382 | if (_cache.is_empty()) { |
ysr@777 | 383 | assert(_curMarkedIndex == _numMarkedRegions, |
ysr@777 | 384 | "if cache is empty, list should also be empty"); |
ysr@777 | 385 | return NULL; |
ysr@777 | 386 | } |
ysr@777 | 387 | |
ysr@777 | 388 | HeapRegion *hr = _cache.get_first(); |
ysr@777 | 389 | assert(hr != NULL, "if cache not empty, first entry should be non-null"); |
ysr@777 | 390 | double predicted_time = g1h->predict_region_elapsed_time_ms(hr, false); |
ysr@777 | 391 | |
ysr@777 | 392 | if (g1p->adaptive_young_list_length()) { |
ysr@777 | 393 | if (time_remaining - predicted_time < 0.0) { |
ysr@777 | 394 | g1h->check_if_region_is_too_expensive(predicted_time); |
ysr@777 | 395 | return NULL; |
ysr@777 | 396 | } |
ysr@777 | 397 | } else { |
ysr@777 | 398 | if (predicted_time > 2.0 * avg_prediction) { |
ysr@777 | 399 | return NULL; |
ysr@777 | 400 | } |
ysr@777 | 401 | } |
ysr@777 | 402 | |
ysr@777 | 403 | HeapRegion *hr2 = _cache.remove_first(); |
ysr@777 | 404 | assert(hr == hr2, "cache contents should not have changed"); |
ysr@777 | 405 | |
ysr@777 | 406 | return hr; |
ysr@777 | 407 | } |