--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -620,7 +620,7 @@
// Support for parallelizing survivor space rescan
if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) {
const size_t max_plab_samples =
- _young_gen->max_survivor_size() / (ThreadLocalAllocBuffer::min_size() * HeapWordSize);
+ _young_gen->max_survivor_size() / (PLAB::min_size() * HeapWordSize);
_survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC);
_survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC);
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "gc/cms/compactibleFreeListSpace.hpp"
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
-#include "gc/cms/parNewGeneration.hpp"
+#include "gc/cms/parNewGeneration.inline.hpp"
#include "gc/cms/parOopClosures.inline.hpp"
#include "gc/serial/defNewGeneration.inline.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -169,11 +169,7 @@
// Allocate a to-space block of size "sz", or else return NULL.
HeapWord* alloc_in_to_space_slow(size_t word_sz);
- HeapWord* alloc_in_to_space(size_t word_sz) {
- HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
- if (obj != NULL) return obj;
- else return alloc_in_to_space_slow(word_sz);
- }
+ inline HeapWord* alloc_in_to_space(size_t word_sz);
HeapWord* young_old_boundary() { return _young_old_boundary; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.inline.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
+#define SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
+
+#include "gc/cms/parNewGeneration.hpp"
+#include "gc/shared/plab.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+inline HeapWord* ParScanThreadState::alloc_in_to_space(size_t word_sz) {
+ HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
+ if (obj != NULL) return obj;
+ else return alloc_in_to_space_slow(word_sz);
+}
+#endif // SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
--- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -46,10 +46,11 @@
_dummy_region = dummy_region;
}
-void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
- bool bot_updates) {
+size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
+ bool bot_updates) {
assert(alloc_region != NULL && alloc_region != _dummy_region,
"pre-condition");
+ size_t result = 0;
// Other threads might still be trying to allocate using a CAS out
// of the region we are trying to retire, as they can do so without
@@ -73,6 +74,7 @@
// If the allocation was successful we should fill in the space.
CollectedHeap::fill_with_object(dummy, free_word_size);
alloc_region->set_pre_dummy_top(dummy);
+ result += free_word_size * HeapWordSize;
break;
}
@@ -81,13 +83,18 @@
// allocation and they fill up the region. In that case, we can
// just get out of the loop.
}
+ result += alloc_region->free();
+
assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill,
"post-condition");
+ return result;
}
-void G1AllocRegion::retire(bool fill_up) {
+size_t G1AllocRegion::retire(bool fill_up) {
assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
+ size_t result = 0;
+
trace("retiring");
HeapRegion* alloc_region = _alloc_region;
if (alloc_region != _dummy_region) {
@@ -98,7 +105,7 @@
ar_ext_msg(this, "the alloc region should never be empty"));
if (fill_up) {
- fill_up_remaining_space(alloc_region, _bot_updates);
+ result = fill_up_remaining_space(alloc_region, _bot_updates);
}
assert(alloc_region->used() >= _used_bytes_before,
@@ -109,6 +116,8 @@
_alloc_region = _dummy_region;
}
trace("retired");
+
+ return result;
}
HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
@@ -251,26 +260,25 @@
_g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes);
}
-HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size,
- bool force) {
+HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size,
+ bool force) {
assert(!force, "not supported for GC alloc regions");
- return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Young);
+ return _g1h->new_gc_alloc_region(word_size, count(), _purpose);
}
-void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region,
- size_t allocated_bytes) {
- _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Young);
+void G1GCAllocRegion::retire_region(HeapRegion* alloc_region,
+ size_t allocated_bytes) {
+ _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, _purpose);
}
-HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size,
- bool force) {
- assert(!force, "not supported for GC alloc regions");
- return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Old);
-}
-
-void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
- size_t allocated_bytes) {
- _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Old);
+size_t G1GCAllocRegion::retire(bool fill_up) {
+ HeapRegion* retired = get();
+ size_t end_waste = G1AllocRegion::retire(fill_up);
+ // Do not count retirement of the dummy allocation region.
+ if (retired != NULL) {
+ _stats->add_region_end_waste(end_waste / HeapWordSize);
+ }
+ return end_waste;
}
HeapRegion* OldGCAllocRegion::release() {
--- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -26,6 +26,8 @@
#define SHARE_VM_GC_G1_G1ALLOCREGION_HPP
#include "gc/g1/heapRegion.hpp"
+#include "gc/g1/g1EvacStats.hpp"
+#include "gc/g1/g1InCSetState.hpp"
class G1CollectedHeap;
@@ -105,13 +107,10 @@
// Ensure that the region passed as a parameter has been filled up
// so that noone else can allocate out of it any more.
- static void fill_up_remaining_space(HeapRegion* alloc_region,
- bool bot_updates);
-
- // Retire the active allocating region. If fill_up is true then make
- // sure that the region is full before we retire it so that noone
- // else can allocate out of it.
- void retire(bool fill_up);
+ // Returns the number of bytes that have been wasted by filled up
+ // the space.
+ static size_t fill_up_remaining_space(HeapRegion* alloc_region,
+ bool bot_updates);
// After a region is allocated by alloc_new_region, this
// method is used to set it as the active alloc_region
@@ -126,6 +125,12 @@
void fill_in_ext_msg(ar_ext_msg* msg, const char* message);
protected:
+ // Retire the active allocating region. If fill_up is true then make
+ // sure that the region is full before we retire it so that no one
+ // else can allocate out of it.
+ // Returns the number of bytes that have been filled up during retire.
+ virtual size_t retire(bool fill_up);
+
// For convenience as subclasses use it.
static G1CollectedHeap* _g1h;
@@ -201,22 +206,33 @@
: G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { }
};
-class SurvivorGCAllocRegion : public G1AllocRegion {
+// Common base class for allocation regions used during GC.
+class G1GCAllocRegion : public G1AllocRegion {
protected:
+ G1EvacStats* _stats;
+ InCSetState::in_cset_state_t _purpose;
+
virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
+
+ virtual size_t retire(bool fill_up);
public:
- SurvivorGCAllocRegion()
- : G1AllocRegion("Survivor GC Alloc Region", false /* bot_updates */) { }
+ G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, InCSetState::in_cset_state_t purpose)
+ : G1AllocRegion(name, bot_updates), _stats(stats), _purpose(purpose) {
+ assert(stats != NULL, "Must pass non-NULL PLAB statistics");
+ }
};
-class OldGCAllocRegion : public G1AllocRegion {
-protected:
- virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
- virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
+class SurvivorGCAllocRegion : public G1GCAllocRegion {
public:
- OldGCAllocRegion()
- : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { }
+ SurvivorGCAllocRegion(G1EvacStats* stats)
+ : G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, InCSetState::Young) { }
+};
+
+class OldGCAllocRegion : public G1GCAllocRegion {
+public:
+ OldGCAllocRegion(G1EvacStats* stats)
+ : G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, InCSetState::Old) { }
// This specialization of release() makes sure that the last card that has
// been allocated into has been completely filled by a dummy object. This
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -30,6 +30,13 @@
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
+G1DefaultAllocator::G1DefaultAllocator(G1CollectedHeap* heap) :
+ G1Allocator(heap),
+ _retained_old_gc_alloc_region(NULL),
+ _survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)),
+ _old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)) {
+}
+
void G1DefaultAllocator::init_mutator_alloc_region() {
assert(_mutator_alloc_region.get() == NULL, "pre-condition");
_mutator_alloc_region.init();
@@ -79,6 +86,8 @@
void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
assert_at_safepoint(true /* should_be_vm_thread */);
+ G1Allocator::init_gc_alloc_regions(evacuation_info);
+
_survivor_gc_alloc_region.init();
_old_gc_alloc_region.init();
reuse_retained_old_region(evacuation_info,
@@ -101,10 +110,8 @@
_retained_old_gc_alloc_region->record_retained_region();
}
- if (ResizePLAB) {
- _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
- _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
- }
+ _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
+ _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
}
void G1DefaultAllocator::abandon_gc_alloc_regions() {
@@ -147,6 +154,22 @@
}
}
+bool G1Allocator::survivor_is_full(AllocationContext_t context) const {
+ return _survivor_is_full;
+}
+
+bool G1Allocator::old_is_full(AllocationContext_t context) const {
+ return _old_is_full;
+}
+
+void G1Allocator::set_survivor_full(AllocationContext_t context) {
+ _survivor_is_full = true;
+}
+
+void G1Allocator::set_old_full(AllocationContext_t context) {
+ _old_is_full = true;
+}
+
HeapWord* G1Allocator::survivor_attempt_allocation(size_t word_size,
AllocationContext_t context) {
assert(!_g1h->is_humongous(word_size),
@@ -154,10 +177,13 @@
HeapWord* result = survivor_gc_alloc_region(context)->attempt_allocation(word_size,
false /* bot_updates */);
- if (result == NULL) {
+ if (result == NULL && !survivor_is_full(context)) {
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
result = survivor_gc_alloc_region(context)->attempt_allocation_locked(word_size,
false /* bot_updates */);
+ if (result == NULL) {
+ set_survivor_full(context);
+ }
}
if (result != NULL) {
_g1h->dirty_young_block(result, word_size);
@@ -172,42 +198,59 @@
HeapWord* result = old_gc_alloc_region(context)->attempt_allocation(word_size,
true /* bot_updates */);
- if (result == NULL) {
+ if (result == NULL && !old_is_full(context)) {
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
result = old_gc_alloc_region(context)->attempt_allocation_locked(word_size,
true /* bot_updates */);
+ if (result == NULL) {
+ set_old_full(context);
+ }
}
return result;
}
+void G1Allocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
+ _survivor_is_full = false;
+ _old_is_full = false;
+}
+
G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator),
_survivor_alignment_bytes(calc_survivor_alignment_bytes()) {
+ for (size_t i = 0; i < ARRAY_SIZE(_direct_allocated); i++) {
+ _direct_allocated[i] = 0;
+ }
}
HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest,
size_t word_sz,
- AllocationContext_t context) {
+ AllocationContext_t context,
+ bool* plab_refill_failed) {
size_t gclab_word_size = _g1h->desired_plab_sz(dest);
if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) {
G1PLAB* alloc_buf = alloc_buffer(dest, context);
alloc_buf->retire();
HeapWord* buf = _allocator->par_allocate_during_gc(dest, gclab_word_size, context);
- if (buf == NULL) {
- return NULL; // Let caller handle allocation failure.
+ if (buf != NULL) {
+ // Otherwise.
+ alloc_buf->set_word_size(gclab_word_size);
+ alloc_buf->set_buf(buf);
+
+ HeapWord* const obj = alloc_buf->allocate(word_sz);
+ assert(obj != NULL, "buffer was definitely big enough...");
+ return obj;
}
// Otherwise.
- alloc_buf->set_word_size(gclab_word_size);
- alloc_buf->set_buf(buf);
-
- HeapWord* const obj = alloc_buf->allocate(word_sz);
- assert(obj != NULL, "buffer was definitely big enough...");
- return obj;
- } else {
- return _allocator->par_allocate_during_gc(dest, word_sz, context);
+ *plab_refill_failed = true;
}
+ // Try direct allocation.
+ HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz, context);
+ if (result != NULL) {
+ _direct_allocated[dest.value()] += word_sz;
+ }
+ return result;
}
void G1PLABAllocator::undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context) {
@@ -225,11 +268,14 @@
_alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
}
-void G1DefaultPLABAllocator::retire_alloc_buffers() {
+void G1DefaultPLABAllocator::flush_and_retire_stats() {
for (uint state = 0; state < InCSetState::Num; state++) {
G1PLAB* const buf = _alloc_buffers[state];
if (buf != NULL) {
- buf->flush_and_retire_stats(_g1h->alloc_buffer_stats(state));
+ G1EvacStats* stats = _g1h->alloc_buffer_stats(state);
+ buf->flush_and_retire_stats(stats);
+ stats->add_direct_allocated(_direct_allocated[state]);
+ _direct_allocated[state] = 0;
}
}
}
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -38,11 +38,20 @@
// Also keeps track of retained regions across GCs.
class G1Allocator : public CHeapObj<mtGC> {
friend class VMStructs;
+private:
+ bool _survivor_is_full;
+ bool _old_is_full;
protected:
G1CollectedHeap* _g1h;
virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0;
+ virtual bool survivor_is_full(AllocationContext_t context) const;
+ virtual bool old_is_full(AllocationContext_t context) const;
+
+ virtual void set_survivor_full(AllocationContext_t context);
+ virtual void set_old_full(AllocationContext_t context);
+
// Accessors to the allocation regions.
virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0;
virtual OldGCAllocRegion* old_gc_alloc_region(AllocationContext_t context) = 0;
@@ -54,7 +63,7 @@
inline HeapWord* old_attempt_allocation(size_t word_size,
AllocationContext_t context);
public:
- G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { }
+ G1Allocator(G1CollectedHeap* heap) : _g1h(heap), _survivor_is_full(false), _old_is_full(false) { }
virtual ~G1Allocator() { }
static G1Allocator* create_allocator(G1CollectedHeap* g1h);
@@ -66,7 +75,7 @@
virtual void init_mutator_alloc_region() = 0;
virtual void release_mutator_alloc_region() = 0;
- virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
+ virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
virtual void abandon_gc_alloc_regions() = 0;
@@ -114,7 +123,7 @@
HeapRegion* _retained_old_gc_alloc_region;
public:
- G1DefaultAllocator(G1CollectedHeap* heap) : G1Allocator(heap), _retained_old_gc_alloc_region(NULL) { }
+ G1DefaultAllocator(G1CollectedHeap* heap);
virtual void init_mutator_alloc_region();
virtual void release_mutator_alloc_region();
@@ -163,6 +172,10 @@
guarantee(_retired, "Allocation buffer has not been retired");
}
+ // The amount of space in words wasted within the PLAB including
+ // waste due to refills and alignment.
+ size_t wasted() const { return _wasted; }
+
virtual void set_buf(HeapWord* buf) {
PLAB::set_buf(buf);
_retired = false;
@@ -198,7 +211,10 @@
// architectures have a special compare against zero instructions.
const uint _survivor_alignment_bytes;
- virtual void retire_alloc_buffers() = 0;
+ // Number of words allocated directly (not counting PLAB allocation).
+ size_t _direct_allocated[InCSetState::Num];
+
+ virtual void flush_and_retire_stats() = 0;
virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0;
// Calculate the survivor space object alignment in bytes. Returns that or 0 if
@@ -215,6 +231,10 @@
}
}
+ HeapWord* allocate_new_plab(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context);
+
public:
G1PLABAllocator(G1Allocator* allocator);
virtual ~G1PLABAllocator() { }
@@ -225,31 +245,28 @@
// Allocate word_sz words in dest, either directly into the regions or by
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
- // not successful.
+ // not successful. Plab_refill_failed indicates whether an attempt to refill the
+ // PLAB failed or not.
HeapWord* allocate_direct_or_new_plab(InCSetState dest,
size_t word_sz,
- AllocationContext_t context);
+ AllocationContext_t context,
+ bool* plab_refill_failed);
// Allocate word_sz words in the PLAB of dest. Returns the address of the
// allocated memory, NULL if not successful.
- HeapWord* plab_allocate(InCSetState dest,
- size_t word_sz,
- AllocationContext_t context) {
- G1PLAB* buffer = alloc_buffer(dest, context);
- if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
- return buffer->allocate(word_sz);
- } else {
- return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
- }
- }
+ inline HeapWord* plab_allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context);
- HeapWord* allocate(InCSetState dest, size_t word_sz,
- AllocationContext_t context) {
+ HeapWord* allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context,
+ bool* refill_failed) {
HeapWord* const obj = plab_allocate(dest, word_sz, context);
if (obj != NULL) {
return obj;
}
- return allocate_direct_or_new_plab(dest, word_sz, context);
+ return allocate_direct_or_new_plab(dest, word_sz, context, refill_failed);
}
void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context);
@@ -273,7 +290,7 @@
return _alloc_buffers[dest.value()];
}
- virtual void retire_alloc_buffers();
+ virtual void flush_and_retire_stats();
virtual void waste(size_t& wasted, size_t& undo_wasted);
};
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -27,6 +27,7 @@
#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1AllocRegion.inline.hpp"
+#include "gc/shared/plab.inline.hpp"
HeapWord* G1Allocator::attempt_allocation(size_t word_size, AllocationContext_t context) {
return mutator_alloc_region(context)->attempt_allocation(word_size, false /* bot_updates */);
@@ -43,4 +44,15 @@
return mutator_alloc_region(context)->attempt_allocation_force(word_size, false /* bot_updates */);
}
+inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context) {
+ G1PLAB* buffer = alloc_buffer(dest, context);
+ if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
+ return buffer->allocate(word_sz);
+ } else {
+ return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
+ }
+}
+
#endif // SHARE_VM_GC_G1_G1ALLOCATOR_HPP
--- a/hotspot/src/share/vm/gc/g1/g1Allocator_ext.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator_ext.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "gc/g1/g1Allocator.hpp"
+#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
G1Allocator* G1Allocator::create_allocator(G1CollectedHeap* g1h) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -1944,8 +1944,8 @@
_young_list(new YoungList(this)),
_gc_time_stamp(0),
_summary_bytes_used(0),
- _survivor_plab_stats(YoungPLABSize, PLABWeight),
- _old_plab_stats(OldPLABSize, PLABWeight),
+ _survivor_evac_stats(YoungPLABSize, PLABWeight),
+ _old_evac_stats(OldPLABSize, PLABWeight),
_expand_heap_after_alloc_failure(true),
_surviving_young_words(NULL),
_old_marking_cycles_started(0),
@@ -5972,6 +5972,11 @@
cur->set_evacuation_failed(false);
// The region is now considered to be old.
cur->set_old();
+ // Do some allocation statistics accounting. Regions that failed evacuation
+ // are always made old, so there is no need to update anything in the young
+ // gen statistics, but we need to update old gen statistics.
+ size_t used_words = cur->marked_bytes() / HeapWordSize;
+ _old_evac_stats.add_failure_used_and_waste(used_words, HeapRegion::GrainWords - used_words);
_old_set.add(cur);
evacuation_info.increment_collectionset_used_after(cur->used());
}
@@ -6217,6 +6222,10 @@
}
}
+bool G1CollectedHeap::is_old_gc_alloc_region(HeapRegion* hr) {
+ return _allocator->is_retained_old_region(hr);
+}
+
void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) {
_young_list->push_region(hr);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -28,12 +28,12 @@
#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/evacuationInfo.hpp"
#include "gc/g1/g1AllocationContext.hpp"
-#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1BiasedArray.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
+#include "gc/g1/g1EvacStats.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/g1YCTypes.hpp"
#include "gc/g1/hSpaceCounters.hpp"
@@ -41,6 +41,7 @@
#include "gc/g1/heapRegionSet.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/plab.hpp"
#include "memory/memRegion.hpp"
#include "utilities/stack.hpp"
@@ -76,6 +77,8 @@
class nmethod;
class Ticks;
class WorkGang;
+class G1Allocator;
+class G1ArchiveAllocator;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -184,8 +187,7 @@
friend class VM_G1IncCollectionPause;
friend class VMStructs;
friend class MutatorAllocRegion;
- friend class SurvivorGCAllocRegion;
- friend class OldGCAllocRegion;
+ friend class G1GCAllocRegion;
// Closures used in implementation.
friend class G1ParScanThreadState;
@@ -245,7 +247,7 @@
// The sequence of all heap regions in the heap.
HeapRegionManager _hrm;
- // Handles non-humongous allocations in the G1CollectedHeap.
+ // Manages all allocations with regions except humongous object allocations.
G1Allocator* _allocator;
// Outside of GC pauses, the number of bytes used in all regions other
@@ -263,11 +265,11 @@
// Statistics for each allocation context
AllocationContextStats _allocation_context_stats;
- // PLAB sizing policy for survivors.
- PLABStats _survivor_plab_stats;
+ // GC allocation statistics policy for survivors.
+ G1EvacStats _survivor_evac_stats;
- // PLAB sizing policy for tenured objects.
- PLABStats _old_plab_stats;
+ // GC allocation statistics policy for tenured objects.
+ G1EvacStats _old_evac_stats;
// It specifies whether we should attempt to expand the heap after a
// region allocation failure. If heap expansion fails we set this to
@@ -606,7 +608,7 @@
bool expand(size_t expand_bytes);
// Returns the PLAB statistics for a given destination.
- inline PLABStats* alloc_buffer_stats(InCSetState dest);
+ inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
// Determines PLAB size for a given destination.
inline size_t desired_plab_sz(InCSetState dest);
@@ -1195,9 +1197,7 @@
// Determine whether the given region is one that we are using as an
// old GC alloc region.
- bool is_old_gc_alloc_region(HeapRegion* hr) {
- return _allocator->is_retained_old_region(hr);
- }
+ bool is_old_gc_alloc_region(HeapRegion* hr);
// Perform a collection of the heap; intended for use in implementing
// "System.gc". This probably implies as full a collection as the
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -35,12 +35,12 @@
#include "gc/shared/taskqueue.hpp"
#include "runtime/orderAccess.inline.hpp"
-PLABStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
+G1EvacStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
switch (dest.value()) {
case InCSetState::Young:
- return &_survivor_plab_stats;
+ return &_survivor_evac_stats;
case InCSetState::Old:
- return &_old_plab_stats;
+ return &_old_evac_stats;
default:
ShouldNotReachHere();
return NULL; // Keep some compilers happy
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -26,8 +26,8 @@
#define SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP
#include "gc/g1/collectionSetChooser.hpp"
-#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MMUTracker.hpp"
#include "gc/shared/collectorPolicy.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy_ext.hpp Thu Aug 20 11:18:51 2015 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
-#define SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
-
-#include "gc/g1/g1CollectorPolicy.hpp"
-
-class G1CollectorPolicyExt : public G1CollectorPolicy { };
-
-#endif // SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1EvacStats.hpp"
+#include "gc/shared/gcId.hpp"
+#include "trace/tracing.hpp"
+
+void G1EvacStats::adjust_desired_plab_sz() {
+ if (PrintPLAB) {
+ gclog_or_tty->print(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " "
+ "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " "
+ "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " "
+ "regions filled = %u direct_allocated = " SIZE_FORMAT " "
+ "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") ",
+ _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste,
+ _regions_filled, _direct_allocated, _failure_used, _failure_waste);
+ }
+
+ if (ResizePLAB) {
+
+ assert(is_object_aligned(max_size()) && min_size() <= max_size(),
+ "PLAB clipping computation may be incorrect");
+
+ if (_allocated == 0) {
+ assert((_unused == 0),
+ err_msg("Inconsistency in PLAB stats: "
+ "_allocated: "SIZE_FORMAT", "
+ "_wasted: "SIZE_FORMAT", "
+ "_region_end_waste: "SIZE_FORMAT", "
+ "_unused: "SIZE_FORMAT", "
+ "_used : "SIZE_FORMAT,
+ _allocated, _wasted, _region_end_waste, _unused, used()));
+ _allocated = 1;
+ }
+ // We account region end waste fully to PLAB allocation. This is not completely fair,
+ // but is a conservative assumption because PLABs may be sized flexibly while we
+ // cannot adjust direct allocations.
+ // In some cases, wasted_frac may become > 1 but that just reflects the problem
+ // with region_end_waste.
+ double wasted_frac = (double)(_unused + _wasted + _region_end_waste) / (double)_allocated;
+ size_t target_refills = (size_t)((wasted_frac * TargetSurvivorRatio) / TargetPLABWastePct);
+ if (target_refills == 0) {
+ target_refills = 1;
+ }
+ size_t cur_plab_sz = used() / target_refills;
+ // Take historical weighted average
+ _filter.sample(cur_plab_sz);
+ // Clip from above and below, and align to object boundary
+ size_t plab_sz;
+ plab_sz = MAX2(min_size(), (size_t)_filter.average());
+ plab_sz = MIN2(max_size(), plab_sz);
+ plab_sz = align_object_size(plab_sz);
+ // Latch the result
+ _desired_net_plab_sz = plab_sz;
+ if (PrintPLAB) {
+ gclog_or_tty->print_cr(" (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ") ", cur_plab_sz, plab_sz);
+ }
+ }
+ // Clear accumulators for next round.
+ reset();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_gc_G1_G1EVACSTATS_HPP
+#define SHARE_VM_gc_G1_G1EVACSTATS_HPP
+
+#include "gc/shared/plab.hpp"
+#include "runtime/atomic.hpp"
+
+// Records various memory allocation statistics gathered during evacuation.
+class G1EvacStats : public PLABStats {
+ private:
+ size_t _region_end_waste; // Number of words wasted due to skipping to the next region.
+ uint _regions_filled; // Number of regions filled completely.
+ size_t _direct_allocated; // Number of words allocated directly into the regions.
+
+ // Number of words in live objects remaining in regions that ultimately suffered an
+ // evacuation failure. This is used in the regions when the regions are made old regions.
+ size_t _failure_used;
+ // Number of words wasted in regions which failed evacuation. This is the sum of space
+ // for objects successfully copied out of the regions (now dead space) plus waste at the
+ // end of regions.
+ size_t _failure_waste;
+
+ virtual void reset() {
+ PLABStats::reset();
+ _region_end_waste = 0;
+ _regions_filled = 0;
+ _direct_allocated = 0;
+ _failure_used = 0;
+ _failure_waste = 0;
+ }
+
+ public:
+ G1EvacStats(size_t desired_plab_sz_, unsigned wt) : PLABStats(desired_plab_sz_, wt),
+ _region_end_waste(0), _regions_filled(0), _direct_allocated(0),
+ _failure_used(0), _failure_waste(0) {
+ }
+
+ virtual void adjust_desired_plab_sz();
+
+ size_t allocated() const { return _allocated; }
+ size_t wasted() const { return _wasted; }
+ size_t unused() const { return _unused; }
+ size_t used() const { return allocated() - (wasted() + unused()); }
+ size_t undo_wasted() const { return _undo_wasted; }
+
+ uint regions_filled() const { return _regions_filled; }
+ size_t region_end_waste() const { return _region_end_waste; }
+ size_t direct_allocated() const { return _direct_allocated; }
+
+ // Amount of space in heapwords used in the failing regions when an evacuation failure happens.
+ size_t failure_used() const { return _failure_used; }
+ // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens.
+ size_t failure_waste() const { return _failure_waste; }
+
+ void add_direct_allocated(size_t value) {
+ Atomic::add_ptr(value, &_direct_allocated);
+ }
+
+ void add_region_end_waste(size_t value) {
+ Atomic::add_ptr(value, &_region_end_waste);
+ Atomic::add_ptr(1, &_regions_filled);
+ }
+
+ void add_failure_used_and_waste(size_t used, size_t waste) {
+ Atomic::add_ptr(used, &_failure_used);
+ Atomic::add_ptr(waste, &_failure_waste);
+ }
+};
+
+#endif // SHARE_VM_gc_G1_G1EVACSTATS_HPP
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
@@ -41,7 +42,9 @@
_term_attempts(0),
_tenuring_threshold(g1h->g1_policy()->tenuring_threshold()),
_age_table(false), _scanner(g1h, rp),
- _strong_roots_time(0), _term_time(0) {
+ _strong_roots_time(0), _term_time(0),
+ _old_gen_is_full(false)
+{
_scanner.set_par_scan_thread_state(this);
// we allocate G1YoungSurvRateNumRegions plus one entries, since
// we "sacrifice" entry 0 to keep track of surviving bytes for
@@ -71,7 +74,7 @@
}
G1ParScanThreadState::~G1ParScanThreadState() {
- _plab_allocator->retire_alloc_buffers();
+ _plab_allocator->flush_and_retire_stats();
delete _plab_allocator;
FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base);
}
@@ -152,26 +155,38 @@
HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
size_t word_sz,
- AllocationContext_t const context) {
+ AllocationContext_t const context,
+ bool previous_plab_refill_failed) {
assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value()));
assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
// Right now we only have two types of regions (young / old) so
// let's keep the logic here simple. We can generalize it when necessary.
if (dest->is_young()) {
+ bool plab_refill_in_old_failed = false;
HeapWord* const obj_ptr = _plab_allocator->allocate(InCSetState::Old,
word_sz,
- context);
- if (obj_ptr == NULL) {
- return NULL;
- }
+ context,
+ &plab_refill_in_old_failed);
// Make sure that we won't attempt to copy any other objects out
// of a survivor region (given that apparently we cannot allocate
- // any new ones) to avoid coming into this slow path.
- _tenuring_threshold = 0;
- dest->set_old();
+ // any new ones) to avoid coming into this slow path again and again.
+ // Only consider failed PLAB refill here: failed inline allocations are
+ // typically large, so not indicative of remaining space.
+ if (previous_plab_refill_failed) {
+ _tenuring_threshold = 0;
+ }
+
+ if (obj_ptr != NULL) {
+ dest->set_old();
+ } else {
+ // We just failed to allocate in old gen. The same idea as explained above
+ // for making survivor gen unavailable for allocation applies for old gen.
+ _old_gen_is_full = plab_refill_in_old_failed;
+ }
return obj_ptr;
} else {
+ _old_gen_is_full = previous_plab_refill_failed;
assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
// no other space to try.
return NULL;
@@ -202,14 +217,20 @@
uint age = 0;
InCSetState dest_state = next_state(state, old_mark, age);
+ // The second clause is to prevent premature evacuation failure in case there
+ // is still space in survivor, but old gen is full.
+ if (_old_gen_is_full && dest_state.is_old()) {
+ return handle_evacuation_failure_par(old, old_mark);
+ }
HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_state, word_sz, context);
// PLAB allocations should succeed most of the time, so we'll
// normally check against NULL once and that's it.
if (obj_ptr == NULL) {
- obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context);
+ bool plab_refill_failed = false;
+ obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context, &plab_refill_failed);
if (obj_ptr == NULL) {
- obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context);
+ obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context, plab_refill_failed);
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -35,6 +35,7 @@
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
+class G1PLABAllocator;
class HeapRegion;
class outputStream;
@@ -71,6 +72,10 @@
// this points into the array, as we use the first few entries for padding
size_t* _surviving_young_words;
+ // Indicates whether in the last generation (old) there is no more space
+ // available for allocation.
+ bool _old_gen_is_full;
+
#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t))
DirtyCardQueue& dirty_card_queue() { return _dcq; }
@@ -190,12 +195,16 @@
// Tries to allocate word_sz in the PLAB of the next "generation" after trying to
// allocate into dest. State is the original (source) cset state for the object
- // that is allocated for.
+ // that is allocated for. Previous_plab_refill_failed indicates whether previously
+ // a PLAB refill into "state" failed.
// Returns a non-NULL pointer if successful, and updates dest if required.
+ // Also determines whether we should continue to try to allocate into the various
+ // generations or just end trying to allocate.
HeapWord* allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
size_t word_sz,
- AllocationContext_t const context);
+ AllocationContext_t const context,
+ bool previous_plab_refill_failed);
inline InCSetState next_state(InCSetState const state, markOop const m, uint& age);
public:
--- a/hotspot/src/share/vm/gc/shared/plab.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/shared/plab.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/plab.hpp"
+#include "gc/shared/plab.inline.hpp"
#include "gc/shared/threadLocalAllocBuffer.hpp"
#include "oops/arrayOop.hpp"
#include "oops/oop.inline.hpp"
--- a/hotspot/src/share/vm/gc/shared/plab.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/shared/plab.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -27,7 +27,6 @@
#include "gc/shared/gcUtil.hpp"
#include "memory/allocation.hpp"
-#include "runtime/atomic.hpp"
#include "utilities/globalDefinitions.hpp"
// Forward declarations.
@@ -95,7 +94,7 @@
}
// Allocate the object aligned to "alignment_in_bytes".
- HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes);
+ inline HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes);
// Undo any allocation in the buffer, which is required to be of the
// "obj" of the given "word_sz".
@@ -149,7 +148,8 @@
};
// PLAB book-keeping.
-class PLABStats VALUE_OBJ_CLASS_SPEC {
+class PLABStats : public CHeapObj<mtGC> {
+ protected:
size_t _allocated; // Total allocated
size_t _wasted; // of which wasted (internal fragmentation)
size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size)
@@ -158,7 +158,7 @@
AdaptiveWeightedAverage
_filter; // Integrator with decay
- void reset() {
+ virtual void reset() {
_allocated = 0;
_wasted = 0;
_undo_wasted = 0;
@@ -174,6 +174,8 @@
_filter(wt)
{ }
+ virtual ~PLABStats() { }
+
static const size_t min_size() {
return PLAB::min_size();
}
@@ -187,23 +189,15 @@
// Updates the current desired PLAB size. Computes the new desired PLAB size with one gc worker thread,
// updates _desired_plab_sz and clears sensor accumulators.
- void adjust_desired_plab_sz();
+ virtual void adjust_desired_plab_sz();
- void add_allocated(size_t v) {
- Atomic::add_ptr(v, &_allocated);
- }
+ inline void add_allocated(size_t v);
- void add_unused(size_t v) {
- Atomic::add_ptr(v, &_unused);
- }
+ inline void add_unused(size_t v);
- void add_wasted(size_t v) {
- Atomic::add_ptr(v, &_wasted);
- }
+ inline void add_wasted(size_t v);
- void add_undo_wasted(size_t v) {
- Atomic::add_ptr(v, &_undo_wasted);
- }
+ inline void add_undo_wasted(size_t v);
};
#endif // SHARE_VM_GC_SHARED_PLAB_HPP
--- a/hotspot/src/share/vm/gc/shared/plab.inline.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/gc/shared/plab.inline.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -27,9 +27,10 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/plab.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/atomic.inline.hpp"
-HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) {
-
+inline HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) {
HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes);
if (res == NULL) {
return NULL;
@@ -41,4 +42,20 @@
return allocate(word_sz);
}
+void PLABStats::add_allocated(size_t v) {
+ Atomic::add_ptr(v, &_allocated);
+}
+
+void PLABStats::add_unused(size_t v) {
+ Atomic::add_ptr(v, &_unused);
+}
+
+void PLABStats::add_wasted(size_t v) {
+ Atomic::add_ptr(v, &_wasted);
+}
+
+void PLABStats::add_undo_wasted(size_t v) {
+ Atomic::add_ptr(v, &_undo_wasted);
+}
+
#endif // SHARE_VM_GC_SHARED_PLAB_INLINE_HPP
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/memory/universe.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -77,7 +77,7 @@
#if INCLUDE_ALL_GCS
#include "gc/cms/cmsCollectorPolicy.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1CollectorPolicy_ext.hpp"
+#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
#endif // INCLUDE_ALL_GCS
@@ -694,13 +694,29 @@
return JNI_OK;
}
-template <class Heap, class Policy>
-jint Universe::create_heap() {
+CollectedHeap* Universe::create_heap() {
assert(_collectedHeap == NULL, "Heap already created");
- Policy* policy = new Policy();
- policy->initialize_all();
- _collectedHeap = new Heap(policy);
- return _collectedHeap->initialize();
+#if !INCLUDE_ALL_GCS
+ if (UseParallelGC) {
+ fatal("UseParallelGC not supported in this VM.");
+ } else if (UseG1GC) {
+ fatal("UseG1GC not supported in this VM.");
+ } else if (UseConcMarkSweepGC) {
+ fatal("UseConcMarkSweepGC not supported in this VM.");
+#else
+ if (UseParallelGC) {
+ return Universe::create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
+ } else if (UseG1GC) {
+ return Universe::create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
+ } else if (UseConcMarkSweepGC) {
+ return Universe::create_heap_with_policy<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
+#endif
+ } else if (UseSerialGC) {
+ return Universe::create_heap_with_policy<GenCollectedHeap, MarkSweepPolicy>();
+ }
+
+ ShouldNotReachHere();
+ return NULL;
}
// Choose the heap base address and oop encoding mode
@@ -714,27 +730,12 @@
jint Universe::initialize_heap() {
jint status = JNI_ERR;
-#if !INCLUDE_ALL_GCS
- if (UseParallelGC) {
- fatal("UseParallelGC not supported in this VM.");
- } else if (UseG1GC) {
- fatal("UseG1GC not supported in this VM.");
- } else if (UseConcMarkSweepGC) {
- fatal("UseConcMarkSweepGC not supported in this VM.");
-#else
- if (UseParallelGC) {
- status = Universe::create_heap<ParallelScavengeHeap, GenerationSizer>();
- } else if (UseG1GC) {
- status = Universe::create_heap<G1CollectedHeap, G1CollectorPolicyExt>();
- } else if (UseConcMarkSweepGC) {
- status = Universe::create_heap<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
-#endif
- } else if (UseSerialGC) {
- status = Universe::create_heap<GenCollectedHeap, MarkSweepPolicy>();
- } else {
- ShouldNotReachHere();
+ _collectedHeap = create_heap_ext();
+ if (_collectedHeap == NULL) {
+ _collectedHeap = create_heap();
}
+ status = _collectedHeap->initialize();
if (status != JNI_OK) {
return status;
}
--- a/hotspot/src/share/vm/memory/universe.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/memory/universe.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -214,7 +214,9 @@
static size_t _heap_capacity_at_last_gc;
static size_t _heap_used_at_last_gc;
- template <class Heap, class Policy> static jint create_heap();
+ template <class Heap, class Policy> static CollectedHeap* create_heap_with_policy();
+ static CollectedHeap* create_heap();
+ static CollectedHeap* create_heap_ext();
static jint initialize_heap();
static void initialize_basic_type_mirrors(TRAPS);
static void fixup_mirrors(TRAPS);
--- a/hotspot/src/share/vm/memory/universe.inline.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/memory/universe.inline.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -49,4 +49,11 @@
_allocation_context_notification_obj = obj;
}
+template <class Heap, class Policy>
+CollectedHeap* Universe::create_heap_with_policy() {
+ Policy* policy = new Policy();
+ policy->initialize_all();
+ return new Heap(policy);
+}
+
#endif // SHARE_VM_MEMORY_UNIVERSE_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/memory/universe_ext.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/universe.hpp"
+
+CollectedHeap* Universe::create_heap_ext() {
+ return NULL;
+}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -81,8 +81,6 @@
bool Arguments::_has_profile = false;
size_t Arguments::_conservative_max_heap_alignment = 0;
size_t Arguments::_min_heap_size = 0;
-uintx Arguments::_min_heap_free_ratio = 0;
-uintx Arguments::_max_heap_free_ratio = 0;
Arguments::Mode Arguments::_mode = _mixed;
bool Arguments::_java_compiler = false;
bool Arguments::_xdebug_mode = false;
@@ -1614,11 +1612,9 @@
// unless the user actually sets these flags.
if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
FLAG_SET_DEFAULT(MinHeapFreeRatio, 0);
- _min_heap_free_ratio = MinHeapFreeRatio;
}
if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) {
FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100);
- _max_heap_free_ratio = MaxHeapFreeRatio;
}
}
@@ -3978,15 +3974,6 @@
return JNI_OK;
}
-// Any custom code post the 'CommandLineFlagConstraint::AfterErgo' constraint check
-// can be done here. We pass a flag that specifies whether
-// the check passed successfully
-void Arguments::post_after_ergo_constraint_check(bool check_passed) {
- // This does not set the flag itself, but stores the value in a safe place for later usage.
- _min_heap_free_ratio = MinHeapFreeRatio;
- _max_heap_free_ratio = MaxHeapFreeRatio;
-}
-
int Arguments::PropertyList_count(SystemProperty* pl) {
int count = 0;
while(pl != NULL) {
--- a/hotspot/src/share/vm/runtime/arguments.hpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Thu Aug 20 17:36:00 2015 +0200
@@ -288,10 +288,6 @@
static uintx _min_heap_size;
- // Used to store original flag values
- static uintx _min_heap_free_ratio;
- static uintx _max_heap_free_ratio;
-
// -Xrun arguments
static AgentLibraryList _libraryList;
static void add_init_library(const char* name, char* options)
@@ -463,8 +459,6 @@
static jint apply_ergo();
// Adjusts the arguments after the OS have adjusted the arguments
static jint adjust_after_os();
- // Set any arguments that need to be set after the 'CommandLineFlagConstraint::AfterErgo' constraint check
- static void post_after_ergo_constraint_check(bool check_passed);
static void set_gc_specific_flags();
static inline bool gc_selected(); // whether a gc has been selected
@@ -526,10 +520,6 @@
static size_t min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(size_t v) { _min_heap_size = v; }
- // Returns the original values of -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio
- static uintx min_heap_free_ratio() { return _min_heap_free_ratio; }
- static uintx max_heap_free_ratio() { return _max_heap_free_ratio; }
-
// -Xrun
static AgentLibrary* libraries() { return _libraryList.first(); }
static bool init_libraries_at_startup() { return !_libraryList.is_empty(); }
--- a/hotspot/src/share/vm/runtime/globals.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/runtime/globals.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -310,13 +310,17 @@
void Flag::get_locked_message(char* buf, int buflen) const {
buf[0] = '\0';
if (is_diagnostic() && !is_unlocked()) {
- jio_snprintf(buf, buflen, "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n",
- _name);
+ jio_snprintf(buf, buflen,
+ "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n"
+ "Error: The unlock option must precede '%s'.\n",
+ _name, _name);
return;
}
if (is_experimental() && !is_unlocked()) {
- jio_snprintf(buf, buflen, "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n",
- _name);
+ jio_snprintf(buf, buflen,
+ "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n"
+ "Error: The unlock option must precede '%s'.\n",
+ _name, _name);
return;
}
if (is_develop() && is_product_build()) {
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Aug 20 17:36:00 2015 +0200
@@ -3331,7 +3331,6 @@
// Final check of all 'AfterErgo' constraints after ergonomics which may change values.
bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo);
- Arguments::post_after_ergo_constraint_check(constraint_result);
if (!constraint_result) {
return JNI_EINVAL;
}
--- a/hotspot/test/compiler/arguments/CheckCICompilerCount.java Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/test/compiler/arguments/CheckCICompilerCount.java Thu Aug 20 17:36:00 2015 +0200
@@ -68,7 +68,7 @@
private static final String[][] NON_TIERED_EXPECTED_OUTPUTS = {
{
- "CICompilerCount=0 must be at least 1",
+ "CICompilerCount (0) must be at least 1",
"Improperly specified VM option 'CICompilerCount=0'"
},
{
@@ -123,7 +123,7 @@
private static final String[][] TIERED_EXPECTED_OUTPUTS = {
{
- "CICompilerCount=1 must be at least 2",
+ "CICompilerCount (1) must be at least 2",
"Improperly specified VM option 'CICompilerCount=1'"
},
{
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Thu Aug 20 11:18:51 2015 -0400
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Thu Aug 20 17:36:00 2015 +0200
@@ -28,7 +28,6 @@
* when their age exceeded tenuring threshold are not aligned to
* SurvivorAlignmentInBytes value.
* @library /testlibrary /../../test/lib
- * @ignore 8130308
* @modules java.base/sun.misc
* java.management
* @build TestPromotionFromSurvivorToTenuredAfterMinorGC
@@ -99,11 +98,18 @@
.getActualMemoryUsage();
test.allocate();
- for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD;
- i++) {
+ for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD; i++) {
SurvivorAlignmentTestMain.WHITE_BOX.youngGC();
}
+ // Sometimes we see that data unrelated to the test has been allocated during
+ // the loop. This data is included in the expectedMemoryUsage since we look
+ // through all threads to see what they allocated. If this data is still in
+ // the survivor area however, it should not be included in expectedMemoryUsage
+ // since the verification below only look at what's in tenured space.
+ expectedMemoryUsage -= SurvivorAlignmentTestMain.getAlignmentHelper(
+ SurvivorAlignmentTestMain.HeapSpace.SURVIVOR)
+ .getActualMemoryUsage();
test.verifyMemoryUsage(expectedMemoryUsage);
}
}