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

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

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 6198
55fb97c4c58d
child 6876
710a3c8b516e
child 9327
f96fcd9e1e1b
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

ysr@777 1 /*
mikael@6198 2 * Copyright (c) 2001, 2013, 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/collectionSetChooser.hpp"
stefank@2314 27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 28 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
tonyp@3114 29 #include "gc_implementation/g1/g1ErgoVerbose.hpp"
stefank@2314 30 #include "memory/space.inline.hpp"
ysr@777 31
tonyp@3539 32 // Even though we don't use the GC efficiency in our heuristics as
tonyp@3539 33 // much as we used to, we still order according to GC efficiency. This
tonyp@3539 34 // will cause regions with a lot of live objects and large RSets to
tonyp@3539 35 // end up at the end of the array. Given that we might skip collecting
tonyp@3539 36 // the last few old regions, if after a few mixed GCs the remaining
tonyp@3539 37 // have reclaimable bytes under a certain threshold, the hope is that
tonyp@3539 38 // the ones we'll skip are ones with both large RSets and a lot of
tonyp@3539 39 // live objects, not the ones with just a lot of live objects if we
tonyp@3539 40 // ordered according to the amount of reclaimable bytes per region.
tonyp@3714 41 static int order_regions(HeapRegion* hr1, HeapRegion* hr2) {
ysr@777 42 if (hr1 == NULL) {
tonyp@3539 43 if (hr2 == NULL) {
tonyp@3539 44 return 0;
tonyp@3539 45 } else {
tonyp@3539 46 return 1;
tonyp@3539 47 }
ysr@777 48 } else if (hr2 == NULL) {
ysr@777 49 return -1;
ysr@777 50 }
tonyp@3539 51
tonyp@3539 52 double gc_eff1 = hr1->gc_efficiency();
tonyp@3539 53 double gc_eff2 = hr2->gc_efficiency();
tonyp@3539 54 if (gc_eff1 > gc_eff2) {
tonyp@3539 55 return -1;
tonyp@3539 56 } if (gc_eff1 < gc_eff2) {
tonyp@3539 57 return 1;
tonyp@3539 58 } else {
tonyp@3539 59 return 0;
tonyp@3539 60 }
ysr@777 61 }
ysr@777 62
tonyp@3714 63 static int order_regions(HeapRegion** hr1p, HeapRegion** hr2p) {
tonyp@3714 64 return order_regions(*hr1p, *hr2p);
ysr@777 65 }
ysr@777 66
ysr@777 67 CollectionSetChooser::CollectionSetChooser() :
ysr@777 68 // The line below is the worst bit of C++ hackery I've ever written
ysr@777 69 // (Detlefs, 11/23). You should think of it as equivalent to
ysr@777 70 // "_regions(100, true)": initialize the growable array and inform it
kvn@2043 71 // that it should allocate its elem array(s) on the C heap.
kvn@2043 72 //
kvn@2043 73 // The first argument, however, is actually a comma expression
kvn@2043 74 // (set_allocation_type(this, C_HEAP), 100). The purpose of the
kvn@2043 75 // set_allocation_type() call is to replace the default allocation
kvn@2043 76 // type for embedded objects STACK_OR_EMBEDDED with C_HEAP. It will
kvn@2043 77 // allow to pass the assert in GenericGrowableArray() which checks
kvn@2043 78 // that a growable array object must be on C heap if elements are.
kvn@2043 79 //
kvn@2043 80 // Note: containing object is allocated on C heap since it is CHeapObj.
kvn@2043 81 //
tonyp@3714 82 _regions((ResourceObj::set_allocation_type((address) &_regions,
ysr@777 83 ResourceObj::C_HEAP),
tonyp@3539 84 100), true /* C_Heap */),
tonyp@3714 85 _curr_index(0), _length(0), _first_par_unreserved_idx(0),
tonyp@3714 86 _region_live_threshold_bytes(0), _remaining_reclaimable_bytes(0) {
tonyp@3714 87 _region_live_threshold_bytes =
johnc@4385 88 HeapRegion::GrainBytes * (size_t) G1MixedGCLiveThresholdPercent / 100;
tonyp@3539 89 }
ysr@777 90
ysr@777 91 #ifndef PRODUCT
tonyp@3714 92 void CollectionSetChooser::verify() {
tonyp@3714 93 guarantee(_length <= regions_length(),
tonyp@3714 94 err_msg("_length: %u regions length: %u", _length, regions_length()));
tonyp@3714 95 guarantee(_curr_index <= _length,
tonyp@3714 96 err_msg("_curr_index: %u _length: %u", _curr_index, _length));
tonyp@3714 97 uint index = 0;
tonyp@3539 98 size_t sum_of_reclaimable_bytes = 0;
tonyp@3539 99 while (index < _curr_index) {
tonyp@3714 100 guarantee(regions_at(index) == NULL,
tonyp@3539 101 "all entries before _curr_index should be NULL");
tonyp@3539 102 index += 1;
ysr@777 103 }
ysr@777 104 HeapRegion *prev = NULL;
tonyp@3539 105 while (index < _length) {
tonyp@3714 106 HeapRegion *curr = regions_at(index++);
tonyp@3714 107 guarantee(curr != NULL, "Regions in _regions array cannot be NULL");
ysr@3185 108 guarantee(!curr->is_young(), "should not be young!");
tonyp@3539 109 guarantee(!curr->isHumongous(), "should not be humongous!");
ysr@3185 110 if (prev != NULL) {
tonyp@3714 111 guarantee(order_regions(prev, curr) != 1,
tonyp@3539 112 err_msg("GC eff prev: %1.4f GC eff curr: %1.4f",
tonyp@3539 113 prev->gc_efficiency(), curr->gc_efficiency()));
ysr@777 114 }
tonyp@3539 115 sum_of_reclaimable_bytes += curr->reclaimable_bytes();
ysr@3185 116 prev = curr;
ysr@777 117 }
tonyp@3714 118 guarantee(sum_of_reclaimable_bytes == _remaining_reclaimable_bytes,
tonyp@3539 119 err_msg("reclaimable bytes inconsistent, "
tonyp@3539 120 "remaining: "SIZE_FORMAT" sum: "SIZE_FORMAT,
tonyp@3714 121 _remaining_reclaimable_bytes, sum_of_reclaimable_bytes));
ysr@777 122 }
tonyp@3714 123 #endif // !PRODUCT
ysr@777 124
tonyp@3714 125 void CollectionSetChooser::sort_regions() {
ysr@777 126 // First trim any unused portion of the top in the parallel case.
ysr@777 127 if (_first_par_unreserved_idx > 0) {
tonyp@3714 128 assert(_first_par_unreserved_idx <= regions_length(),
ysr@777 129 "Or we didn't reserved enough length");
tonyp@3714 130 regions_trunc_to(_first_par_unreserved_idx);
ysr@777 131 }
tonyp@3714 132 _regions.sort(order_regions);
tonyp@3714 133 assert(_length <= regions_length(), "Requirement");
tonyp@3714 134 #ifdef ASSERT
tonyp@3714 135 for (uint i = 0; i < _length; i++) {
tonyp@3714 136 assert(regions_at(i) != NULL, "Should be true by sorting!");
ysr@777 137 }
tonyp@3714 138 #endif // ASSERT
tonyp@2717 139 if (G1PrintRegionLivenessInfo) {
tonyp@2717 140 G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Sorting");
tonyp@3714 141 for (uint i = 0; i < _length; ++i) {
tonyp@3714 142 HeapRegion* r = regions_at(i);
tonyp@2717 143 cl.doHeapRegion(r);
ysr@777 144 }
ysr@777 145 }
tonyp@3714 146 verify();
ysr@777 147 }
ysr@777 148
tonyp@3539 149
tonyp@3714 150 void CollectionSetChooser::add_region(HeapRegion* hr) {
ysr@777 151 assert(!hr->isHumongous(),
ysr@777 152 "Humongous regions shouldn't be added to the collection set");
ysr@777 153 assert(!hr->is_young(), "should not be young!");
tonyp@3714 154 _regions.append(hr);
tonyp@3539 155 _length++;
tonyp@3714 156 _remaining_reclaimable_bytes += hr->reclaimable_bytes();
ysr@777 157 hr->calc_gc_efficiency();
ysr@777 158 }
ysr@777 159
tonyp@3714 160 void CollectionSetChooser::prepare_for_par_region_addition(uint n_regions,
tonyp@3714 161 uint chunk_size) {
ysr@777 162 _first_par_unreserved_idx = 0;
tonyp@3713 163 uint n_threads = (uint) ParallelGCThreads;
jmasa@3294 164 if (UseDynamicNumberOfGCThreads) {
jmasa@3294 165 assert(G1CollectedHeap::heap()->workers()->active_workers() > 0,
jmasa@3294 166 "Should have been set earlier");
jmasa@3294 167 // This is defensive code. As the assertion above says, the number
jmasa@3294 168 // of active threads should be > 0, but in case there is some path
jmasa@3294 169 // or some improperly initialized variable with leads to no
jmasa@3294 170 // active threads, protect against that in a product build.
jmasa@3294 171 n_threads = MAX2(G1CollectedHeap::heap()->workers()->active_workers(),
jmasa@3357 172 1U);
jmasa@3294 173 }
tonyp@3714 174 uint max_waste = n_threads * chunk_size;
tonyp@3714 175 // it should be aligned with respect to chunk_size
tonyp@3714 176 uint aligned_n_regions = (n_regions + chunk_size - 1) / chunk_size * chunk_size;
tonyp@3714 177 assert(aligned_n_regions % chunk_size == 0, "should be aligned");
tonyp@3714 178 regions_at_put_grow(aligned_n_regions + max_waste - 1, NULL);
ysr@777 179 }
ysr@777 180
tonyp@3714 181 uint CollectionSetChooser::claim_array_chunk(uint chunk_size) {
tonyp@3714 182 uint res = (uint) Atomic::add((jint) chunk_size,
tonyp@3714 183 (volatile jint*) &_first_par_unreserved_idx);
tonyp@3714 184 assert(regions_length() > res + chunk_size - 1,
ysr@777 185 "Should already have been expanded");
tonyp@3714 186 return res - chunk_size;
ysr@777 187 }
ysr@777 188
tonyp@3714 189 void CollectionSetChooser::set_region(uint index, HeapRegion* hr) {
tonyp@3714 190 assert(regions_at(index) == NULL, "precondition");
ysr@777 191 assert(!hr->is_young(), "should not be young!");
tonyp@3714 192 regions_at_put(index, hr);
ysr@777 193 hr->calc_gc_efficiency();
ysr@777 194 }
ysr@777 195
tonyp@3714 196 void CollectionSetChooser::update_totals(uint region_num,
tonyp@3714 197 size_t reclaimable_bytes) {
tonyp@3539 198 // Only take the lock if we actually need to update the totals.
tonyp@3539 199 if (region_num > 0) {
tonyp@3539 200 assert(reclaimable_bytes > 0, "invariant");
tonyp@3539 201 // We could have just used atomics instead of taking the
tonyp@3539 202 // lock. However, we currently don't have an atomic add for size_t.
tonyp@3539 203 MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
tonyp@3714 204 _length += region_num;
tonyp@3714 205 _remaining_reclaimable_bytes += reclaimable_bytes;
tonyp@3539 206 } else {
tonyp@3539 207 assert(reclaimable_bytes == 0, "invariant");
tonyp@3539 208 }
ysr@777 209 }
ysr@777 210
tonyp@3714 211 void CollectionSetChooser::clear() {
tonyp@3714 212 _regions.clear();
tonyp@3539 213 _curr_index = 0;
tonyp@3539 214 _length = 0;
tonyp@3714 215 _remaining_reclaimable_bytes = 0;
ysr@777 216 };

mercurial