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

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7118
227a9e5e4b4a
child 7645
f2e3f0e1f97d
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

tschatzl@6937 1 /*
tschatzl@6937 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
tschatzl@6937 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
tschatzl@6937 4 *
tschatzl@6937 5 * This code is free software; you can redistribute it and/or modify it
tschatzl@6937 6 * under the terms of the GNU General Public License version 2 only, as
tschatzl@6937 7 * published by the Free Software Foundation.
tschatzl@6937 8 *
tschatzl@6937 9 * This code is distributed in the hope that it will be useful, but WITHOUT
tschatzl@6937 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
tschatzl@6937 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
tschatzl@6937 12 * version 2 for more details (a copy is included in the LICENSE file that
tschatzl@6937 13 * accompanied this code).
tschatzl@6937 14 *
tschatzl@6937 15 * You should have received a copy of the GNU General Public License version
tschatzl@6937 16 * 2 along with this work; if not, write to the Free Software Foundation,
tschatzl@6937 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
tschatzl@6937 18 *
tschatzl@6937 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
tschatzl@6937 20 * or visit www.oracle.com if you need additional information or have any
tschatzl@6937 21 * questions.
tschatzl@6937 22 *
tschatzl@6937 23 */
tschatzl@6937 24
tschatzl@6937 25 #include "precompiled.hpp"
tschatzl@6937 26 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
tschatzl@6937 27 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
tschatzl@6937 28 #include "gc_implementation/g1/g1ParScanThreadState.inline.hpp"
tschatzl@6937 29 #include "oops/oop.inline.hpp"
tschatzl@6937 30 #include "oops/oop.pcgc.inline.hpp"
tschatzl@6937 31 #include "runtime/prefetch.inline.hpp"
tschatzl@6937 32
tschatzl@6937 33 G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp)
tschatzl@6937 34 : _g1h(g1h),
tschatzl@6937 35 _refs(g1h->task_queue(queue_num)),
tschatzl@6937 36 _dcq(&g1h->dirty_card_queue_set()),
tschatzl@6937 37 _ct_bs(g1h->g1_barrier_set()),
tschatzl@6937 38 _g1_rem(g1h->g1_rem_set()),
tschatzl@6937 39 _hash_seed(17), _queue_num(queue_num),
tschatzl@6937 40 _term_attempts(0),
tschatzl@6939 41 _age_table(false), _scanner(g1h, rp),
sjohanss@7118 42 _strong_roots_time(0), _term_time(0) {
tschatzl@6939 43 _scanner.set_par_scan_thread_state(this);
tschatzl@6937 44 // we allocate G1YoungSurvRateNumRegions plus one entries, since
tschatzl@6937 45 // we "sacrifice" entry 0 to keep track of surviving bytes for
tschatzl@6937 46 // non-young regions (where the age is -1)
tschatzl@6937 47 // We also add a few elements at the beginning and at the end in
tschatzl@6937 48 // an attempt to eliminate cache contention
tschatzl@6937 49 uint real_length = 1 + _g1h->g1_policy()->young_cset_region_length();
tschatzl@6937 50 uint array_length = PADDING_ELEM_NUM +
tschatzl@6937 51 real_length +
tschatzl@6937 52 PADDING_ELEM_NUM;
tschatzl@6937 53 _surviving_young_words_base = NEW_C_HEAP_ARRAY(size_t, array_length, mtGC);
tschatzl@6937 54 if (_surviving_young_words_base == NULL)
tschatzl@6937 55 vm_exit_out_of_memory(array_length * sizeof(size_t), OOM_MALLOC_ERROR,
tschatzl@6937 56 "Not enough space for young surv histo.");
tschatzl@6937 57 _surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM;
tschatzl@6937 58 memset(_surviving_young_words, 0, (size_t) real_length * sizeof(size_t));
tschatzl@6937 59
sjohanss@7118 60 _g1_par_allocator = G1ParGCAllocator::create_allocator(_g1h);
tschatzl@6937 61
tschatzl@6937 62 _start = os::elapsedTime();
tschatzl@6937 63 }
tschatzl@6937 64
tschatzl@6938 65 G1ParScanThreadState::~G1ParScanThreadState() {
sjohanss@7118 66 _g1_par_allocator->retire_alloc_buffers();
sjohanss@7118 67 delete _g1_par_allocator;
tschatzl@6938 68 FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base, mtGC);
tschatzl@6938 69 }
tschatzl@6938 70
tschatzl@6937 71 void
tschatzl@6937 72 G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st)
tschatzl@6937 73 {
tschatzl@6937 74 st->print_raw_cr("GC Termination Stats");
tschatzl@6937 75 st->print_raw_cr(" elapsed --strong roots-- -------termination-------"
tschatzl@6937 76 " ------waste (KiB)------");
tschatzl@6937 77 st->print_raw_cr("thr ms ms % ms % attempts"
tschatzl@6937 78 " total alloc undo");
tschatzl@6937 79 st->print_raw_cr("--- --------- --------- ------ --------- ------ --------"
tschatzl@6937 80 " ------- ------- -------");
tschatzl@6937 81 }
tschatzl@6937 82
tschatzl@6937 83 void
tschatzl@6937 84 G1ParScanThreadState::print_termination_stats(int i,
tschatzl@6937 85 outputStream* const st) const
tschatzl@6937 86 {
tschatzl@6937 87 const double elapsed_ms = elapsed_time() * 1000.0;
tschatzl@6937 88 const double s_roots_ms = strong_roots_time() * 1000.0;
tschatzl@6937 89 const double term_ms = term_time() * 1000.0;
sjohanss@7118 90 const size_t alloc_buffer_waste = _g1_par_allocator->alloc_buffer_waste();
sjohanss@7118 91 const size_t undo_waste = _g1_par_allocator->undo_waste();
tschatzl@6937 92 st->print_cr("%3d %9.2f %9.2f %6.2f "
tschatzl@6937 93 "%9.2f %6.2f " SIZE_FORMAT_W(8) " "
tschatzl@6937 94 SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7),
tschatzl@6937 95 i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms,
tschatzl@6937 96 term_ms, term_ms * 100 / elapsed_ms, term_attempts(),
sjohanss@7118 97 (alloc_buffer_waste + undo_waste) * HeapWordSize / K,
sjohanss@7118 98 alloc_buffer_waste * HeapWordSize / K,
sjohanss@7118 99 undo_waste * HeapWordSize / K);
tschatzl@6937 100 }
tschatzl@6937 101
tschatzl@6937 102 #ifdef ASSERT
tschatzl@6937 103 bool G1ParScanThreadState::verify_ref(narrowOop* ref) const {
tschatzl@6937 104 assert(ref != NULL, "invariant");
tschatzl@6937 105 assert(UseCompressedOops, "sanity");
tschatzl@6937 106 assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, p2i(ref)));
tschatzl@6937 107 oop p = oopDesc::load_decode_heap_oop(ref);
tschatzl@6937 108 assert(_g1h->is_in_g1_reserved(p),
tschatzl@6937 109 err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)));
tschatzl@6937 110 return true;
tschatzl@6937 111 }
tschatzl@6937 112
tschatzl@6937 113 bool G1ParScanThreadState::verify_ref(oop* ref) const {
tschatzl@6937 114 assert(ref != NULL, "invariant");
tschatzl@6937 115 if (has_partial_array_mask(ref)) {
tschatzl@6937 116 // Must be in the collection set--it's already been copied.
tschatzl@6937 117 oop p = clear_partial_array_mask(ref);
tschatzl@6937 118 assert(_g1h->obj_in_cs(p),
tschatzl@6937 119 err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)));
tschatzl@6937 120 } else {
tschatzl@6937 121 oop p = oopDesc::load_decode_heap_oop(ref);
tschatzl@6937 122 assert(_g1h->is_in_g1_reserved(p),
tschatzl@6937 123 err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)));
tschatzl@6937 124 }
tschatzl@6937 125 return true;
tschatzl@6937 126 }
tschatzl@6937 127
tschatzl@6937 128 bool G1ParScanThreadState::verify_task(StarTask ref) const {
tschatzl@6937 129 if (ref.is_narrow()) {
tschatzl@6937 130 return verify_ref((narrowOop*) ref);
tschatzl@6937 131 } else {
tschatzl@6937 132 return verify_ref((oop*) ref);
tschatzl@6937 133 }
tschatzl@6937 134 }
tschatzl@6937 135 #endif // ASSERT
tschatzl@6937 136
tschatzl@6937 137 void G1ParScanThreadState::trim_queue() {
tschatzl@6937 138 assert(_evac_failure_cl != NULL, "not set");
tschatzl@6937 139
tschatzl@6937 140 StarTask ref;
tschatzl@6937 141 do {
tschatzl@6937 142 // Drain the overflow stack first, so other threads can steal.
tschatzl@6938 143 while (_refs->pop_overflow(ref)) {
tschatzl@6938 144 dispatch_reference(ref);
tschatzl@6937 145 }
tschatzl@6937 146
tschatzl@6938 147 while (_refs->pop_local(ref)) {
tschatzl@6938 148 dispatch_reference(ref);
tschatzl@6937 149 }
tschatzl@6938 150 } while (!_refs->is_empty());
tschatzl@6937 151 }
tschatzl@6937 152
tschatzl@6937 153 oop G1ParScanThreadState::copy_to_survivor_space(oop const old) {
tschatzl@6937 154 size_t word_sz = old->size();
tschatzl@6937 155 HeapRegion* from_region = _g1h->heap_region_containing_raw(old);
tschatzl@6937 156 // +1 to make the -1 indexes valid...
tschatzl@6937 157 int young_index = from_region->young_index_in_cset()+1;
tschatzl@6937 158 assert( (from_region->is_young() && young_index > 0) ||
tschatzl@6937 159 (!from_region->is_young() && young_index == 0), "invariant" );
tschatzl@6937 160 G1CollectorPolicy* g1p = _g1h->g1_policy();
tschatzl@6937 161 markOop m = old->mark();
tschatzl@6937 162 int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age()
tschatzl@6937 163 : m->age();
tschatzl@6937 164 GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age,
tschatzl@6937 165 word_sz);
sjohanss@7118 166 AllocationContext_t context = from_region->allocation_context();
sjohanss@7118 167 HeapWord* obj_ptr = _g1_par_allocator->allocate(alloc_purpose, word_sz, context);
tschatzl@6937 168 #ifndef PRODUCT
tschatzl@6937 169 // Should this evacuation fail?
tschatzl@6937 170 if (_g1h->evacuation_should_fail()) {
tschatzl@6937 171 if (obj_ptr != NULL) {
sjohanss@7118 172 _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context);
tschatzl@6937 173 obj_ptr = NULL;
tschatzl@6937 174 }
tschatzl@6937 175 }
tschatzl@6937 176 #endif // !PRODUCT
tschatzl@6937 177
tschatzl@6937 178 if (obj_ptr == NULL) {
tschatzl@6937 179 // This will either forward-to-self, or detect that someone else has
tschatzl@6937 180 // installed a forwarding pointer.
tschatzl@6937 181 return _g1h->handle_evacuation_failure_par(this, old);
tschatzl@6937 182 }
tschatzl@6937 183
tschatzl@6937 184 oop obj = oop(obj_ptr);
tschatzl@6937 185
tschatzl@6937 186 // We're going to allocate linearly, so might as well prefetch ahead.
tschatzl@6937 187 Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes);
tschatzl@6937 188
tschatzl@6937 189 oop forward_ptr = old->forward_to_atomic(obj);
tschatzl@6937 190 if (forward_ptr == NULL) {
tschatzl@6937 191 Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz);
tschatzl@6937 192
tschatzl@6937 193 // alloc_purpose is just a hint to allocate() above, recheck the type of region
tschatzl@6937 194 // we actually allocated from and update alloc_purpose accordingly
tschatzl@6937 195 HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr);
tschatzl@6937 196 alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured;
tschatzl@6937 197
tschatzl@6937 198 if (g1p->track_object_age(alloc_purpose)) {
tschatzl@6937 199 // We could simply do obj->incr_age(). However, this causes a
tschatzl@6937 200 // performance issue. obj->incr_age() will first check whether
tschatzl@6937 201 // the object has a displaced mark by checking its mark word;
tschatzl@6937 202 // getting the mark word from the new location of the object
tschatzl@6937 203 // stalls. So, given that we already have the mark word and we
tschatzl@6937 204 // are about to install it anyway, it's better to increase the
tschatzl@6937 205 // age on the mark word, when the object does not have a
tschatzl@6937 206 // displaced mark word. We're not expecting many objects to have
tschatzl@6937 207 // a displaced marked word, so that case is not optimized
tschatzl@6937 208 // further (it could be...) and we simply call obj->incr_age().
tschatzl@6937 209
tschatzl@6937 210 if (m->has_displaced_mark_helper()) {
tschatzl@6937 211 // in this case, we have to install the mark word first,
tschatzl@6937 212 // otherwise obj looks to be forwarded (the old mark word,
tschatzl@6937 213 // which contains the forward pointer, was copied)
tschatzl@6937 214 obj->set_mark(m);
tschatzl@6937 215 obj->incr_age();
tschatzl@6937 216 } else {
tschatzl@6937 217 m = m->incr_age();
tschatzl@6937 218 obj->set_mark(m);
tschatzl@6937 219 }
tschatzl@6937 220 age_table()->add(obj, word_sz);
tschatzl@6937 221 } else {
tschatzl@6937 222 obj->set_mark(m);
tschatzl@6937 223 }
tschatzl@6937 224
tschatzl@6937 225 if (G1StringDedup::is_enabled()) {
tschatzl@6937 226 G1StringDedup::enqueue_from_evacuation(from_region->is_young(),
tschatzl@6937 227 to_region->is_young(),
tschatzl@6937 228 queue_num(),
tschatzl@6937 229 obj);
tschatzl@6937 230 }
tschatzl@6937 231
tschatzl@6937 232 size_t* surv_young_words = surviving_young_words();
tschatzl@6937 233 surv_young_words[young_index] += word_sz;
tschatzl@6937 234
tschatzl@6937 235 if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) {
tschatzl@6937 236 // We keep track of the next start index in the length field of
tschatzl@6937 237 // the to-space object. The actual length can be found in the
tschatzl@6937 238 // length field of the from-space object.
tschatzl@6937 239 arrayOop(obj)->set_length(0);
tschatzl@6937 240 oop* old_p = set_partial_array_mask(old);
tschatzl@6937 241 push_on_queue(old_p);
tschatzl@6937 242 } else {
tschatzl@6937 243 // No point in using the slower heap_region_containing() method,
tschatzl@6937 244 // given that we know obj is in the heap.
tschatzl@6937 245 _scanner.set_region(_g1h->heap_region_containing_raw(obj));
tschatzl@6937 246 obj->oop_iterate_backwards(&_scanner);
tschatzl@6937 247 }
tschatzl@6937 248 } else {
sjohanss@7118 249 _g1_par_allocator->undo_allocation(alloc_purpose, obj_ptr, word_sz, context);
tschatzl@6937 250 obj = forward_ptr;
tschatzl@6937 251 }
tschatzl@6937 252 return obj;
tschatzl@6937 253 }

mercurial