8135152: Create a G1ParScanThreadStateSet class for managing G1 GC per thread states

Reviewed-by: tschatzl, ehelin
This commit is contained in:
Mikael Gerdin 2015-09-09 10:34:22 +02:00
parent 802664728f
commit 2dbd4dd578
9 changed files with 127 additions and 61 deletions

View File

@ -4164,8 +4164,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// 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 G1KlassScanClosure : public KlassClosure {
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 @@ public:
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 @@ public:
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 @@ class G1STWRefProcTaskProxy: public AbstractGangTask {
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 @@ public:
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 @@ void G1STWRefProcTaskExecutor::execute(EnqueueTask& enq_task) {
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 @@ public:
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 @@ public:
};
// 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 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadState** per_t
// 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 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadState** per_t
}
// 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 @@ void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadState** per_t
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 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
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 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
_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();

View File

@ -56,6 +56,7 @@ class HRRSCleanupTask;
class GenerationSpec;
class OopsInHeapRegionClosure;
class G1ParScanThreadState;
class G1ParScanThreadStateSet;
class G1KlassScanClosure;
class G1ParScanThreadState;
class ObjectClosure;
@ -192,6 +193,7 @@ class G1CollectedHeap : public CollectedHeap {
// Closures used in implementation.
friend class G1ParScanThreadState;
friend class G1ParScanThreadStateSet;
friend class G1ParTask;
friend class G1PLABAllocator;
friend class G1PrepareCompactClosure;
@ -584,11 +586,11 @@ protected:
// 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 @@ public:
// 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 @@ protected:
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);

View File

@ -38,7 +38,3 @@ HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index,
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);
}

View File

@ -865,8 +865,8 @@ public:
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();

View File

@ -71,11 +71,16 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id)
_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 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
}
}
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)));

View File

@ -121,6 +121,8 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
return _surviving_young_words + 1;
}
void flush();
private:
#define G1_PARTIAL_ARRAY_MASK 0x2
@ -189,4 +191,34 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
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

View File

@ -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);
}

View File

@ -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(ageTable* subTable) {
}
}
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;

View File

@ -68,7 +68,6 @@ class ageTable VALUE_OBJ_CLASS_SPEC {
// 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);