8146991: Introduce per-worker preserved mark stacks in ParallelGC

Reviewed-by: tschatzl, ysr
This commit is contained in:
Antonios Printezis 2016-03-09 09:45:47 +01:00
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/psScavenge.inline.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
@ -41,6 +42,7 @@
PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;
PreservedMarksSet* PSPromotionManager::_preserved_marks_set = NULL;
PSOldGen* PSPromotionManager::_old_gen = NULL;
MutableSpace* PSPromotionManager::_young_space = NULL;
@ -50,10 +52,12 @@ void PSPromotionManager::initialize() {
_old_gen = heap->old_gen();
_young_space = heap->young_gen()->to_space();
const uint promotion_manager_num = ParallelGCThreads + 1;
// To prevent false sharing, we pad the PSPromotionManagers
// and make sure that the first instance starts at a cache line.
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");
_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
@ -65,6 +69,14 @@ void PSPromotionManager::initialize() {
}
// The VMThread gets its own PSPromotionManager, which is not available
// 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
@ -90,6 +102,7 @@ PSPromotionManager* PSPromotionManager::vm_thread_promotion_manager() {
void PSPromotionManager::pre_scavenge() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
_preserved_marks_set->assert_empty();
_young_space = heap->young_gen()->to_space();
for(uint i=0; i<ParallelGCThreads+1; i++) {
@ -110,6 +123,11 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
}
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;
}
@ -187,6 +205,8 @@ PSPromotionManager::PSPromotionManager() {
// let's choose 1.5x the chunk size
_min_array_size_for_chunking = 3 * _array_chunk_size / 2;
_preserved_marks = NULL;
reset();
}
@ -211,6 +231,10 @@ void PSPromotionManager::reset() {
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) {
totally_drain = totally_drain || _totally_drain;
@ -422,8 +446,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {
push_contents(obj);
// Save the mark if needed
PSScavenge::oop_promotion_failed(obj, obj_mark);
_preserved_marks->push_if_necessary(obj, obj_mark);
} else {
// We lost, someone else "owns" this object
guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");

@ -28,6 +28,7 @@
#include "gc/parallel/psPromotionLAB.hpp"
#include "gc/shared/copyFailedInfo.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/preservedMarks.hpp"
#include "gc/shared/taskqueue.hpp"
#include "memory/allocation.hpp"
#include "memory/padded.hpp"
@ -55,6 +56,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
private:
static PaddedEnd<PSPromotionManager>* _manager_array;
static OopStarTaskQueueSet* _stack_array_depth;
static PreservedMarksSet* _preserved_marks_set;
static PSOldGen* _old_gen;
static MutableSpace* _young_space;
@ -84,6 +86,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
uint _array_chunk_size;
uint _min_array_size_for_chunking;
PreservedMarks* _preserved_marks;
PromotionFailedInfo _promotion_failed_info;
// Accessors
@ -176,6 +179,8 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC {
oop oop_promotion_failed(oop obj, markOop obj_mark);
void reset();
void register_preserved_marks(PreservedMarks* preserved_marks);
static void restore_preserved_marks() { _preserved_marks_set->restore(); }
void flush_labs();
void drain_stacks(bool totally_drain) {

@ -68,8 +68,6 @@ uintptr_t PSScavenge::_young_generation_boundary_compressed = 0
elapsedTimer PSScavenge::_accumulated_time;
STWGCTimer PSScavenge::_gc_timer;
ParallelScavengeTracer PSScavenge::_gc_tracer;
Stack<markOop, mtGC> PSScavenge::_preserved_mark_stack;
Stack<oop, mtGC> PSScavenge::_preserved_oop_stack;
CollectorCounters* PSScavenge::_counters = NULL;
// 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 {
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
ProcessTask & _rp_task;
@ -257,9 +247,6 @@ bool PSScavenge::invoke_no_policy() {
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
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();
TimeStamp scavenge_entry;
@ -656,52 +643,20 @@ bool PSScavenge::invoke_no_policy() {
}
// This method iterates over all objects in the young generation,
// unforwarding markOops. It then restores any preserved mark oops,
// and clears the _preserved_mark_stack.
// removing all forwarding references. It then restores any preserved marks.
void PSScavenge::clean_up_failed_promotion() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSYoungGen* young_gen = heap->young_gen();
{
ResourceMark rm;
RemoveForwardedPointerClosure remove_fwd_ptr_closure;
young_gen->object_iterate(&remove_fwd_ptr_closure);
// Unforward all pointers in the young gen.
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);
}
PSPromotionManager::restore_preserved_marks();
// Reset the PromotionFailureALot counters.
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() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters();

@ -79,8 +79,6 @@ class PSScavenge: AllStatic {
static HeapWord* _young_generation_boundary;
// Used to optimize compressed oops young gen boundary checking.
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 void clean_up_failed_promotion();
@ -127,9 +125,6 @@ class PSScavenge: AllStatic {
// Return true if a collection was done; false otherwise.
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);
// 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() {
size_t total_size = 0;
for (uint i = 0; i < _num; i += 1) {
total_size += get(i)->size();
get(i)->restore();
}
assert_empty();
log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size);
}
void PreservedMarksSet::reclaim() {

@ -53,6 +53,7 @@ private:
public:
bool is_empty() const { return _stack.is_empty(); }
size_t size() const { return _stack.size(); }
inline void push_if_necessary(oop obj, markOop m);
// Iterate over the stack, restore the preserved marks, then reclaim
// the memory taken up by stack chunks.
@ -65,7 +66,7 @@ public:
virtual void do_object(oop obj);
};
class PreservedMarksSet VALUE_OBJ_CLASS_SPEC {
class PreservedMarksSet : public CHeapObj<mtGC> {
private:
// true -> _stacks will be allocated in the C heap
// false -> _stacks will be allocated in the resource arena