--- 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