duke@435: /* stefank@2314: * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP stefank@2314: #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP stefank@2314: stefank@2314: #include "memory/allocation.hpp" stefank@2325: #include "memory/blockOffsetTable.hpp" stefank@2314: #include "memory/threadLocalAllocBuffer.hpp" stefank@2314: #include "utilities/globalDefinitions.hpp" stefank@2314: duke@435: // Forward decl. duke@435: duke@435: class PLABStats; duke@435: duke@435: // A per-thread allocation buffer used during GC. duke@435: class ParGCAllocBuffer: public CHeapObj { duke@435: protected: duke@435: char head[32]; duke@435: size_t _word_sz; // in HeapWord units duke@435: HeapWord* _bottom; duke@435: HeapWord* _top; duke@435: HeapWord* _end; // last allocatable address + 1 duke@435: HeapWord* _hard_end; // _end + AlignmentReserve duke@435: bool _retained; // whether we hold a _retained_filler duke@435: MemRegion _retained_filler; duke@435: // In support of ergonomic sizing of PLAB's duke@435: size_t _allocated; // in HeapWord units duke@435: size_t _wasted; // in HeapWord units duke@435: char tail[32]; coleenp@548: static size_t FillerHeaderSize; coleenp@548: static size_t AlignmentReserve; duke@435: duke@435: public: duke@435: // Initializes the buffer to be empty, but with the given "word_sz". duke@435: // Must get initialized with "set_buf" for an allocation to succeed. duke@435: ParGCAllocBuffer(size_t word_sz); duke@435: duke@435: static const size_t min_size() { duke@435: return ThreadLocalAllocBuffer::min_size(); duke@435: } duke@435: duke@435: static const size_t max_size() { duke@435: return ThreadLocalAllocBuffer::max_size(); duke@435: } duke@435: duke@435: // If an allocation of the given "word_sz" can be satisfied within the duke@435: // buffer, do the allocation, returning a pointer to the start of the duke@435: // allocated block. If the allocation request cannot be satisfied, duke@435: // return NULL. duke@435: HeapWord* allocate(size_t word_sz) { duke@435: HeapWord* res = _top; ysr@1069: if (pointer_delta(_end, _top) >= word_sz) { ysr@1069: _top = _top + word_sz; duke@435: return res; duke@435: } else { duke@435: return NULL; duke@435: } duke@435: } duke@435: duke@435: // Undo the last allocation in the buffer, which is required to be of the duke@435: // "obj" of the given "word_sz". duke@435: void undo_allocation(HeapWord* obj, size_t word_sz) { ysr@1069: assert(pointer_delta(_top, _bottom) >= word_sz, "Bad undo"); ysr@1069: assert(pointer_delta(_top, obj) == word_sz, "Bad undo"); ysr@1069: _top = obj; duke@435: } duke@435: duke@435: // The total (word) size of the buffer, including both allocated and duke@435: // unallocted space. duke@435: size_t word_sz() { return _word_sz; } duke@435: duke@435: // Should only be done if we are about to reset with a new buffer of the duke@435: // given size. duke@435: void set_word_size(size_t new_word_sz) { duke@435: assert(new_word_sz > AlignmentReserve, "Too small"); duke@435: _word_sz = new_word_sz; duke@435: } duke@435: duke@435: // The number of words of unallocated space remaining in the buffer. duke@435: size_t words_remaining() { duke@435: assert(_end >= _top, "Negative buffer"); duke@435: return pointer_delta(_end, _top, HeapWordSize); duke@435: } duke@435: duke@435: bool contains(void* addr) { duke@435: return (void*)_bottom <= addr && addr < (void*)_hard_end; duke@435: } duke@435: duke@435: // Sets the space of the buffer to be [buf, space+word_sz()). duke@435: void set_buf(HeapWord* buf) { duke@435: _bottom = buf; duke@435: _top = _bottom; duke@435: _hard_end = _bottom + word_sz(); duke@435: _end = _hard_end - AlignmentReserve; duke@435: assert(_end >= _top, "Negative buffer"); duke@435: // In support of ergonomic sizing duke@435: _allocated += word_sz(); duke@435: } duke@435: duke@435: // Flush the stats supporting ergonomic sizing of PLAB's duke@435: void flush_stats(PLABStats* stats); duke@435: void flush_stats_and_retire(PLABStats* stats, bool retain) { duke@435: // We flush the stats first in order to get a reading of duke@435: // unused space in the last buffer. duke@435: if (ResizePLAB) { duke@435: flush_stats(stats); duke@435: } duke@435: // Retire the last allocation buffer. duke@435: retire(true, retain); duke@435: } duke@435: duke@435: // Force future allocations to fail and queries for contains() duke@435: // to return false duke@435: void invalidate() { duke@435: assert(!_retained, "Shouldn't retain an invalidated buffer."); duke@435: _end = _hard_end; duke@435: _wasted += pointer_delta(_end, _top); // unused space duke@435: _top = _end; // force future allocations to fail duke@435: _bottom = _end; // force future contains() queries to return false duke@435: } duke@435: duke@435: // Fills in the unallocated portion of the buffer with a garbage object. duke@435: // If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain" duke@435: // is true, attempt to re-use the unused portion in the next GC. duke@435: void retire(bool end_of_gc, bool retain); duke@435: duke@435: void print() PRODUCT_RETURN; duke@435: }; duke@435: duke@435: // PLAB stats book-keeping duke@435: class PLABStats VALUE_OBJ_CLASS_SPEC { duke@435: size_t _allocated; // total allocated duke@435: size_t _wasted; // of which wasted (internal fragmentation) duke@435: size_t _unused; // Unused in last buffer duke@435: size_t _used; // derived = allocated - wasted - unused duke@435: size_t _desired_plab_sz;// output of filter (below), suitably trimmed and quantized duke@435: AdaptiveWeightedAverage duke@435: _filter; // integrator with decay duke@435: duke@435: public: duke@435: PLABStats(size_t desired_plab_sz_, unsigned wt) : duke@435: _allocated(0), duke@435: _wasted(0), duke@435: _unused(0), duke@435: _used(0), duke@435: _desired_plab_sz(desired_plab_sz_), duke@435: _filter(wt) duke@435: { duke@435: size_t min_sz = min_size(); duke@435: size_t max_sz = max_size(); duke@435: size_t aligned_min_sz = align_object_size(min_sz); duke@435: size_t aligned_max_sz = align_object_size(max_sz); duke@435: assert(min_sz <= aligned_min_sz && max_sz >= aligned_max_sz && duke@435: min_sz <= max_sz, duke@435: "PLAB clipping computation in adjust_desired_plab_sz()" duke@435: " may be incorrect"); duke@435: } duke@435: duke@435: static const size_t min_size() { duke@435: return ParGCAllocBuffer::min_size(); duke@435: } duke@435: duke@435: static const size_t max_size() { duke@435: return ParGCAllocBuffer::max_size(); duke@435: } duke@435: duke@435: size_t desired_plab_sz() { duke@435: return _desired_plab_sz; duke@435: } duke@435: duke@435: void adjust_desired_plab_sz(); // filter computation, latches output to duke@435: // _desired_plab_sz, clears sensor accumulators duke@435: duke@435: void add_allocated(size_t v) { duke@435: Atomic::add_ptr(v, &_allocated); duke@435: } duke@435: duke@435: void add_unused(size_t v) { duke@435: Atomic::add_ptr(v, &_unused); duke@435: } duke@435: duke@435: void add_wasted(size_t v) { duke@435: Atomic::add_ptr(v, &_wasted); duke@435: } duke@435: }; duke@435: duke@435: class ParGCAllocBufferWithBOT: public ParGCAllocBuffer { duke@435: BlockOffsetArrayContigSpace _bt; duke@435: BlockOffsetSharedArray* _bsa; duke@435: HeapWord* _true_end; // end of the whole ParGCAllocBuffer duke@435: duke@435: static const size_t ChunkSizeInWords; duke@435: static const size_t ChunkSizeInBytes; duke@435: HeapWord* allocate_slow(size_t word_sz); duke@435: duke@435: void fill_region_with_block(MemRegion mr, bool contig); duke@435: duke@435: public: duke@435: ParGCAllocBufferWithBOT(size_t word_sz, BlockOffsetSharedArray* bsa); duke@435: duke@435: HeapWord* allocate(size_t word_sz) { duke@435: HeapWord* res = ParGCAllocBuffer::allocate(word_sz); duke@435: if (res != NULL) { duke@435: _bt.alloc_block(res, word_sz); duke@435: } else { duke@435: res = allocate_slow(word_sz); duke@435: } duke@435: return res; duke@435: } duke@435: duke@435: void undo_allocation(HeapWord* obj, size_t word_sz); duke@435: duke@435: void set_buf(HeapWord* buf_start) { duke@435: ParGCAllocBuffer::set_buf(buf_start); duke@435: _true_end = _hard_end; duke@435: _bt.set_region(MemRegion(buf_start, word_sz())); duke@435: _bt.initialize_threshold(); duke@435: } duke@435: duke@435: void retire(bool end_of_gc, bool retain); duke@435: duke@435: MemRegion range() { duke@435: return MemRegion(_top, _true_end); duke@435: } duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP