src/share/vm/gc_implementation/g1/collectionSetChooser.cpp

Mon, 02 Aug 2010 12:51:43 -0700

author
johnc
date
Mon, 02 Aug 2010 12:51:43 -0700
changeset 2060
2d160770d2e5
parent 1907
c18cbe5936b8
child 2043
2dfd013a7465
permissions
-rw-r--r--

6814437: G1: remove the _new_refs array
Summary: The per-worker _new_refs array is used to hold references that point into the collection set. It is populated during RSet updating and subsequently processed. In the event of an evacuation failure it processed again to recreate the RSets of regions in the collection set. Remove the per-worker _new_refs array by processing the references directly. Use a DirtyCardQueue to hold the cards containing the references so that the RSets of regions in the collection set can be recreated when handling an evacuation failure.
Reviewed-by: iveresov, jmasa, tonyp

ysr@777 1 /*
trims@1907 2 * Copyright (c) 2001, 2009, Oracle and/or its affiliates. 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 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * 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);
johnc@1538 354
johnc@1538 355 DEBUG_ONLY(int marked_count = 0;)
ysr@777 356 for (int i = 0; i < _markedRegions.length(); i++) {
johnc@1538 357 HeapRegion* r = _markedRegions.at(i);
johnc@1538 358 if (r != NULL) {
johnc@1538 359 printHeapRegion(r);
johnc@1538 360 DEBUG_ONLY(marked_count++;)
johnc@1538 361 }
ysr@777 362 }
johnc@1538 363 assert(marked_count == _numMarkedRegions, "must be");
ysr@777 364 gclog_or_tty->print_cr("Done sorted heap region print");
ysr@777 365 }
ysr@777 366
ysr@777 367 void CollectionSetChooser::removeRegion(HeapRegion *hr) {
ysr@777 368 int si = hr->sort_index();
ysr@777 369 assert(si == -1 || hr->is_marked(), "Sort index not valid.");
ysr@777 370 if (si > -1) {
ysr@777 371 assert(_markedRegions.at(si) == hr, "Sort index not valid." );
ysr@777 372 _markedRegions.at_put(si, NULL);
ysr@777 373 } else if (si < -1) {
ysr@777 374 assert(_cache.region_in_cache(hr), "should be in the cache");
ysr@777 375 _cache.remove(hr);
ysr@777 376 assert(hr->sort_index() == -1, "sort index invariant");
ysr@777 377 }
ysr@777 378 hr->set_sort_index(-1);
ysr@777 379 }
ysr@777 380
ysr@777 381 // if time_remaining < 0.0, then this method should try to return
ysr@777 382 // a region, whether it fits within the remaining time or not
ysr@777 383 HeapRegion*
ysr@777 384 CollectionSetChooser::getNextMarkedRegion(double time_remaining,
ysr@777 385 double avg_prediction) {
ysr@777 386 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 387 G1CollectorPolicy* g1p = g1h->g1_policy();
ysr@777 388 fillCache();
ysr@777 389 if (_cache.is_empty()) {
ysr@777 390 assert(_curMarkedIndex == _numMarkedRegions,
ysr@777 391 "if cache is empty, list should also be empty");
ysr@777 392 return NULL;
ysr@777 393 }
ysr@777 394
ysr@777 395 HeapRegion *hr = _cache.get_first();
ysr@777 396 assert(hr != NULL, "if cache not empty, first entry should be non-null");
ysr@777 397 double predicted_time = g1h->predict_region_elapsed_time_ms(hr, false);
ysr@777 398
ysr@777 399 if (g1p->adaptive_young_list_length()) {
ysr@777 400 if (time_remaining - predicted_time < 0.0) {
ysr@777 401 g1h->check_if_region_is_too_expensive(predicted_time);
ysr@777 402 return NULL;
ysr@777 403 }
ysr@777 404 } else {
ysr@777 405 if (predicted_time > 2.0 * avg_prediction) {
ysr@777 406 return NULL;
ysr@777 407 }
ysr@777 408 }
ysr@777 409
ysr@777 410 HeapRegion *hr2 = _cache.remove_first();
ysr@777 411 assert(hr == hr2, "cache contents should not have changed");
ysr@777 412
ysr@777 413 return hr;
ysr@777 414 }

mercurial