1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/g1/g1ParScanThreadState.cpp Mon Jul 21 09:41:04 2014 +0200 1.3 @@ -0,0 +1,251 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 1.30 +#include "gc_implementation/g1/g1OopClosures.inline.hpp" 1.31 +#include "gc_implementation/g1/g1ParScanThreadState.inline.hpp" 1.32 +#include "oops/oop.inline.hpp" 1.33 +#include "oops/oop.pcgc.inline.hpp" 1.34 +#include "runtime/prefetch.inline.hpp" 1.35 + 1.36 +#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away 1.37 +#pragma warning( disable:4355 ) // 'this' : used in base member initializer list 1.38 +#endif // _MSC_VER 1.39 + 1.40 +G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp) 1.41 + : _g1h(g1h), 1.42 + _refs(g1h->task_queue(queue_num)), 1.43 + _dcq(&g1h->dirty_card_queue_set()), 1.44 + _ct_bs(g1h->g1_barrier_set()), 1.45 + _g1_rem(g1h->g1_rem_set()), 1.46 + _hash_seed(17), _queue_num(queue_num), 1.47 + _term_attempts(0), 1.48 + _surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)), 1.49 + _tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)), 1.50 + _age_table(false), _scanner(g1h, this, rp), 1.51 + _strong_roots_time(0), _term_time(0), 1.52 + _alloc_buffer_waste(0), _undo_waste(0) { 1.53 + // we allocate G1YoungSurvRateNumRegions plus one entries, since 1.54 + // we "sacrifice" entry 0 to keep track of surviving bytes for 1.55 + // non-young regions (where the age is -1) 1.56 + // We also add a few elements at the beginning and at the end in 1.57 + // an attempt to eliminate cache contention 1.58 + uint real_length = 1 + _g1h->g1_policy()->young_cset_region_length(); 1.59 + uint array_length = PADDING_ELEM_NUM + 1.60 + real_length + 1.61 + PADDING_ELEM_NUM; 1.62 + _surviving_young_words_base = NEW_C_HEAP_ARRAY(size_t, array_length, mtGC); 1.63 + if (_surviving_young_words_base == NULL) 1.64 + vm_exit_out_of_memory(array_length * sizeof(size_t), OOM_MALLOC_ERROR, 1.65 + "Not enough space for young surv histo."); 1.66 + _surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM; 1.67 + memset(_surviving_young_words, 0, (size_t) real_length * sizeof(size_t)); 1.68 + 1.69 + _alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer; 1.70 + _alloc_buffers[GCAllocForTenured] = &_tenured_alloc_buffer; 1.71 + 1.72 + _start = os::elapsedTime(); 1.73 +} 1.74 + 1.75 +void 1.76 +G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st) 1.77 +{ 1.78 + st->print_raw_cr("GC Termination Stats"); 1.79 + st->print_raw_cr(" elapsed --strong roots-- -------termination-------" 1.80 + " ------waste (KiB)------"); 1.81 + st->print_raw_cr("thr ms ms % ms % attempts" 1.82 + " total alloc undo"); 1.83 + st->print_raw_cr("--- --------- --------- ------ --------- ------ --------" 1.84 + " ------- ------- -------"); 1.85 +} 1.86 + 1.87 +void 1.88 +G1ParScanThreadState::print_termination_stats(int i, 1.89 + outputStream* const st) const 1.90 +{ 1.91 + const double elapsed_ms = elapsed_time() * 1000.0; 1.92 + const double s_roots_ms = strong_roots_time() * 1000.0; 1.93 + const double term_ms = term_time() * 1000.0; 1.94 + st->print_cr("%3d %9.2f %9.2f %6.2f " 1.95 + "%9.2f %6.2f " SIZE_FORMAT_W(8) " " 1.96 + SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7), 1.97 + i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms, 1.98 + term_ms, term_ms * 100 / elapsed_ms, term_attempts(), 1.99 + (alloc_buffer_waste() + undo_waste()) * HeapWordSize / K, 1.100 + alloc_buffer_waste() * HeapWordSize / K, 1.101 + undo_waste() * HeapWordSize / K); 1.102 +} 1.103 + 1.104 +#ifdef ASSERT 1.105 +bool G1ParScanThreadState::verify_ref(narrowOop* ref) const { 1.106 + assert(ref != NULL, "invariant"); 1.107 + assert(UseCompressedOops, "sanity"); 1.108 + assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, p2i(ref))); 1.109 + oop p = oopDesc::load_decode_heap_oop(ref); 1.110 + assert(_g1h->is_in_g1_reserved(p), 1.111 + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); 1.112 + return true; 1.113 +} 1.114 + 1.115 +bool G1ParScanThreadState::verify_ref(oop* ref) const { 1.116 + assert(ref != NULL, "invariant"); 1.117 + if (has_partial_array_mask(ref)) { 1.118 + // Must be in the collection set--it's already been copied. 1.119 + oop p = clear_partial_array_mask(ref); 1.120 + assert(_g1h->obj_in_cs(p), 1.121 + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); 1.122 + } else { 1.123 + oop p = oopDesc::load_decode_heap_oop(ref); 1.124 + assert(_g1h->is_in_g1_reserved(p), 1.125 + err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); 1.126 + } 1.127 + return true; 1.128 +} 1.129 + 1.130 +bool G1ParScanThreadState::verify_task(StarTask ref) const { 1.131 + if (ref.is_narrow()) { 1.132 + return verify_ref((narrowOop*) ref); 1.133 + } else { 1.134 + return verify_ref((oop*) ref); 1.135 + } 1.136 +} 1.137 +#endif // ASSERT 1.138 + 1.139 +void G1ParScanThreadState::trim_queue() { 1.140 + assert(_evac_failure_cl != NULL, "not set"); 1.141 + 1.142 + StarTask ref; 1.143 + do { 1.144 + // Drain the overflow stack first, so other threads can steal. 1.145 + while (refs()->pop_overflow(ref)) { 1.146 + deal_with_reference(ref); 1.147 + } 1.148 + 1.149 + while (refs()->pop_local(ref)) { 1.150 + deal_with_reference(ref); 1.151 + } 1.152 + } while (!refs()->is_empty()); 1.153 +} 1.154 + 1.155 +oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { 1.156 + size_t word_sz = old->size(); 1.157 + HeapRegion* from_region = _g1h->heap_region_containing_raw(old); 1.158 + // +1 to make the -1 indexes valid... 1.159 + int young_index = from_region->young_index_in_cset()+1; 1.160 + assert( (from_region->is_young() && young_index > 0) || 1.161 + (!from_region->is_young() && young_index == 0), "invariant" ); 1.162 + G1CollectorPolicy* g1p = _g1h->g1_policy(); 1.163 + markOop m = old->mark(); 1.164 + int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age() 1.165 + : m->age(); 1.166 + GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age, 1.167 + word_sz); 1.168 + HeapWord* obj_ptr = allocate(alloc_purpose, word_sz); 1.169 +#ifndef PRODUCT 1.170 + // Should this evacuation fail? 1.171 + if (_g1h->evacuation_should_fail()) { 1.172 + if (obj_ptr != NULL) { 1.173 + undo_allocation(alloc_purpose, obj_ptr, word_sz); 1.174 + obj_ptr = NULL; 1.175 + } 1.176 + } 1.177 +#endif // !PRODUCT 1.178 + 1.179 + if (obj_ptr == NULL) { 1.180 + // This will either forward-to-self, or detect that someone else has 1.181 + // installed a forwarding pointer. 1.182 + return _g1h->handle_evacuation_failure_par(this, old); 1.183 + } 1.184 + 1.185 + oop obj = oop(obj_ptr); 1.186 + 1.187 + // We're going to allocate linearly, so might as well prefetch ahead. 1.188 + Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes); 1.189 + 1.190 + oop forward_ptr = old->forward_to_atomic(obj); 1.191 + if (forward_ptr == NULL) { 1.192 + Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz); 1.193 + 1.194 + // alloc_purpose is just a hint to allocate() above, recheck the type of region 1.195 + // we actually allocated from and update alloc_purpose accordingly 1.196 + HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr); 1.197 + alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured; 1.198 + 1.199 + if (g1p->track_object_age(alloc_purpose)) { 1.200 + // We could simply do obj->incr_age(). However, this causes a 1.201 + // performance issue. obj->incr_age() will first check whether 1.202 + // the object has a displaced mark by checking its mark word; 1.203 + // getting the mark word from the new location of the object 1.204 + // stalls. So, given that we already have the mark word and we 1.205 + // are about to install it anyway, it's better to increase the 1.206 + // age on the mark word, when the object does not have a 1.207 + // displaced mark word. We're not expecting many objects to have 1.208 + // a displaced marked word, so that case is not optimized 1.209 + // further (it could be...) and we simply call obj->incr_age(). 1.210 + 1.211 + if (m->has_displaced_mark_helper()) { 1.212 + // in this case, we have to install the mark word first, 1.213 + // otherwise obj looks to be forwarded (the old mark word, 1.214 + // which contains the forward pointer, was copied) 1.215 + obj->set_mark(m); 1.216 + obj->incr_age(); 1.217 + } else { 1.218 + m = m->incr_age(); 1.219 + obj->set_mark(m); 1.220 + } 1.221 + age_table()->add(obj, word_sz); 1.222 + } else { 1.223 + obj->set_mark(m); 1.224 + } 1.225 + 1.226 + if (G1StringDedup::is_enabled()) { 1.227 + G1StringDedup::enqueue_from_evacuation(from_region->is_young(), 1.228 + to_region->is_young(), 1.229 + queue_num(), 1.230 + obj); 1.231 + } 1.232 + 1.233 + size_t* surv_young_words = surviving_young_words(); 1.234 + surv_young_words[young_index] += word_sz; 1.235 + 1.236 + if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) { 1.237 + // We keep track of the next start index in the length field of 1.238 + // the to-space object. The actual length can be found in the 1.239 + // length field of the from-space object. 1.240 + arrayOop(obj)->set_length(0); 1.241 + oop* old_p = set_partial_array_mask(old); 1.242 + push_on_queue(old_p); 1.243 + } else { 1.244 + // No point in using the slower heap_region_containing() method, 1.245 + // given that we know obj is in the heap. 1.246 + _scanner.set_region(_g1h->heap_region_containing_raw(obj)); 1.247 + obj->oop_iterate_backwards(&_scanner); 1.248 + } 1.249 + } else { 1.250 + undo_allocation(alloc_purpose, obj_ptr, word_sz); 1.251 + obj = forward_ptr; 1.252 + } 1.253 + return obj; 1.254 +}