8135152: Create a G1ParScanThreadStateSet class for managing G1 GC per thread states
Reviewed-by: tschatzl, ehelin
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Sep 09 10:34:22 2015 +0200
@@ -4164,8 +4164,9 @@
// Initialize the GC alloc regions.
_allocator->init_gc_alloc_regions(evacuation_info);
+ G1ParScanThreadStateSet per_thread_states(this, workers()->active_workers());
// Actually do the work...
- evacuate_collection_set(evacuation_info);
+ evacuate_collection_set(evacuation_info, &per_thread_states);
free_collection_set(g1_policy()->collection_set(), evacuation_info);
@@ -4545,15 +4546,15 @@
class G1ParTask : public AbstractGangTask {
protected:
- G1CollectedHeap* _g1h;
- G1ParScanThreadState** _pss;
- RefToScanQueueSet* _queues;
- G1RootProcessor* _root_processor;
- ParallelTaskTerminator _terminator;
- uint _n_workers;
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadStateSet* _pss;
+ RefToScanQueueSet* _queues;
+ G1RootProcessor* _root_processor;
+ ParallelTaskTerminator _terminator;
+ uint _n_workers;
public:
- G1ParTask(G1CollectedHeap* g1h, G1ParScanThreadState** per_thread_states, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers)
+ G1ParTask(G1CollectedHeap* g1h, G1ParScanThreadStateSet* per_thread_states, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers)
: AbstractGangTask("G1 collection"),
_g1h(g1h),
_pss(per_thread_states),
@@ -4611,7 +4612,7 @@
ReferenceProcessor* rp = _g1h->ref_processor_stw();
- G1ParScanThreadState* pss = _pss[worker_id];
+ G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
pss->set_ref_processor(rp);
bool only_young = _g1h->collector_state()->gcs_are_young();
@@ -5267,15 +5268,15 @@
class G1STWRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
private:
- G1CollectedHeap* _g1h;
- G1ParScanThreadState** _pss;
- RefToScanQueueSet* _queues;
- WorkGang* _workers;
- uint _active_workers;
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadStateSet* _pss;
+ RefToScanQueueSet* _queues;
+ WorkGang* _workers;
+ uint _active_workers;
public:
G1STWRefProcTaskExecutor(G1CollectedHeap* g1h,
- G1ParScanThreadState** per_thread_states,
+ G1ParScanThreadStateSet* per_thread_states,
WorkGang* workers,
RefToScanQueueSet *task_queues,
uint n_workers) :
@@ -5299,14 +5300,14 @@
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
ProcessTask& _proc_task;
G1CollectedHeap* _g1h;
- G1ParScanThreadState** _pss;
+ G1ParScanThreadStateSet* _pss;
RefToScanQueueSet* _task_queues;
ParallelTaskTerminator* _terminator;
public:
G1STWRefProcTaskProxy(ProcessTask& proc_task,
G1CollectedHeap* g1h,
- G1ParScanThreadState** per_thread_states,
+ G1ParScanThreadStateSet* per_thread_states,
RefToScanQueueSet *task_queues,
ParallelTaskTerminator* terminator) :
AbstractGangTask("Process reference objects in parallel"),
@@ -5324,7 +5325,7 @@
G1STWIsAliveClosure is_alive(_g1h);
- G1ParScanThreadState* pss = _pss[worker_id];
+ G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
pss->set_ref_processor(NULL);
G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, pss);
@@ -5403,14 +5404,14 @@
class G1ParPreserveCMReferentsTask: public AbstractGangTask {
protected:
- G1CollectedHeap* _g1h;
- G1ParScanThreadState** _pss;
- RefToScanQueueSet* _queues;
- ParallelTaskTerminator _terminator;
- uint _n_workers;
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadStateSet* _pss;
+ RefToScanQueueSet* _queues;
+ ParallelTaskTerminator _terminator;
+ uint _n_workers;
public:
- G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h, G1ParScanThreadState** per_thread_states, int workers, RefToScanQueueSet *task_queues) :
+ G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h, G1ParScanThreadStateSet* per_thread_states, int workers, RefToScanQueueSet *task_queues) :
AbstractGangTask("ParPreserveCMReferents"),
_g1h(g1h),
_pss(per_thread_states),
@@ -5423,7 +5424,7 @@
ResourceMark rm;
HandleMark hm;
- G1ParScanThreadState* pss = _pss[worker_id];
+ G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
pss->set_ref_processor(NULL);
assert(pss->queue_is_empty(), "both queue and overflow should be empty");
@@ -5484,7 +5485,7 @@
};
// Weak Reference processing during an evacuation pause (part 1).
-void G1CollectedHeap::process_discovered_references(G1ParScanThreadState** per_thread_states) {
+void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) {
double ref_proc_start = os::elapsedTime();
ReferenceProcessor* rp = _ref_processor_stw;
@@ -5529,7 +5530,7 @@
// JNI refs.
// Use only a single queue for this PSS.
- G1ParScanThreadState* pss = per_thread_states[0];
+ G1ParScanThreadState* pss = per_thread_states->state_for_worker(0);
pss->set_ref_processor(NULL);
assert(pss->queue_is_empty(), "pre-condition");
@@ -5590,7 +5591,7 @@
}
// Weak Reference processing during an evacuation pause (part 2).
-void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadState** per_thread_states) {
+void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadStateSet* per_thread_states) {
double ref_enq_start = os::elapsedTime();
ReferenceProcessor* rp = _ref_processor_stw;
@@ -5625,7 +5626,7 @@
g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0);
}
-void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
+void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) {
_expand_heap_after_alloc_failure = true;
_evacuation_failed = false;
@@ -5645,11 +5646,6 @@
double start_par_time_sec = os::elapsedTime();
double end_par_time_sec;
- G1ParScanThreadState** per_thread_states = NEW_C_HEAP_ARRAY(G1ParScanThreadState*, n_workers, mtGC);
- for (uint i = 0; i < n_workers; i++) {
- per_thread_states[i] = new_par_scan_state(i);
- }
-
{
G1RootProcessor root_processor(this, n_workers);
G1ParTask g1_par_task(this, per_thread_states, _task_queues, &root_processor, n_workers);
@@ -5703,11 +5699,7 @@
_allocator->release_gc_alloc_regions(evacuation_info);
g1_rem_set()->cleanup_after_oops_into_collection_set_do();
- for (uint i = 0; i < n_workers; i++) {
- G1ParScanThreadState* pss = per_thread_states[i];
- delete pss;
- }
- FREE_C_HEAP_ARRAY(G1ParScanThreadState*, per_thread_states);
+ per_thread_states->flush();
record_obj_copy_mem_stats();
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Sep 09 10:34:22 2015 +0200
@@ -56,6 +56,7 @@
class GenerationSpec;
class OopsInHeapRegionClosure;
class G1ParScanThreadState;
+class G1ParScanThreadStateSet;
class G1KlassScanClosure;
class G1ParScanThreadState;
class ObjectClosure;
@@ -192,6 +193,7 @@
// Closures used in implementation.
friend class G1ParScanThreadState;
+ friend class G1ParScanThreadStateSet;
friend class G1ParTask;
friend class G1PLABAllocator;
friend class G1PrepareCompactClosure;
@@ -584,11 +586,11 @@
// Process any reference objects discovered during
// an incremental evacuation pause.
- void process_discovered_references(G1ParScanThreadState** per_thread_states);
+ void process_discovered_references(G1ParScanThreadStateSet* per_thread_states);
// Enqueue any remaining discovered references
// after processing.
- void enqueue_discovered_references(G1ParScanThreadState** per_thread_states);
+ void enqueue_discovered_references(G1ParScanThreadStateSet* per_thread_states);
public:
WorkGang* workers() const { return _workers; }
@@ -683,9 +685,6 @@
// Allocates a new heap region instance.
HeapRegion* new_heap_region(uint hrs_index, MemRegion mr);
- // Allocates a new per thread par scan state for the given thread id.
- G1ParScanThreadState* new_par_scan_state(uint worker_id);
-
// Allocate the highest free region in the reserved heap. This will commit
// regions as necessary.
HeapRegion* alloc_highest_free_region();
@@ -799,7 +798,7 @@
bool do_collection_pause_at_safepoint(double target_pause_time_ms);
// Actually do the work of evacuating the collection set.
- void evacuate_collection_set(EvacuationInfo& evacuation_info);
+ void evacuate_collection_set(EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states);
// Print the header for the per-thread termination statistics.
static void print_termination_stats_hdr(outputStream* const st);
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp Wed Sep 09 10:34:22 2015 +0200
@@ -38,7 +38,3 @@
MemRegion mr) {
return new HeapRegion(hrs_index, bot_shared(), mr);
}
-
-G1ParScanThreadState* G1CollectedHeap::new_par_scan_state(uint worker_id) {
- return new G1ParScanThreadState(this, worker_id);
-}
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Sep 09 10:34:22 2015 +0200
@@ -865,8 +865,8 @@
return _recorded_survivor_regions;
}
- void record_thread_age_table(ageTable* age_table) {
- _survivors_age_table.merge_par(age_table);
+ void record_age_table(ageTable* age_table) {
+ _survivors_age_table.merge(age_table);
}
void update_max_gc_locker_expansion();
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Wed Sep 09 10:34:22 2015 +0200
@@ -71,11 +71,16 @@
_dest[InCSetState::Old] = InCSetState::Old;
}
-G1ParScanThreadState::~G1ParScanThreadState() {
+// Pass locally gathered statistics to global state.
+void G1ParScanThreadState::flush() {
+ _dcq.flush();
// Update allocation statistics.
_plab_allocator->flush_and_retire_stats();
+ _g1h->g1_policy()->record_age_table(&_age_table);
+}
+
+G1ParScanThreadState::~G1ParScanThreadState() {
delete _plab_allocator;
- _g1h->g1_policy()->record_thread_age_table(&_age_table);
// Update heap statistics.
_g1h->update_surviving_young_words(_surviving_young_words);
FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base);
@@ -314,6 +319,25 @@
}
}
+G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) {
+ assert(worker_id < _n_workers, "out of bounds access");
+ return _states[worker_id];
+}
+
+void G1ParScanThreadStateSet::flush() {
+ assert(!_flushed, "thread local state from the per thread states should be flushed once");
+
+ for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) {
+ G1ParScanThreadState* pss = _states[worker_index];
+
+ pss->flush();
+
+ delete pss;
+ _states[worker_index] = NULL;
+ }
+ _flushed = true;
+}
+
oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) {
assert(_g1h->obj_in_cs(old),
err_msg("Object " PTR_FORMAT " should be in the CSet", p2i(old)));
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Wed Sep 09 10:34:22 2015 +0200
@@ -121,6 +121,8 @@
return _surviving_young_words + 1;
}
+ void flush();
+
private:
#define G1_PARTIAL_ARRAY_MASK 0x2
@@ -189,4 +191,34 @@
oop handle_evacuation_failure_par(oop obj, markOop m);
};
+class G1ParScanThreadStateSet : public StackObj {
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadState** _states;
+ uint _n_workers;
+ bool _flushed;
+
+ public:
+ G1ParScanThreadStateSet(G1CollectedHeap* g1h, uint n_workers) :
+ _g1h(g1h),
+ _states(NEW_C_HEAP_ARRAY(G1ParScanThreadState*, n_workers, mtGC)),
+ _n_workers(n_workers),
+ _flushed(false) {
+ for (uint i = 0; i < n_workers; ++i) {
+ _states[i] = new_par_scan_state(i);
+ }
+ }
+
+ ~G1ParScanThreadStateSet() {
+ assert(_flushed, "thread local state from the per thread states should have been flushed");
+ FREE_C_HEAP_ARRAY(G1ParScanThreadState*, _states);
+ }
+
+ void flush();
+
+ G1ParScanThreadState* state_for_worker(uint worker_id);
+
+ private:
+ G1ParScanThreadState* new_par_scan_state(uint worker_id);
+};
+
#endif // SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp Wed Sep 09 10:34:22 2015 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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/g1ParScanThreadState.hpp"
+
+G1ParScanThreadState* G1ParScanThreadStateSet::new_par_scan_state(uint worker_id) {
+ return new G1ParScanThreadState(_g1h, worker_id);
+}
--- a/hotspot/src/share/vm/gc/shared/ageTable.cpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp Wed Sep 09 10:34:22 2015 +0200
@@ -28,7 +28,6 @@
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
#include "memory/resourceArea.hpp"
-#include "runtime/atomic.inline.hpp"
#include "utilities/copy.hpp"
/* Copyright (c) 1992, 2015, Oracle and/or its affiliates, and Stanford University.
@@ -73,12 +72,6 @@
}
}
-void ageTable::merge_par(ageTable* subTable) {
- for (int i = 0; i < table_size; i++) {
- Atomic::add_ptr(subTable->sizes[i], &sizes[i]);
- }
-}
-
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters) {
size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
uint result;
--- a/hotspot/src/share/vm/gc/shared/ageTable.hpp Tue Sep 08 16:00:34 2015 -0400
+++ b/hotspot/src/share/vm/gc/shared/ageTable.hpp Wed Sep 09 10:34:22 2015 +0200
@@ -68,7 +68,6 @@
// Merge another age table with the current one. Used
// for parallel young generation gc.
void merge(ageTable* subTable);
- void merge_par(ageTable* subTable);
// calculate new tenuring threshold based on age information
uint compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters);