8146991: Introduce per-worker preserved mark stacks in ParallelGC
Reviewed-by: tschatzl, ysr
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Wed Mar 09 09:45:47 2016 +0100
@@ -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 @@
_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 @@
}
// 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 @@
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 @@
}
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 @@
// 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 @@
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 @@
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.");
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Wed Mar 09 09:45:47 2016 +0100
@@ -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 @@
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 @@
uint _array_chunk_size;
uint _min_array_size_for_chunking;
+ PreservedMarks* _preserved_marks;
PromotionFailedInfo _promotion_failed_info;
// Accessors
@@ -176,6 +179,8 @@
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) {
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Wed Mar 09 09:45:47 2016 +0100
@@ -68,8 +68,6 @@
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 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 @@
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 @@
}
// 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;
-
- // 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());
+ RemoveForwardedPointerClosure remove_fwd_ptr_closure;
+ young_gen->object_iterate(&remove_fwd_ptr_closure);
- // 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();
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Wed Mar 09 09:45:47 2016 +0100
@@ -79,8 +79,6 @@
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 @@
// 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
--- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Wed Mar 09 09:45:47 2016 +0100
@@ -62,9 +62,14 @@
}
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() {
--- a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp Tue Mar 08 15:19:53 2016 -0500
+++ b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp Wed Mar 09 09:45:47 2016 +0100
@@ -53,6 +53,7 @@
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 @@
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