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