Thu, 21 Aug 2014 16:44:41 +0200
8055098: WB API should be extended to provide information about size and age of object.
Summary: Extend the WhiteBox API to provide information about the size and age of objects. Further add a mechanism to trigger a young GC.
Reviewed-by: tschatzl, sjohanss
Contributed-by: Leonid Mesnik <leonid.mesnik@oracle.com>
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 | }; |