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

Tue, 21 Aug 2012 14:10:39 -0700

author
johnc
date
Tue, 21 Aug 2012 14:10:39 -0700
changeset 3998
7383557659bd
parent 3924
3a431b605145
child 5078
194f52aa2f23
permissions
-rw-r--r--

7185699: G1: Prediction model discrepancies
Summary: Correct the result value of G1CollectedHeap::pending_card_num(). Change the code that calculates the GC efficiency of a non-young heap region to use historical data from mixed GCs and the actual number of live bytes when predicting how long it would take to collect the region. Changes were also reviewed by Thomas Schatzl.
Reviewed-by: azeemj, brutisso

ysr@777 1 /*
brutisso@3923 2 * Copyright (c) 2001, 2012, 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
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
stefank@2314 27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
stefank@2314 28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 29 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
brutisso@3923 30 #include "gc_implementation/g1/g1GCPhaseTimes.hpp"
stefank@2314 31 #include "gc_implementation/g1/g1RemSet.hpp"
stefank@2314 32 #include "gc_implementation/g1/heapRegionSeq.inline.hpp"
stefank@2314 33 #include "memory/space.inline.hpp"
stefank@2314 34 #include "runtime/atomic.hpp"
johnc@2713 35 #include "runtime/java.hpp"
stefank@2314 36 #include "utilities/copy.hpp"
ysr@777 37
johnc@1325 38 // Possible sizes for the card counts cache: odd primes that roughly double in size.
johnc@1325 39 // (See jvmtiTagMap.cpp).
johnc@2713 40
johnc@2713 41 #define MAX_SIZE ((size_t) -1)
johnc@2713 42
johnc@2713 43 size_t ConcurrentG1Refine::_cc_cache_sizes[] = {
johnc@2713 44 16381, 32771, 76831, 150001, 307261,
johnc@2713 45 614563, 1228891, 2457733, 4915219, 9830479,
johnc@2713 46 19660831, 39321619, 78643219, 157286461, MAX_SIZE
johnc@1325 47 };
johnc@1325 48
ysr@777 49 ConcurrentG1Refine::ConcurrentG1Refine() :
johnc@1325 50 _card_counts(NULL), _card_epochs(NULL),
johnc@2713 51 _n_card_counts(0), _max_cards(0), _max_n_card_counts(0),
johnc@1325 52 _cache_size_index(0), _expand_card_counts(false),
ysr@777 53 _hot_cache(NULL),
ysr@777 54 _def_use_cache(false), _use_cache(false),
tonyp@2716 55 // We initialize the epochs of the array to 0. By initializing
tonyp@2716 56 // _n_periods to 1 and not 0 we automatically invalidate all the
tonyp@2716 57 // entries on the array. Otherwise we might accidentally think that
tonyp@2716 58 // we claimed a card that was in fact never set (see CR7033292).
tonyp@2716 59 _n_periods(1),
iveresov@1229 60 _threads(NULL), _n_threads(0)
ysr@777 61 {
iveresov@1546 62
iveresov@1546 63 // Ergomonically select initial concurrent refinement parameters
tonyp@1717 64 if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
tonyp@1717 65 FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, MAX2<int>(ParallelGCThreads, 1));
iveresov@1546 66 }
tonyp@1717 67 set_green_zone(G1ConcRefinementGreenZone);
iveresov@1546 68
tonyp@1717 69 if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) {
tonyp@1717 70 FLAG_SET_DEFAULT(G1ConcRefinementYellowZone, green_zone() * 3);
iveresov@1546 71 }
tonyp@1717 72 set_yellow_zone(MAX2<int>(G1ConcRefinementYellowZone, green_zone()));
iveresov@1546 73
tonyp@1717 74 if (FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) {
tonyp@1717 75 FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2);
iveresov@1546 76 }
tonyp@1717 77 set_red_zone(MAX2<int>(G1ConcRefinementRedZone, yellow_zone()));
iveresov@1546 78 _n_worker_threads = thread_num();
iveresov@1546 79 // We need one extra thread to do the young gen rset size sampling.
iveresov@1546 80 _n_threads = _n_worker_threads + 1;
iveresov@1546 81 reset_threshold_step();
iveresov@1546 82
zgu@3900 83 _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads, mtGC);
iveresov@1546 84 int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids();
iveresov@1546 85 ConcurrentG1RefineThread *next = NULL;
iveresov@1546 86 for (int i = _n_threads - 1; i >= 0; i--) {
iveresov@1546 87 ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i);
iveresov@1546 88 assert(t != NULL, "Conc refine should have been created");
iveresov@1546 89 assert(t->cg1r() == this, "Conc refine thread should refer to this");
iveresov@1546 90 _threads[i] = t;
iveresov@1546 91 next = t;
ysr@777 92 }
ysr@777 93 }
ysr@777 94
iveresov@1546 95 void ConcurrentG1Refine::reset_threshold_step() {
tonyp@1717 96 if (FLAG_IS_DEFAULT(G1ConcRefinementThresholdStep)) {
iveresov@1546 97 _thread_threshold_step = (yellow_zone() - green_zone()) / (worker_thread_num() + 1);
iveresov@1546 98 } else {
tonyp@1717 99 _thread_threshold_step = G1ConcRefinementThresholdStep;
iveresov@1230 100 }
iveresov@1546 101 }
iveresov@1546 102
iveresov@1546 103 int ConcurrentG1Refine::thread_num() {
tonyp@1717 104 return MAX2<int>((G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads : ParallelGCThreads, 1);
iveresov@1230 105 }
iveresov@1230 106
ysr@777 107 void ConcurrentG1Refine::init() {
johnc@1325 108 if (G1ConcRSLogCacheSize > 0) {
johnc@1325 109 _g1h = G1CollectedHeap::heap();
johnc@2713 110
johnc@2713 111 _max_cards = _g1h->max_capacity() >> CardTableModRefBS::card_shift;
johnc@2713 112 _max_n_card_counts = _max_cards * G1MaxHotCardCountSizePercent / 100;
johnc@1325 113
johnc@1325 114 size_t max_card_num = ((size_t)1 << (sizeof(unsigned)*BitsPerByte-1)) - 1;
johnc@2713 115 guarantee(_max_cards < max_card_num, "card_num representation");
johnc@1325 116
johnc@2713 117 // We need _n_card_counts to be less than _max_n_card_counts here
johnc@2713 118 // so that the expansion call (below) actually allocates the
johnc@2713 119 // _counts and _epochs arrays.
johnc@2713 120 assert(_n_card_counts == 0, "pre-condition");
johnc@2713 121 assert(_max_n_card_counts > 0, "pre-condition");
johnc@2713 122
johnc@2713 123 // Find the index into cache size array that is of a size that's
johnc@2713 124 // large enough to hold desired_sz.
johnc@2713 125 size_t desired_sz = _max_cards / InitialCacheFraction;
johnc@2713 126 int desired_sz_index = 0;
johnc@2713 127 while (_cc_cache_sizes[desired_sz_index] < desired_sz) {
johnc@2713 128 desired_sz_index += 1;
johnc@2713 129 assert(desired_sz_index < MAX_CC_CACHE_INDEX, "invariant");
johnc@1325 130 }
johnc@2713 131 assert(desired_sz_index < MAX_CC_CACHE_INDEX, "invariant");
johnc@1325 132
johnc@2713 133 // If the desired_sz value is between two sizes then
johnc@2713 134 // _cc_cache_sizes[desired_sz_index-1] < desired_sz <= _cc_cache_sizes[desired_sz_index]
johnc@2713 135 // we will start with the lower size in the optimistic expectation that
johnc@2713 136 // we will not need to expand up. Note desired_sz_index could also be 0.
johnc@2713 137 if (desired_sz_index > 0 &&
johnc@2713 138 _cc_cache_sizes[desired_sz_index] > desired_sz) {
johnc@2713 139 desired_sz_index -= 1;
johnc@2713 140 }
johnc@1325 141
johnc@2713 142 if (!expand_card_count_cache(desired_sz_index)) {
johnc@2713 143 // Allocation was unsuccessful - exit
johnc@2713 144 vm_exit_during_initialization("Could not reserve enough space for card count cache");
johnc@2713 145 }
johnc@2713 146 assert(_n_card_counts > 0, "post-condition");
johnc@2713 147 assert(_cache_size_index == desired_sz_index, "post-condition");
johnc@1325 148
johnc@1325 149 Copy::fill_to_bytes(&_card_counts[0],
johnc@1325 150 _n_card_counts * sizeof(CardCountCacheEntry));
johnc@1325 151 Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry));
johnc@1325 152
johnc@1325 153 ModRefBarrierSet* bs = _g1h->mr_bs();
ysr@777 154 guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition");
johnc@1325 155 _ct_bs = (CardTableModRefBS*)bs;
johnc@1325 156 _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start());
johnc@1325 157
ysr@777 158 _def_use_cache = true;
ysr@777 159 _use_cache = true;
ysr@777 160 _hot_cache_size = (1 << G1ConcRSLogCacheSize);
zgu@3900 161 _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size, mtGC);
ysr@777 162 _n_hot = 0;
ysr@777 163 _hot_cache_idx = 0;
johnc@1324 164
johnc@1324 165 // For refining the cards in the hot cache in parallel
johnc@1324 166 int n_workers = (ParallelGCThreads > 0 ?
johnc@1325 167 _g1h->workers()->total_workers() : 1);
johnc@1324 168 _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers);
johnc@1324 169 _hot_cache_par_claimed_idx = 0;
ysr@777 170 }
ysr@777 171 }
ysr@777 172
iveresov@1229 173 void ConcurrentG1Refine::stop() {
iveresov@1229 174 if (_threads != NULL) {
iveresov@1229 175 for (int i = 0; i < _n_threads; i++) {
iveresov@1229 176 _threads[i]->stop();
iveresov@1229 177 }
iveresov@1229 178 }
iveresov@1229 179 }
iveresov@1229 180
iveresov@1546 181 void ConcurrentG1Refine::reinitialize_threads() {
iveresov@1546 182 reset_threshold_step();
iveresov@1546 183 if (_threads != NULL) {
iveresov@1546 184 for (int i = 0; i < _n_threads; i++) {
iveresov@1546 185 _threads[i]->initialize();
iveresov@1546 186 }
iveresov@1546 187 }
iveresov@1546 188 }
iveresov@1546 189
ysr@777 190 ConcurrentG1Refine::~ConcurrentG1Refine() {
johnc@1325 191 if (G1ConcRSLogCacheSize > 0) {
johnc@2713 192 // Please see the comment in allocate_card_count_cache
johnc@2713 193 // for why we call os::malloc() and os::free() directly.
ysr@777 194 assert(_card_counts != NULL, "Logic");
zgu@3900 195 os::free(_card_counts, mtGC);
johnc@1325 196 assert(_card_epochs != NULL, "Logic");
zgu@3900 197 os::free(_card_epochs, mtGC);
johnc@2713 198
ysr@777 199 assert(_hot_cache != NULL, "Logic");
zgu@3900 200 FREE_C_HEAP_ARRAY(jbyte*, _hot_cache, mtGC);
ysr@777 201 }
iveresov@1229 202 if (_threads != NULL) {
iveresov@1229 203 for (int i = 0; i < _n_threads; i++) {
iveresov@1229 204 delete _threads[i];
iveresov@1229 205 }
zgu@3900 206 FREE_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _threads, mtGC);
ysr@777 207 }
ysr@777 208 }
ysr@777 209
iveresov@1229 210 void ConcurrentG1Refine::threads_do(ThreadClosure *tc) {
iveresov@1229 211 if (_threads != NULL) {
iveresov@1229 212 for (int i = 0; i < _n_threads; i++) {
iveresov@1229 213 tc->do_thread(_threads[i]);
iveresov@1229 214 }
ysr@777 215 }
ysr@777 216 }
ysr@777 217
johnc@1325 218 bool ConcurrentG1Refine::is_young_card(jbyte* card_ptr) {
johnc@1325 219 HeapWord* start = _ct_bs->addr_for(card_ptr);
johnc@1325 220 HeapRegion* r = _g1h->heap_region_containing(start);
johnc@1325 221 if (r != NULL && r->is_young()) {
johnc@1325 222 return true;
johnc@1325 223 }
johnc@1325 224 // This card is not associated with a heap region
johnc@1325 225 // so can't be young.
johnc@1325 226 return false;
ysr@777 227 }
ysr@777 228
johnc@1325 229 jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* defer) {
johnc@1325 230 unsigned new_card_num = ptr_2_card_num(card_ptr);
johnc@1325 231 unsigned bucket = hash(new_card_num);
johnc@1325 232 assert(0 <= bucket && bucket < _n_card_counts, "Bounds");
johnc@1325 233
johnc@1325 234 CardCountCacheEntry* count_ptr = &_card_counts[bucket];
johnc@1325 235 CardEpochCacheEntry* epoch_ptr = &_card_epochs[bucket];
johnc@1325 236
johnc@1325 237 // We have to construct a new entry if we haven't updated the counts
johnc@1325 238 // during the current period, or if the count was updated for a
johnc@1325 239 // different card number.
johnc@1325 240 unsigned int new_epoch = (unsigned int) _n_periods;
johnc@1325 241 julong new_epoch_entry = make_epoch_entry(new_card_num, new_epoch);
johnc@1325 242
johnc@1325 243 while (true) {
johnc@1325 244 // Fetch the previous epoch value
johnc@1325 245 julong prev_epoch_entry = epoch_ptr->_value;
johnc@1325 246 julong cas_res;
johnc@1325 247
johnc@1325 248 if (extract_epoch(prev_epoch_entry) != new_epoch) {
johnc@1325 249 // This entry has not yet been updated during this period.
johnc@1325 250 // Note: we update the epoch value atomically to ensure
johnc@1325 251 // that there is only one winner that updates the cached
johnc@1325 252 // card_ptr value even though all the refine threads share
johnc@1325 253 // the same epoch value.
johnc@1325 254
johnc@1325 255 cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry,
johnc@1325 256 (volatile jlong*)&epoch_ptr->_value,
johnc@1325 257 (jlong) prev_epoch_entry);
johnc@1325 258
johnc@1325 259 if (cas_res == prev_epoch_entry) {
johnc@1325 260 // We have successfully won the race to update the
johnc@1325 261 // epoch and card_num value. Make it look like the
johnc@1325 262 // count and eviction count were previously cleared.
johnc@1325 263 count_ptr->_count = 1;
johnc@1325 264 count_ptr->_evict_count = 0;
johnc@1325 265 *count = 0;
johnc@1325 266 // We can defer the processing of card_ptr
johnc@1325 267 *defer = true;
johnc@1325 268 return card_ptr;
johnc@1325 269 }
johnc@1325 270 // We did not win the race to update the epoch field, so some other
johnc@1325 271 // thread must have done it. The value that gets returned by CAS
johnc@1325 272 // should be the new epoch value.
johnc@1325 273 assert(extract_epoch(cas_res) == new_epoch, "unexpected epoch");
johnc@1325 274 // We could 'continue' here or just re-read the previous epoch value
johnc@1325 275 prev_epoch_entry = epoch_ptr->_value;
johnc@1325 276 }
johnc@1325 277
johnc@1325 278 // The epoch entry for card_ptr has been updated during this period.
johnc@1325 279 unsigned old_card_num = extract_card_num(prev_epoch_entry);
johnc@1325 280
johnc@1325 281 // The card count that will be returned to caller
johnc@1325 282 *count = count_ptr->_count;
johnc@1325 283
johnc@1325 284 // Are we updating the count for the same card?
johnc@1325 285 if (new_card_num == old_card_num) {
johnc@1325 286 // Same card - just update the count. We could have more than one
johnc@1325 287 // thread racing to update count for the current card. It should be
johnc@1325 288 // OK not to use a CAS as the only penalty should be some missed
johnc@1325 289 // increments of the count which delays identifying the card as "hot".
johnc@1325 290
johnc@1325 291 if (*count < max_jubyte) count_ptr->_count++;
johnc@1325 292 // We can defer the processing of card_ptr
johnc@1325 293 *defer = true;
johnc@1325 294 return card_ptr;
johnc@1325 295 }
johnc@1325 296
johnc@1325 297 // Different card - evict old card info
johnc@1325 298 if (count_ptr->_evict_count < max_jubyte) count_ptr->_evict_count++;
johnc@1325 299 if (count_ptr->_evict_count > G1CardCountCacheExpandThreshold) {
johnc@1325 300 // Trigger a resize the next time we clear
johnc@1325 301 _expand_card_counts = true;
johnc@1325 302 }
johnc@1325 303
johnc@1325 304 cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry,
johnc@1325 305 (volatile jlong*)&epoch_ptr->_value,
johnc@1325 306 (jlong) prev_epoch_entry);
johnc@1325 307
johnc@1325 308 if (cas_res == prev_epoch_entry) {
johnc@1325 309 // We successfully updated the card num value in the epoch entry
johnc@1325 310 count_ptr->_count = 0; // initialize counter for new card num
johnc@2021 311 jbyte* old_card_ptr = card_num_2_ptr(old_card_num);
johnc@1325 312
johnc@1325 313 // Even though the region containg the card at old_card_num was not
johnc@1325 314 // in the young list when old_card_num was recorded in the epoch
johnc@1325 315 // cache it could have been added to the free list and subsequently
johnc@2021 316 // added to the young list in the intervening time. See CR 6817995.
johnc@2021 317 // We do not deal with this case here - it will be handled in
johnc@2021 318 // HeapRegion::oops_on_card_seq_iterate_careful after it has been
johnc@2021 319 // determined that the region containing the card has been allocated
johnc@2021 320 // to, and it's safe to check the young type of the region.
johnc@1325 321
johnc@1325 322 // We do not want to defer processing of card_ptr in this case
johnc@1325 323 // (we need to refine old_card_ptr and card_ptr)
johnc@1325 324 *defer = false;
johnc@1325 325 return old_card_ptr;
johnc@1325 326 }
johnc@1325 327 // Someone else beat us - try again.
johnc@1325 328 }
johnc@1325 329 }
johnc@1325 330
johnc@1325 331 jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
johnc@1325 332 int count;
johnc@1325 333 jbyte* cached_ptr = add_card_count(card_ptr, &count, defer);
johnc@1325 334 assert(cached_ptr != NULL, "bad cached card ptr");
johnc@1681 335
johnc@2021 336 // We've just inserted a card pointer into the card count cache
johnc@2021 337 // and got back the card that we just inserted or (evicted) the
johnc@2021 338 // previous contents of that count slot.
johnc@1681 339
johnc@2021 340 // The card we got back could be in a young region. When the
johnc@2021 341 // returned card (if evicted) was originally inserted, we had
johnc@2021 342 // determined that its containing region was not young. However
johnc@2021 343 // it is possible for the region to be freed during a cleanup
johnc@2021 344 // pause, then reallocated and tagged as young which will result
johnc@2021 345 // in the returned card residing in a young region.
johnc@2021 346 //
johnc@2021 347 // We do not deal with this case here - the change from non-young
johnc@2021 348 // to young could be observed at any time - it will be handled in
johnc@2021 349 // HeapRegion::oops_on_card_seq_iterate_careful after it has been
johnc@2021 350 // determined that the region containing the card has been allocated
johnc@2021 351 // to.
johnc@1325 352
johnc@1325 353 // The card pointer we obtained from card count cache is not hot
johnc@1325 354 // so do not store it in the cache; return it for immediate
johnc@1325 355 // refining.
ysr@777 356 if (count < G1ConcRSHotCardLimit) {
johnc@1325 357 return cached_ptr;
ysr@777 358 }
johnc@1325 359
johnc@2021 360 // Otherwise, the pointer we got from the _card_counts cache is hot.
ysr@777 361 jbyte* res = NULL;
ysr@777 362 MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
ysr@777 363 if (_n_hot == _hot_cache_size) {
ysr@777 364 res = _hot_cache[_hot_cache_idx];
ysr@777 365 _n_hot--;
ysr@777 366 }
ysr@777 367 // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx.
johnc@1325 368 _hot_cache[_hot_cache_idx] = cached_ptr;
ysr@777 369 _hot_cache_idx++;
ysr@777 370 if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0;
ysr@777 371 _n_hot++;
johnc@1325 372
johnc@2021 373 // The card obtained from the hot card cache could be in a young
johnc@2021 374 // region. See above on how this can happen.
johnc@1325 375
ysr@777 376 return res;
ysr@777 377 }
ysr@777 378
johnc@2060 379 void ConcurrentG1Refine::clean_up_cache(int worker_i,
johnc@2060 380 G1RemSet* g1rs,
johnc@2060 381 DirtyCardQueue* into_cset_dcq) {
ysr@777 382 assert(!use_cache(), "cache should be disabled");
johnc@1324 383 int start_idx;
johnc@1324 384
johnc@1324 385 while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once
johnc@1324 386 int end_idx = start_idx + _hot_cache_par_chunk_size;
johnc@1324 387
johnc@1324 388 if (start_idx ==
johnc@1324 389 Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) {
johnc@1324 390 // The current worker has successfully claimed the chunk [start_idx..end_idx)
johnc@1324 391 end_idx = MIN2(end_idx, _n_hot);
johnc@1324 392 for (int i = start_idx; i < end_idx; i++) {
johnc@1324 393 jbyte* entry = _hot_cache[i];
johnc@1324 394 if (entry != NULL) {
johnc@2060 395 if (g1rs->concurrentRefineOneCard(entry, worker_i, true)) {
johnc@2060 396 // 'entry' contains references that point into the current
johnc@2060 397 // collection set. We need to record 'entry' in the DCQS
johnc@2060 398 // that's used for that purpose.
johnc@2060 399 //
johnc@2060 400 // The only time we care about recording cards that contain
johnc@2060 401 // references that point into the collection set is during
johnc@2060 402 // RSet updating while within an evacuation pause.
johnc@2060 403 // In this case worker_i should be the id of a GC worker thread
johnc@2060 404 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
brutisso@2646 405 assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "incorrect worker id");
johnc@2060 406 into_cset_dcq->enqueue(entry);
johnc@2060 407 }
johnc@1324 408 }
johnc@1324 409 }
ysr@777 410 }
ysr@777 411 }
ysr@777 412 }
ysr@777 413
johnc@2713 414 // The arrays used to hold the card counts and the epochs must have
johnc@2713 415 // a 1:1 correspondence. Hence they are allocated and freed together
johnc@2713 416 // Returns true if the allocations of both the counts and epochs
johnc@2713 417 // were successful; false otherwise.
johnc@2713 418 bool ConcurrentG1Refine::allocate_card_count_cache(size_t n,
johnc@2713 419 CardCountCacheEntry** counts,
johnc@2713 420 CardEpochCacheEntry** epochs) {
johnc@2713 421 // We call the allocation/free routines directly for the counts
johnc@2713 422 // and epochs arrays. The NEW_C_HEAP_ARRAY/FREE_C_HEAP_ARRAY
johnc@2713 423 // macros call AllocateHeap and FreeHeap respectively.
johnc@2713 424 // AllocateHeap will call vm_exit_out_of_memory in the event
johnc@2713 425 // of an allocation failure and abort the JVM. With the
johnc@2713 426 // _counts/epochs arrays we only need to abort the JVM if the
johnc@2713 427 // initial allocation of these arrays fails.
johnc@2713 428 //
johnc@2713 429 // Additionally AllocateHeap/FreeHeap do some tracing of
johnc@2713 430 // allocate/free calls so calling one without calling the
johnc@2713 431 // other can cause inconsistencies in the tracing. So we
johnc@2713 432 // call neither.
johnc@2713 433
johnc@2713 434 assert(*counts == NULL, "out param");
johnc@2713 435 assert(*epochs == NULL, "out param");
johnc@2713 436
johnc@2713 437 size_t counts_size = n * sizeof(CardCountCacheEntry);
johnc@2713 438 size_t epochs_size = n * sizeof(CardEpochCacheEntry);
johnc@2713 439
zgu@3900 440 *counts = (CardCountCacheEntry*) os::malloc(counts_size, mtGC);
johnc@2713 441 if (*counts == NULL) {
johnc@2713 442 // allocation was unsuccessful
johnc@2713 443 return false;
johnc@2713 444 }
johnc@2713 445
zgu@3900 446 *epochs = (CardEpochCacheEntry*) os::malloc(epochs_size, mtGC);
johnc@2713 447 if (*epochs == NULL) {
johnc@2713 448 // allocation was unsuccessful - free counts array
johnc@2713 449 assert(*counts != NULL, "must be");
zgu@3900 450 os::free(*counts, mtGC);
johnc@2713 451 *counts = NULL;
johnc@2713 452 return false;
johnc@2713 453 }
johnc@2713 454
johnc@2713 455 // We successfully allocated both counts and epochs
johnc@2713 456 return true;
johnc@2713 457 }
johnc@2713 458
johnc@2713 459 // Returns true if the card counts/epochs cache was
johnc@2713 460 // successfully expanded; false otherwise.
johnc@2713 461 bool ConcurrentG1Refine::expand_card_count_cache(int cache_size_idx) {
johnc@2713 462 // Can we expand the card count and epoch tables?
johnc@1325 463 if (_n_card_counts < _max_n_card_counts) {
johnc@2713 464 assert(cache_size_idx >= 0 && cache_size_idx < MAX_CC_CACHE_INDEX, "oob");
johnc@1325 465
johnc@2713 466 size_t cache_size = _cc_cache_sizes[cache_size_idx];
johnc@1325 467 // Make sure we don't go bigger than we will ever need
johnc@2713 468 cache_size = MIN2(cache_size, _max_n_card_counts);
johnc@1325 469
johnc@2713 470 // Should we expand the card count and card epoch tables?
johnc@2713 471 if (cache_size > _n_card_counts) {
johnc@2713 472 // We have been asked to allocate new, larger, arrays for
johnc@2713 473 // the card counts and the epochs. Attempt the allocation
johnc@2713 474 // of both before we free the existing arrays in case
johnc@2713 475 // the allocation is unsuccessful...
johnc@2713 476 CardCountCacheEntry* counts = NULL;
johnc@2713 477 CardEpochCacheEntry* epochs = NULL;
johnc@2713 478
johnc@2713 479 if (allocate_card_count_cache(cache_size, &counts, &epochs)) {
johnc@2713 480 // Allocation was successful.
johnc@2713 481 // We can just free the old arrays; we're
johnc@2713 482 // not interested in preserving the contents
zgu@3900 483 if (_card_counts != NULL) os::free(_card_counts, mtGC);
zgu@3900 484 if (_card_epochs != NULL) os::free(_card_epochs, mtGC);
johnc@2713 485
johnc@2713 486 // Cache the size of the arrays and the index that got us there.
johnc@2713 487 _n_card_counts = cache_size;
johnc@2713 488 _cache_size_index = cache_size_idx;
johnc@2713 489
johnc@2713 490 _card_counts = counts;
johnc@2713 491 _card_epochs = epochs;
johnc@2713 492
johnc@2713 493 // We successfully allocated/expanded the caches.
johnc@2713 494 return true;
johnc@2713 495 }
ysr@777 496 }
ysr@777 497 }
johnc@2713 498
johnc@2713 499 // We did not successfully expand the caches.
johnc@2713 500 return false;
ysr@777 501 }
ysr@777 502
johnc@1325 503 void ConcurrentG1Refine::clear_and_record_card_counts() {
brutisso@3923 504 if (G1ConcRSLogCacheSize == 0) {
brutisso@3923 505 return;
brutisso@3923 506 }
johnc@1325 507
johnc@1325 508 double start = os::elapsedTime();
johnc@1325 509
johnc@1325 510 if (_expand_card_counts) {
johnc@2713 511 int new_idx = _cache_size_index + 1;
johnc@2713 512
johnc@2713 513 if (expand_card_count_cache(new_idx)) {
johnc@2713 514 // Allocation was successful and _n_card_counts has
johnc@2713 515 // been updated to the new size. We only need to clear
johnc@2713 516 // the epochs so we don't read a bogus epoch value
johnc@2713 517 // when inserting a card into the hot card cache.
johnc@2713 518 Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry));
johnc@2713 519 }
johnc@1325 520 _expand_card_counts = false;
ysr@777 521 }
ysr@777 522
johnc@1325 523 int this_epoch = (int) _n_periods;
johnc@1325 524 assert((this_epoch+1) <= max_jint, "to many periods");
johnc@1325 525 // Update epoch
johnc@1325 526 _n_periods++;
brutisso@3923 527 double cc_clear_time_ms = (os::elapsedTime() - start) * 1000;
brutisso@3923 528 _g1h->g1_policy()->phase_times()->record_cc_clear_time_ms(cc_clear_time_ms);
ysr@777 529 }
tonyp@1454 530
tonyp@1454 531 void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const {
tonyp@1454 532 for (int i = 0; i < _n_threads; ++i) {
tonyp@1454 533 _threads[i]->print_on(st);
tonyp@1454 534 st->cr();
tonyp@1454 535 }
tonyp@1454 536 }

mercurial