mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 18:14:38 +02:00
8146991: Introduce per-worker preserved mark stacks in ParallelGC
Reviewed-by: tschatzl, ysr
This commit is contained in:
parent
22f2f6ff95
commit
00a657d109
6 changed files with 42 additions and 58 deletions
|
@ -29,6 +29,7 @@
|
||||||
#include "gc/parallel/psPromotionManager.inline.hpp"
|
#include "gc/parallel/psPromotionManager.inline.hpp"
|
||||||
#include "gc/parallel/psScavenge.inline.hpp"
|
#include "gc/parallel/psScavenge.inline.hpp"
|
||||||
#include "gc/shared/gcTrace.hpp"
|
#include "gc/shared/gcTrace.hpp"
|
||||||
|
#include "gc/shared/preservedMarks.inline.hpp"
|
||||||
#include "gc/shared/taskqueue.inline.hpp"
|
#include "gc/shared/taskqueue.inline.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
|
|
||||||
PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
|
PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
|
||||||
OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;
|
OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;
|
||||||
|
PreservedMarksSet* PSPromotionManager::_preserved_marks_set = NULL;
|
||||||
PSOldGen* PSPromotionManager::_old_gen = NULL;
|
PSOldGen* PSPromotionManager::_old_gen = NULL;
|
||||||
MutableSpace* PSPromotionManager::_young_space = NULL;
|
MutableSpace* PSPromotionManager::_young_space = NULL;
|
||||||
|
|
||||||
|
@ -50,10 +52,12 @@ void PSPromotionManager::initialize() {
|
||||||
_old_gen = heap->old_gen();
|
_old_gen = heap->old_gen();
|
||||||
_young_space = heap->young_gen()->to_space();
|
_young_space = heap->young_gen()->to_space();
|
||||||
|
|
||||||
|
const uint promotion_manager_num = ParallelGCThreads + 1;
|
||||||
|
|
||||||
// To prevent false sharing, we pad the PSPromotionManagers
|
// To prevent false sharing, we pad the PSPromotionManagers
|
||||||
// and make sure that the first instance starts at a cache line.
|
// and make sure that the first instance starts at a cache line.
|
||||||
assert(_manager_array == NULL, "Attempt to initialize twice");
|
assert(_manager_array == NULL, "Attempt to initialize twice");
|
||||||
_manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(ParallelGCThreads + 1);
|
_manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(promotion_manager_num);
|
||||||
guarantee(_manager_array != NULL, "Could not initialize promotion manager");
|
guarantee(_manager_array != NULL, "Could not initialize promotion manager");
|
||||||
|
|
||||||
_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
|
_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
|
||||||
|
@ -65,6 +69,14 @@ void PSPromotionManager::initialize() {
|
||||||
}
|
}
|
||||||
// The VMThread gets its own PSPromotionManager, which is not available
|
// The VMThread gets its own PSPromotionManager, which is not available
|
||||||
// for work stealing.
|
// for work stealing.
|
||||||
|
|
||||||
|
assert(_preserved_marks_set == NULL, "Attempt to initialize twice");
|
||||||
|
_preserved_marks_set = new PreservedMarksSet(true /* in_c_heap */);
|
||||||
|
guarantee(_preserved_marks_set != NULL, "Could not initialize preserved marks set");
|
||||||
|
_preserved_marks_set->init(promotion_manager_num);
|
||||||
|
for (uint i = 0; i < promotion_manager_num; i += 1) {
|
||||||
|
_manager_array[i].register_preserved_marks(_preserved_marks_set->get(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions to get around the circular dependency between
|
// Helper functions to get around the circular dependency between
|
||||||
|
@ -90,6 +102,7 @@ PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() {
|
||||||
void PSPromotionManager::pre_scavenge() {
|
void PSPromotionManager::pre_scavenge() {
|
||||||
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
||||||
|
|
||||||
|
_preserved_marks_set->assert_empty();
|
||||||
_young_space = heap->young_gen()->to_space();
|
_young_space = heap->young_gen()->to_space();
|
||||||
|
|
||||||
for(uint i=0; i<ParallelGCThreads+1; i++) {
|
for(uint i=0; i<ParallelGCThreads+1; i++) {
|
||||||
|
@ -110,6 +123,11 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
|
||||||
}
|
}
|
||||||
manager->flush_labs();
|
manager->flush_labs();
|
||||||
}
|
}
|
||||||
|
if (!promotion_failure_occurred) {
|
||||||
|
// If there was no promotion failure, the preserved mark stacks
|
||||||
|
// should be empty.
|
||||||
|
_preserved_marks_set->assert_empty();
|
||||||
|
}
|
||||||
return promotion_failure_occurred;
|
return promotion_failure_occurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +205,8 @@ PSPromotionManager::PSPromotionManager() {
|
||||||
// let's choose 1.5x the chunk size
|
// let's choose 1.5x the chunk size
|
||||||
_min_array_size_for_chunking = 3 * _array_chunk_size / 2;
|
_min_array_size_for_chunking = 3 * _array_chunk_size / 2;
|
||||||
|
|
||||||
|
_preserved_marks = NULL;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +231,10 @@ void PSPromotionManager::reset() {
|
||||||
TASKQUEUE_STATS_ONLY(reset_stats());
|
TASKQUEUE_STATS_ONLY(reset_stats());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSPromotionManager::register_preserved_marks(PreservedMarks* preserved_marks) {
|
||||||
|
assert(_preserved_marks == NULL, "do not set it twice");
|
||||||
|
_preserved_marks = preserved_marks;
|
||||||
|
}
|
||||||
|
|
||||||
void PSPromotionManager::drain_stacks_depth(bool totally_drain) {
|
void PSPromotionManager::drain_stacks_depth(bool totally_drain) {
|
||||||
totally_drain = totally_drain || _totally_drain;
|
totally_drain = totally_drain || _totally_drain;
|
||||||
|
@ -422,8 +446,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {
|
||||||
|
|
||||||
push_contents(obj);
|
push_contents(obj);
|
||||||
|
|
||||||
// Save the mark if needed
|
_preserved_marks->push_if_necessary(obj, obj_mark);
|
||||||
PSScavenge::oop_promotion_failed(obj, obj_mark);
|
|
||||||
} else {
|
} else {
|
||||||
// We lost, someone else "owns" this object
|
// We lost, someone else "owns" this object
|
||||||
guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");
|
guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "gc/parallel/psPromotionLAB.hpp"
|
#include "gc/parallel/psPromotionLAB.hpp"
|
||||||
#include "gc/shared/copyFailedInfo.hpp"
|
#include "gc/shared/copyFailedInfo.hpp"
|
||||||
#include "gc/shared/gcTrace.hpp"
|
#include "gc/shared/gcTrace.hpp"
|
||||||
|
#include "gc/shared/preservedMarks.hpp"
|
||||||
#include "gc/shared/taskqueue.hpp"
|
#include "gc/shared/taskqueue.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/padded.hpp"
|
#include "memory/padded.hpp"
|
||||||
|
@ -55,6 +56,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
|
||||||
private:
|
private:
|
||||||
static PaddedEnd<PSPromotionManager>* _manager_array;
|
static PaddedEnd<PSPromotionManager>* _manager_array;
|
||||||
static OopStarTaskQueueSet* _stack_array_depth;
|
static OopStarTaskQueueSet* _stack_array_depth;
|
||||||
|
static PreservedMarksSet* _preserved_marks_set;
|
||||||
static PSOldGen* _old_gen;
|
static PSOldGen* _old_gen;
|
||||||
static MutableSpace* _young_space;
|
static MutableSpace* _young_space;
|
||||||
|
|
||||||
|
@ -84,6 +86,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
|
||||||
uint _array_chunk_size;
|
uint _array_chunk_size;
|
||||||
uint _min_array_size_for_chunking;
|
uint _min_array_size_for_chunking;
|
||||||
|
|
||||||
|
PreservedMarks* _preserved_marks;
|
||||||
PromotionFailedInfo _promotion_failed_info;
|
PromotionFailedInfo _promotion_failed_info;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
@ -176,6 +179,8 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
|
||||||
oop oop_promotion_failed(oop obj, markOop obj_mark);
|
oop oop_promotion_failed(oop obj, markOop obj_mark);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
void register_preserved_marks(PreservedMarks* preserved_marks);
|
||||||
|
static void restore_preserved_marks() { _preserved_marks_set->restore(); }
|
||||||
|
|
||||||
void flush_labs();
|
void flush_labs();
|
||||||
void drain_stacks(bool totally_drain) {
|
void drain_stacks(bool totally_drain) {
|
||||||
|
|
|
@ -68,8 +68,6 @@ uintptr_t PSScavenge::_young_generation_boundary_compressed = 0
|
||||||
elapsedTimer PSScavenge::_accumulated_time;
|
elapsedTimer PSScavenge::_accumulated_time;
|
||||||
STWGCTimer PSScavenge::_gc_timer;
|
STWGCTimer PSScavenge::_gc_timer;
|
||||||
ParallelScavengeTracer PSScavenge::_gc_tracer;
|
ParallelScavengeTracer PSScavenge::_gc_tracer;
|
||||||
Stack<markOop, mtGC> PSScavenge::_preserved_mark_stack;
|
|
||||||
Stack<oop, mtGC> PSScavenge::_preserved_oop_stack;
|
|
||||||
CollectorCounters* PSScavenge::_counters = NULL;
|
CollectorCounters* PSScavenge::_counters = NULL;
|
||||||
|
|
||||||
// Define before use
|
// Define before use
|
||||||
|
@ -123,14 +121,6 @@ class PSEvacuateFollowersClosure: public VoidClosure {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PSPromotionFailedClosure : public ObjectClosure {
|
|
||||||
virtual void do_object(oop obj) {
|
|
||||||
if (obj->is_forwarded()) {
|
|
||||||
obj->init_mark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PSRefProcTaskProxy: public GCTask {
|
class PSRefProcTaskProxy: public GCTask {
|
||||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||||
ProcessTask & _rp_task;
|
ProcessTask & _rp_task;
|
||||||
|
@ -257,9 +247,6 @@ bool PSScavenge::invoke_no_policy() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
|
||||||
assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
|
assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
|
||||||
|
|
||||||
assert(_preserved_mark_stack.is_empty(), "should be empty");
|
|
||||||
assert(_preserved_oop_stack.is_empty(), "should be empty");
|
|
||||||
|
|
||||||
_gc_timer.register_gc_start();
|
_gc_timer.register_gc_start();
|
||||||
|
|
||||||
TimeStamp scavenge_entry;
|
TimeStamp scavenge_entry;
|
||||||
|
@ -656,52 +643,20 @@ bool PSScavenge::invoke_no_policy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method iterates over all objects in the young generation,
|
// This method iterates over all objects in the young generation,
|
||||||
// unforwarding markOops. It then restores any preserved mark oops,
|
// removing all forwarding references. It then restores any preserved marks.
|
||||||
// and clears the _preserved_mark_stack.
|
|
||||||
void PSScavenge::clean_up_failed_promotion() {
|
void PSScavenge::clean_up_failed_promotion() {
|
||||||
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
||||||
PSYoungGen* young_gen = heap->young_gen();
|
PSYoungGen* young_gen = heap->young_gen();
|
||||||
|
|
||||||
{
|
RemoveForwardedPointerClosure remove_fwd_ptr_closure;
|
||||||
ResourceMark rm;
|
young_gen->object_iterate(&remove_fwd_ptr_closure);
|
||||||
|
|
||||||
// Unforward all pointers in the young gen.
|
PSPromotionManager::restore_preserved_marks();
|
||||||
PSPromotionFailedClosure unforward_closure;
|
|
||||||
young_gen->object_iterate(&unforward_closure);
|
|
||||||
|
|
||||||
log_trace(gc, ergo)("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size());
|
|
||||||
|
|
||||||
// Restore any saved marks.
|
|
||||||
while (!_preserved_oop_stack.is_empty()) {
|
|
||||||
oop obj = _preserved_oop_stack.pop();
|
|
||||||
markOop mark = _preserved_mark_stack.pop();
|
|
||||||
obj->set_mark(mark);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the preserved mark and oop stack caches.
|
|
||||||
_preserved_mark_stack.clear(true);
|
|
||||||
_preserved_oop_stack.clear(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the PromotionFailureALot counters.
|
// Reset the PromotionFailureALot counters.
|
||||||
NOT_PRODUCT(heap->reset_promotion_should_fail();)
|
NOT_PRODUCT(heap->reset_promotion_should_fail();)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called whenever an attempt to promote an object
|
|
||||||
// fails. Some markOops will need preservation, some will not. Note
|
|
||||||
// that the entire eden is traversed after a failed promotion, with
|
|
||||||
// all forwarded headers replaced by the default markOop. This means
|
|
||||||
// it is not necessary to preserve most markOops.
|
|
||||||
void PSScavenge::oop_promotion_failed(oop obj, markOop obj_mark) {
|
|
||||||
if (obj_mark->must_be_preserved_for_promotion_failure(obj)) {
|
|
||||||
// Should use per-worker private stacks here rather than
|
|
||||||
// locking a common pair of stacks.
|
|
||||||
ThreadCritical tc;
|
|
||||||
_preserved_oop_stack.push(obj);
|
|
||||||
_preserved_mark_stack.push(obj_mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PSScavenge::should_attempt_scavenge() {
|
bool PSScavenge::should_attempt_scavenge() {
|
||||||
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
||||||
PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters();
|
PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters();
|
||||||
|
|
|
@ -79,8 +79,6 @@ class PSScavenge: AllStatic {
|
||||||
static HeapWord* _young_generation_boundary;
|
static HeapWord* _young_generation_boundary;
|
||||||
// Used to optimize compressed oops young gen boundary checking.
|
// Used to optimize compressed oops young gen boundary checking.
|
||||||
static uintptr_t _young_generation_boundary_compressed;
|
static uintptr_t _young_generation_boundary_compressed;
|
||||||
static Stack<markOop, mtGC> _preserved_mark_stack; // List of marks to be restored after failed promotion
|
|
||||||
static Stack<oop, mtGC> _preserved_oop_stack; // List of oops that need their mark restored.
|
|
||||||
static CollectorCounters* _counters; // collector performance counters
|
static CollectorCounters* _counters; // collector performance counters
|
||||||
|
|
||||||
static void clean_up_failed_promotion();
|
static void clean_up_failed_promotion();
|
||||||
|
@ -127,9 +125,6 @@ class PSScavenge: AllStatic {
|
||||||
// Return true if a collection was done; false otherwise.
|
// Return true if a collection was done; false otherwise.
|
||||||
static bool invoke_no_policy();
|
static bool invoke_no_policy();
|
||||||
|
|
||||||
// If an attempt to promote fails, this method is invoked
|
|
||||||
static void oop_promotion_failed(oop obj, markOop obj_mark);
|
|
||||||
|
|
||||||
template <class T> static inline bool should_scavenge(T* p);
|
template <class T> static inline bool should_scavenge(T* p);
|
||||||
|
|
||||||
// These call should_scavenge() above and, if it returns true, also check that
|
// These call should_scavenge() above and, if it returns true, also check that
|
||||||
|
|
|
@ -62,9 +62,14 @@ void PreservedMarksSet::init(uint num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreservedMarksSet::restore() {
|
void PreservedMarksSet::restore() {
|
||||||
|
size_t total_size = 0;
|
||||||
for (uint i = 0; i < _num; i += 1) {
|
for (uint i = 0; i < _num; i += 1) {
|
||||||
|
total_size += get(i)->size();
|
||||||
get(i)->restore();
|
get(i)->restore();
|
||||||
}
|
}
|
||||||
|
assert_empty();
|
||||||
|
|
||||||
|
log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreservedMarksSet::reclaim() {
|
void PreservedMarksSet::reclaim() {
|
||||||
|
|
|
@ -53,6 +53,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool is_empty() const { return _stack.is_empty(); }
|
bool is_empty() const { return _stack.is_empty(); }
|
||||||
|
size_t size() const { return _stack.size(); }
|
||||||
inline void push_if_necessary(oop obj, markOop m);
|
inline void push_if_necessary(oop obj, markOop m);
|
||||||
// Iterate over the stack, restore the preserved marks, then reclaim
|
// Iterate over the stack, restore the preserved marks, then reclaim
|
||||||
// the memory taken up by stack chunks.
|
// the memory taken up by stack chunks.
|
||||||
|
@ -65,7 +66,7 @@ public:
|
||||||
virtual void do_object(oop obj);
|
virtual void do_object(oop obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreservedMarksSet VALUE_OBJ_CLASS_SPEC {
|
class PreservedMarksSet : public CHeapObj<mtGC> {
|
||||||
private:
|
private:
|
||||||
// true -> _stacks will be allocated in the C heap
|
// true -> _stacks will be allocated in the C heap
|
||||||
// false -> _stacks will be allocated in the resource arena
|
// false -> _stacks will be allocated in the resource arena
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue