--- old/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-02-23 09:52:22.400737787 +0100 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.cpp 2015-02-23 09:52:22.343736133 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,7 @@ if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) { G1ParGCAllocBuffer* alloc_buf = alloc_buffer(dest, context); add_to_alloc_buffer_waste(alloc_buf->words_remaining()); - alloc_buf->retire(false /* end_of_gc */, false /* retain */); + alloc_buf->retire(); HeapWord* buf = _g1h->par_allocate_during_gc(dest, gclab_word_size, context); if (buf == NULL) { @@ -154,9 +154,7 @@ G1ParGCAllocBuffer* const buf = _alloc_buffers[state]; if (buf != NULL) { add_to_alloc_buffer_waste(buf->words_remaining()); - buf->flush_stats_and_retire(_g1h->alloc_buffer_stats(state), - true /* end_of_gc */, - false /* retain */); + buf->flush_and_retire_stats(_g1h->alloc_buffer_stats(state)); } } } --- old/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-02-23 09:52:22.742747717 +0100 +++ new/src/share/vm/gc_implementation/g1/g1Allocator.hpp 2015-02-23 09:52:22.685746062 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -159,11 +159,11 @@ _retired = false; } - virtual void retire(bool end_of_gc, bool retain) { + virtual void retire() { if (_retired) { return; } - ParGCAllocBuffer::retire(end_of_gc, retain); + ParGCAllocBuffer::retire(); _retired = true; } }; --- old/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2015-02-23 09:52:23.086757704 +0100 +++ new/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp 2015-02-23 09:52:23.027755991 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,7 +232,7 @@ if (word_sz * 100 < ParallelGCBufferWastePct * plab->word_sz()) { // Is small enough; abandon this buffer and start a new one. - plab->retire(false, false); + plab->retire(); size_t buf_size = plab->word_sz(); HeapWord* buf_space = sp->par_allocate(buf_size); if (buf_space == NULL) { @@ -463,10 +463,7 @@ // Flush stats related to To-space PLAB activity and // retire the last buffer. - par_scan_state.to_space_alloc_buffer()-> - flush_stats_and_retire(_gen.plab_stats(), - true /* end_of_gc */, - false /* retain */); + par_scan_state.to_space_alloc_buffer()->flush_and_retire_stats(_gen.plab_stats()); // Every thread has its own age table. We need to merge // them all into one. --- old/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp 2015-02-23 09:52:23.437767894 +0100 +++ new/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp 2015-02-23 09:52:23.380766239 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,27 +24,30 @@ #include "precompiled.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" -#include "memory/sharedHeap.hpp" +#include "memory/threadLocalAllocBuffer.hpp" #include "oops/arrayOop.hpp" #include "oops/oop.inline.hpp" -#include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +size_t ParGCAllocBuffer::min_size() { + // Make sure that we return something that is larger than AlignmentReserve + return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; +} + +size_t ParGCAllocBuffer::max_size() { + return ThreadLocalAllocBuffer::max_size(); +} ParGCAllocBuffer::ParGCAllocBuffer(size_t desired_plab_sz_) : _word_sz(desired_plab_sz_), _bottom(NULL), _top(NULL), - _end(NULL), _hard_end(NULL), - _retained(false), _retained_filler(), - _allocated(0), _wasted(0) + _end(NULL), _hard_end(NULL), _allocated(0), _wasted(0) { - assert (min_size() > AlignmentReserve, "Inconsistency!"); - // arrayOopDesc::header_size depends on command line initialization. - FillerHeaderSize = align_object_size(arrayOopDesc::header_size(T_INT)); - AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? FillerHeaderSize : 0; + // ArrayOopDesc::header_size depends on command line initialization. + AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; + assert(min_size() > AlignmentReserve, + err_msg("Minimum PLAB size " SIZE_FORMAT" must be larger than alignment reserve " SIZE_FORMAT" " + "to be able to contain objects", min_size(), AlignmentReserve)); } -size_t ParGCAllocBuffer::FillerHeaderSize; - // If the minimum object size is greater than MinObjAlignment, we can // end up with a shard at the end of the buffer that's smaller than // the smallest object. We can't allow that because the buffer must @@ -52,41 +55,35 @@ // sure we have enough space for a filler int array object. size_t ParGCAllocBuffer::AlignmentReserve; -void ParGCAllocBuffer::retire(bool end_of_gc, bool retain) { - assert(!retain || end_of_gc, "Can only retain at GC end."); - if (_retained) { - // If the buffer had been retained shorten the previous filler object. - assert(_retained_filler.end() <= _top, "INVARIANT"); - CollectedHeap::fill_with_object(_retained_filler); - // Wasted space book-keeping, otherwise (normally) done in invalidate() - _wasted += _retained_filler.word_size(); - _retained = false; - } - assert(!end_of_gc || !_retained, "At this point, end_of_gc ==> !_retained."); +void ParGCAllocBuffer::flush_and_retire_stats(PLABStats* stats) { + // We want to distinguish between unused space in the last buffer and waste + // created otherwise. Save the amount of unused space because retire() will + // update the pointers we use. + size_t unused = pointer_delta(_end, _top); + + // Retire the last allocation buffer. + retire(); + + stats->add_allocated(_allocated); + // Retire() counts the unused space as wasted. So we need to remove it again + // before updating the statistics. + stats->add_wasted(_wasted - unused); + stats->add_unused(unused); + + // Since we have flushed the stats we need to clear the _allocated and _wasted + // fields in case somebody retains an instance of this over GCs. Not doing so + // will artifically inflate the values in the statistics. + _allocated = 0; + _wasted = 0; +} + +void ParGCAllocBuffer::retire() { if (_top < _hard_end) { CollectedHeap::fill_with_object(_top, _hard_end); - if (!retain) { - invalidate(); - } else { - // Is there wasted space we'd like to retain for the next GC? - if (pointer_delta(_end, _top) > FillerHeaderSize) { - _retained = true; - _retained_filler = MemRegion(_top, FillerHeaderSize); - _top = _top + FillerHeaderSize; - } else { - invalidate(); - } - } + invalidate(); } } -void ParGCAllocBuffer::flush_stats(PLABStats* stats) { - assert(ResizePLAB, "Wasted work"); - stats->add_allocated(_allocated); - stats->add_wasted(_wasted); - stats->add_unused(pointer_delta(_end, _top)); -} - // Compute desired plab size and latch result for later // use. This should be called once at the end of parallel // scavenge; it clears the sensor accumulators. @@ -101,44 +98,37 @@ err_msg("Inconsistency in PLAB stats: " "_allocated: "SIZE_FORMAT", " "_wasted: "SIZE_FORMAT", " - "_unused: "SIZE_FORMAT", " - "_used : "SIZE_FORMAT, - _allocated, _wasted, _unused, _used)); + "_unused: "SIZE_FORMAT, + _allocated, _wasted, _unused)); _allocated = 1; } - double wasted_frac = (double)_unused/(double)_allocated; - size_t target_refills = (size_t)((wasted_frac*TargetSurvivorRatio)/ - TargetPLABWastePct); + double wasted_frac = (double)_unused / (double)_allocated; + size_t target_refills = (size_t)((wasted_frac * TargetSurvivorRatio) / TargetPLABWastePct); if (target_refills == 0) { target_refills = 1; } - _used = _allocated - _wasted - _unused; - size_t plab_sz = _used/(target_refills*no_of_gc_workers); - if (PrintPLAB) gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT " ", plab_sz); + size_t used = _allocated - _wasted - _unused; + size_t recent_plab_sz = used / (target_refills * no_of_gc_workers); // Take historical weighted average - _filter.sample(plab_sz); + _filter.sample(recent_plab_sz); // Clip from above and below, and align to object boundary - plab_sz = MAX2(min_size(), (size_t)_filter.average()); - plab_sz = MIN2(max_size(), plab_sz); - plab_sz = align_object_size(plab_sz); + size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average()); + new_plab_sz = MIN2(max_size(), new_plab_sz); + new_plab_sz = align_object_size(new_plab_sz); // Latch the result - if (PrintPLAB) gclog_or_tty->print(" desired_plab_sz = " SIZE_FORMAT ") ", plab_sz); - _desired_plab_sz = plab_sz; - // Now clear the accumulators for next round: - // note this needs to be fixed in the case where we - // are retaining across scavenges. FIX ME !!! XXX - _allocated = 0; - _wasted = 0; - _unused = 0; + if (PrintPLAB) { + gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT" desired_plab_sz = " SIZE_FORMAT") ", recent_plab_sz, new_plab_sz); + } + _desired_plab_sz = new_plab_sz; + + reset(); } #ifndef PRODUCT void ParGCAllocBuffer::print() { - gclog_or_tty->print("parGCAllocBuffer: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT - " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT " _retained: %c" - " _retained_filler: [" PTR_FORMAT "," PTR_FORMAT ")\n", - _bottom, _top, _end, _hard_end, - "FT"[_retained], _retained_filler.start(), _retained_filler.end()); + gclog_or_tty->print_cr("parGCAllocBuffer: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT + " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT ")", + p2i(_bottom), p2i(_top), p2i(_end), p2i(_hard_end)); } #endif // !PRODUCT --- old/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp 2015-02-23 09:52:23.839779565 +0100 +++ new/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp 2015-02-23 09:52:23.771777591 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,52 +24,40 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARGCALLOCBUFFER_HPP -#include "gc_interface/collectedHeap.hpp" + +#include "gc_implementation/shared/gcUtil.hpp" #include "memory/allocation.hpp" -#include "memory/blockOffsetTable.hpp" -#include "memory/threadLocalAllocBuffer.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" -// Forward decl. - +// Forward declarations. class PLABStats; // A per-thread allocation buffer used during GC. class ParGCAllocBuffer: public CHeapObj { protected: char head[32]; - size_t _word_sz; // in HeapWord units + size_t _word_sz; // In HeapWord units HeapWord* _bottom; HeapWord* _top; - HeapWord* _end; // last allocatable address + 1 - HeapWord* _hard_end; // _end + AlignmentReserve - bool _retained; // whether we hold a _retained_filler - MemRegion _retained_filler; + HeapWord* _end; // Last allocatable address + 1 + HeapWord* _hard_end; // _end + AlignmentReserve // In support of ergonomic sizing of PLAB's size_t _allocated; // in HeapWord units size_t _wasted; // in HeapWord units char tail[32]; - static size_t FillerHeaderSize; static size_t AlignmentReserve; - // Flush the stats supporting ergonomic sizing of PLAB's - // Should not be called directly - void flush_stats(PLABStats* stats); - public: // Initializes the buffer to be empty, but with the given "word_sz". // Must get initialized with "set_buf" for an allocation to succeed. ParGCAllocBuffer(size_t word_sz); virtual ~ParGCAllocBuffer() {} - static const size_t min_size() { - // Make sure that we return something that is larger than AlignmentReserve - return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; - } - - static const size_t max_size() { - return ThreadLocalAllocBuffer::max_size(); - } + // Minimum PLAB size. + static size_t min_size(); + // Maximum PLAB size. + static size_t max_size(); // If an allocation of the given "word_sz" can be satisfied within the // buffer, do the allocation, returning a pointer to the start of the @@ -128,62 +116,45 @@ _allocated += word_sz(); } - // Flush the stats supporting ergonomic sizing of PLAB's - // and retire the current buffer. - void flush_stats_and_retire(PLABStats* stats, bool end_of_gc, bool retain) { - // We flush the stats first in order to get a reading of - // unused space in the last buffer. - if (ResizePLAB) { - flush_stats(stats); - - // Since we have flushed the stats we need to clear - // the _allocated and _wasted fields. Not doing so - // will artifically inflate the values in the stats - // to which we add them. - // The next time we flush these values, we will add - // what we have just flushed in addition to the size - // of the buffers allocated between now and then. - _allocated = 0; - _wasted = 0; - } - // Retire the last allocation buffer. - retire(end_of_gc, retain); - } + // Flush allocation statistics into the given PLABStats supporting ergonomic + // sizing of PLAB's and retire the current buffer. + void flush_and_retire_stats(PLABStats* stats); // Force future allocations to fail and queries for contains() // to return false void invalidate() { - assert(!_retained, "Shouldn't retain an invalidated buffer."); _end = _hard_end; _wasted += pointer_delta(_end, _top); // unused space _top = _end; // force future allocations to fail _bottom = _end; // force future contains() queries to return false } - // Fills in the unallocated portion of the buffer with a garbage object. - // If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain" - // is true, attempt to re-use the unused portion in the next GC. - virtual void retire(bool end_of_gc, bool retain); + // Fills in the unallocated portion of the buffer with a garbage object and update + // statistics. + virtual void retire(); void print() PRODUCT_RETURN; }; -// PLAB stats book-keeping +// PLAB book-keeping. class PLABStats VALUE_OBJ_CLASS_SPEC { - size_t _allocated; // total allocated + size_t _allocated; // Total allocated size_t _wasted; // of which wasted (internal fragmentation) size_t _unused; // Unused in last buffer - size_t _used; // derived = allocated - wasted - unused - size_t _desired_plab_sz;// output of filter (below), suitably trimmed and quantized + size_t _desired_plab_sz;// Output of filter (below), suitably trimmed and quantized AdaptiveWeightedAverage - _filter; // integrator with decay + _filter; // Integrator with decay + void reset() { + _allocated = 0; + _wasted = 0; + _unused = 0; + } 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) { } @@ -200,9 +171,9 @@ return _desired_plab_sz; } + // Updates the current desired PLAB size. Computes the new desired PLAB size, + // updates _desired_plab_sz and clears sensor accumulators. 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); --- old/src/share/vm/memory/tenuredGeneration.cpp 2015-02-23 09:52:24.241791236 +0100 +++ new/src/share/vm/memory/tenuredGeneration.cpp 2015-02-23 09:52:24.173789262 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "gc_implementation/shared/collectorCounters.hpp" #include "gc_implementation/shared/gcTimer.hpp" -#include "gc_implementation/shared/parGCAllocBuffer.hpp" #include "memory/allocation.inline.hpp" #include "memory/blockOffsetTable.inline.hpp" #include "memory/cardGeneration.inline.hpp"