src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp

Thu, 20 Sep 2012 09:52:56 -0700

author
johnc
date
Thu, 20 Sep 2012 09:52:56 -0700
changeset 4067
b2ef234911c9
parent 3982
aaf61e68b255
child 4130
2e6857353b2c
permissions
-rw-r--r--

7190666: G1: assert(_unused == 0) failed: Inconsistency in PLAB stats
Summary: Reset the fields in ParGCAllocBuffer, that are used for accumulating values for the ResizePLAB sensors in PLABStats, to zero after flushing the values to the PLABStats fields. Flush PLABStats values only when retiring the final allocation buffers prior to disposing of a G1ParScanThreadState object, rather than when retiring every allocation buffer.
Reviewed-by: jwilhelm, jmasa, ysr

duke@435 1 /*
johnc@3982 2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 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.
duke@435 22 *
duke@435 23 */
duke@435 24
stefank@2314 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP
stefank@2314 26 #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP
stefank@2314 27
stefank@2314 28 #include "memory/allocation.hpp"
stefank@2325 29 #include "memory/blockOffsetTable.hpp"
stefank@2314 30 #include "memory/threadLocalAllocBuffer.hpp"
stefank@2314 31 #include "utilities/globalDefinitions.hpp"
stefank@2314 32
duke@435 33 // Forward decl.
duke@435 34
duke@435 35 class PLABStats;
duke@435 36
duke@435 37 // A per-thread allocation buffer used during GC.
zgu@3900 38 class ParGCAllocBuffer: public CHeapObj<mtGC> {
duke@435 39 protected:
duke@435 40 char head[32];
duke@435 41 size_t _word_sz; // in HeapWord units
duke@435 42 HeapWord* _bottom;
duke@435 43 HeapWord* _top;
duke@435 44 HeapWord* _end; // last allocatable address + 1
duke@435 45 HeapWord* _hard_end; // _end + AlignmentReserve
duke@435 46 bool _retained; // whether we hold a _retained_filler
duke@435 47 MemRegion _retained_filler;
duke@435 48 // In support of ergonomic sizing of PLAB's
duke@435 49 size_t _allocated; // in HeapWord units
duke@435 50 size_t _wasted; // in HeapWord units
duke@435 51 char tail[32];
coleenp@548 52 static size_t FillerHeaderSize;
coleenp@548 53 static size_t AlignmentReserve;
duke@435 54
johnc@4067 55 // Flush the stats supporting ergonomic sizing of PLAB's
johnc@4067 56 // Should not be called directly
johnc@4067 57 void flush_stats(PLABStats* stats);
johnc@4067 58
duke@435 59 public:
duke@435 60 // Initializes the buffer to be empty, but with the given "word_sz".
duke@435 61 // Must get initialized with "set_buf" for an allocation to succeed.
duke@435 62 ParGCAllocBuffer(size_t word_sz);
duke@435 63
duke@435 64 static const size_t min_size() {
duke@435 65 return ThreadLocalAllocBuffer::min_size();
duke@435 66 }
duke@435 67
duke@435 68 static const size_t max_size() {
duke@435 69 return ThreadLocalAllocBuffer::max_size();
duke@435 70 }
duke@435 71
duke@435 72 // If an allocation of the given "word_sz" can be satisfied within the
duke@435 73 // buffer, do the allocation, returning a pointer to the start of the
duke@435 74 // allocated block. If the allocation request cannot be satisfied,
duke@435 75 // return NULL.
duke@435 76 HeapWord* allocate(size_t word_sz) {
duke@435 77 HeapWord* res = _top;
ysr@1069 78 if (pointer_delta(_end, _top) >= word_sz) {
ysr@1069 79 _top = _top + word_sz;
duke@435 80 return res;
duke@435 81 } else {
duke@435 82 return NULL;
duke@435 83 }
duke@435 84 }
duke@435 85
duke@435 86 // Undo the last allocation in the buffer, which is required to be of the
duke@435 87 // "obj" of the given "word_sz".
duke@435 88 void undo_allocation(HeapWord* obj, size_t word_sz) {
ysr@1069 89 assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo");
ysr@1069 90 assert(pointer_delta(_top, obj) == word_sz, "Bad undo");
ysr@1069 91 _top = obj;
duke@435 92 }
duke@435 93
duke@435 94 // The total (word) size of the buffer, including both allocated and
duke@435 95 // unallocted space.
duke@435 96 size_t word_sz() { return _word_sz; }
duke@435 97
duke@435 98 // Should only be done if we are about to reset with a new buffer of the
duke@435 99 // given size.
duke@435 100 void set_word_size(size_t new_word_sz) {
duke@435 101 assert(new_word_sz > AlignmentReserve, "Too small");
duke@435 102 _word_sz = new_word_sz;
duke@435 103 }
duke@435 104
duke@435 105 // The number of words of unallocated space remaining in the buffer.
duke@435 106 size_t words_remaining() {
duke@435 107 assert(_end >= _top, "Negative buffer");
duke@435 108 return pointer_delta(_end, _top, HeapWordSize);
duke@435 109 }
duke@435 110
duke@435 111 bool contains(void* addr) {
duke@435 112 return (void*)_bottom <= addr && addr < (void*)_hard_end;
duke@435 113 }
duke@435 114
duke@435 115 // Sets the space of the buffer to be [buf, space+word_sz()).
duke@435 116 void set_buf(HeapWord* buf) {
duke@435 117 _bottom = buf;
duke@435 118 _top = _bottom;
duke@435 119 _hard_end = _bottom + word_sz();
duke@435 120 _end = _hard_end - AlignmentReserve;
duke@435 121 assert(_end >= _top, "Negative buffer");
duke@435 122 // In support of ergonomic sizing
duke@435 123 _allocated += word_sz();
duke@435 124 }
duke@435 125
duke@435 126 // Flush the stats supporting ergonomic sizing of PLAB's
johnc@4067 127 // and retire the current buffer.
johnc@3982 128 void flush_stats_and_retire(PLABStats* stats, bool end_of_gc, bool retain) {
duke@435 129 // We flush the stats first in order to get a reading of
duke@435 130 // unused space in the last buffer.
duke@435 131 if (ResizePLAB) {
duke@435 132 flush_stats(stats);
johnc@4067 133
johnc@4067 134 // Since we have flushed the stats we need to clear
johnc@4067 135 // the _allocated and _wasted fields. Not doing so
johnc@4067 136 // will artifically inflate the values in the stats
johnc@4067 137 // to which we add them.
johnc@4067 138 // The next time we flush these values, we will add
johnc@4067 139 // what we have just flushed in addition to the size
johnc@4067 140 // of the buffers allocated between now and then.
johnc@4067 141 _allocated = 0;
johnc@4067 142 _wasted = 0;
duke@435 143 }
duke@435 144 // Retire the last allocation buffer.
johnc@3982 145 retire(end_of_gc, retain);
duke@435 146 }
duke@435 147
duke@435 148 // Force future allocations to fail and queries for contains()
duke@435 149 // to return false
duke@435 150 void invalidate() {
duke@435 151 assert(!_retained, "Shouldn't retain an invalidated buffer.");
duke@435 152 _end = _hard_end;
duke@435 153 _wasted += pointer_delta(_end, _top); // unused space
duke@435 154 _top = _end; // force future allocations to fail
duke@435 155 _bottom = _end; // force future contains() queries to return false
duke@435 156 }
duke@435 157
duke@435 158 // Fills in the unallocated portion of the buffer with a garbage object.
duke@435 159 // If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain"
duke@435 160 // is true, attempt to re-use the unused portion in the next GC.
duke@435 161 void retire(bool end_of_gc, bool retain);
duke@435 162
duke@435 163 void print() PRODUCT_RETURN;
duke@435 164 };
duke@435 165
duke@435 166 // PLAB stats book-keeping
duke@435 167 class PLABStats VALUE_OBJ_CLASS_SPEC {
duke@435 168 size_t _allocated; // total allocated
duke@435 169 size_t _wasted; // of which wasted (internal fragmentation)
duke@435 170 size_t _unused; // Unused in last buffer
duke@435 171 size_t _used; // derived = allocated - wasted - unused
duke@435 172 size_t _desired_plab_sz;// output of filter (below), suitably trimmed and quantized
duke@435 173 AdaptiveWeightedAverage
duke@435 174 _filter; // integrator with decay
duke@435 175
duke@435 176 public:
duke@435 177 PLABStats(size_t desired_plab_sz_, unsigned wt) :
duke@435 178 _allocated(0),
duke@435 179 _wasted(0),
duke@435 180 _unused(0),
duke@435 181 _used(0),
duke@435 182 _desired_plab_sz(desired_plab_sz_),
duke@435 183 _filter(wt)
duke@435 184 {
duke@435 185 size_t min_sz = min_size();
duke@435 186 size_t max_sz = max_size();
duke@435 187 size_t aligned_min_sz = align_object_size(min_sz);
duke@435 188 size_t aligned_max_sz = align_object_size(max_sz);
duke@435 189 assert(min_sz <= aligned_min_sz && max_sz >= aligned_max_sz &&
duke@435 190 min_sz <= max_sz,
duke@435 191 "PLAB clipping computation in adjust_desired_plab_sz()"
duke@435 192 " may be incorrect");
duke@435 193 }
duke@435 194
duke@435 195 static const size_t min_size() {
duke@435 196 return ParGCAllocBuffer::min_size();
duke@435 197 }
duke@435 198
duke@435 199 static const size_t max_size() {
duke@435 200 return ParGCAllocBuffer::max_size();
duke@435 201 }
duke@435 202
duke@435 203 size_t desired_plab_sz() {
duke@435 204 return _desired_plab_sz;
duke@435 205 }
duke@435 206
duke@435 207 void adjust_desired_plab_sz(); // filter computation, latches output to
duke@435 208 // _desired_plab_sz, clears sensor accumulators
duke@435 209
duke@435 210 void add_allocated(size_t v) {
duke@435 211 Atomic::add_ptr(v, &_allocated);
duke@435 212 }
duke@435 213
duke@435 214 void add_unused(size_t v) {
duke@435 215 Atomic::add_ptr(v, &_unused);
duke@435 216 }
duke@435 217
duke@435 218 void add_wasted(size_t v) {
duke@435 219 Atomic::add_ptr(v, &_wasted);
duke@435 220 }
duke@435 221 };
duke@435 222
duke@435 223 class ParGCAllocBufferWithBOT: public ParGCAllocBuffer {
duke@435 224 BlockOffsetArrayContigSpace _bt;
duke@435 225 BlockOffsetSharedArray* _bsa;
duke@435 226 HeapWord* _true_end; // end of the whole ParGCAllocBuffer
duke@435 227
duke@435 228 static const size_t ChunkSizeInWords;
duke@435 229 static const size_t ChunkSizeInBytes;
duke@435 230 HeapWord* allocate_slow(size_t word_sz);
duke@435 231
duke@435 232 void fill_region_with_block(MemRegion mr, bool contig);
duke@435 233
duke@435 234 public:
duke@435 235 ParGCAllocBufferWithBOT(size_t word_sz, BlockOffsetSharedArray* bsa);
duke@435 236
duke@435 237 HeapWord* allocate(size_t word_sz) {
duke@435 238 HeapWord* res = ParGCAllocBuffer::allocate(word_sz);
duke@435 239 if (res != NULL) {
duke@435 240 _bt.alloc_block(res, word_sz);
duke@435 241 } else {
duke@435 242 res = allocate_slow(word_sz);
duke@435 243 }
duke@435 244 return res;
duke@435 245 }
duke@435 246
duke@435 247 void undo_allocation(HeapWord* obj, size_t word_sz);
duke@435 248
duke@435 249 void set_buf(HeapWord* buf_start) {
duke@435 250 ParGCAllocBuffer::set_buf(buf_start);
duke@435 251 _true_end = _hard_end;
duke@435 252 _bt.set_region(MemRegion(buf_start, word_sz()));
duke@435 253 _bt.initialize_threshold();
duke@435 254 }
duke@435 255
duke@435 256 void retire(bool end_of_gc, bool retain);
duke@435 257
duke@435 258 MemRegion range() {
duke@435 259 return MemRegion(_top, _true_end);
duke@435 260 }
duke@435 261 };
stefank@2314 262
stefank@2314 263 #endif // SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP

mercurial