diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index ffa778af3ba..b3d29bdc53f 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -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(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index c554d7582ac..fcdc7146fb9 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -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); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp index f05668e685a..0c04c106aad 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp @@ -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); -} diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index 1ed47e6d6e2..27a7779b63c 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -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(); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index ef87c3666a5..660cfa76289 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -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))); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index ee97257a516..31f4e1eb793 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -121,6 +121,8 @@ class G1ParScanThreadState : public CHeapObj { return _surviving_young_words + 1; } + void flush(); + private: #define G1_PARTIAL_ARRAY_MASK 0x2 @@ -189,4 +191,34 @@ class G1ParScanThreadState : public CHeapObj { 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 diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp new file mode 100644 index 00000000000..b63c07c260b --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp @@ -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); +} diff --git a/hotspot/src/share/vm/gc/shared/ageTable.cpp b/hotspot/src/share/vm/gc/shared/ageTable.cpp index 0a6c189f94f..cfa2a648323 100644 --- a/hotspot/src/share/vm/gc/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp @@ -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; diff --git a/hotspot/src/share/vm/gc/shared/ageTable.hpp b/hotspot/src/share/vm/gc/shared/ageTable.hpp index 2902822006b..588cd9e5c72 100644 --- a/hotspot/src/share/vm/gc/shared/ageTable.hpp +++ b/hotspot/src/share/vm/gc/shared/ageTable.hpp @@ -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);