8225582: Shenandoah: Enable concurrent evacuation of JNIHandles

Reviewed-by: rkennke, shade
This commit is contained in:
Zhengyu Gu 2019-06-19 08:52:15 -04:00
parent b870874d22
commit fe66fd327f
11 changed files with 207 additions and 38 deletions

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019, Red Hat, Inc. All rights reserved.
*
* 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/shenandoah/shenandoahConcurrentRoots.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
bool ShenandoahConcurrentRoots::can_do_concurrent_roots() {
// Don't support traversal GC at this moment
return !ShenandoahHeap::heap()->is_concurrent_traversal_in_progress();
}
bool ShenandoahConcurrentRoots::should_do_concurrent_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
bool stw_gc_in_progress = heap->is_full_gc_in_progress() ||
heap->is_degenerated_gc_in_progress();
return can_do_concurrent_roots() &&
!stw_gc_in_progress;
}

@ -0,0 +1,38 @@
/*
* Copyright (c) 2019, Red Hat, Inc. All rights reserved.
*
* 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.
*
*/
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP
#include "memory/allocation.hpp"
class ShenandoahConcurrentRoots : public AllStatic {
public:
// Can GC settings allow concurrent root processing
static bool can_do_concurrent_roots();
// If current GC cycle can process roots concurrently
static bool should_do_concurrent_roots();
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP

@ -377,6 +377,9 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau
// Complete marking under STW, and start evacuation
heap->vmop_entry_final_mark();
// Evacuate concurrent roots
heap->entry_roots();
// Final mark might have reclaimed some immediate garbage, kick cleanup to reclaim
// the space. This would be the last action if there is nothing to evacuate.
heap->entry_cleanup();

@ -38,6 +38,7 @@
#include "gc/shenandoah/shenandoahCollectionSet.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp"
#include "gc/shenandoah/shenandoahConcurrentRoots.hpp"
#include "gc/shenandoah/shenandoahControlThread.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
@ -1071,9 +1072,11 @@ void ShenandoahHeap::evacuate_and_update_roots() {
DerivedPointerTable::clear();
#endif
assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Only iterate roots while world is stopped");
{
ShenandoahRootEvacuator rp(workers()->active_workers(), ShenandoahPhaseTimings::init_evac);
// Include concurrent roots if current cycle can not process those roots concurrently
ShenandoahRootEvacuator rp(workers()->active_workers(),
ShenandoahPhaseTimings::init_evac,
!ShenandoahConcurrentRoots::should_do_concurrent_roots());
ShenandoahEvacuateUpdateRootsTask roots_task(&rp);
workers()->run_task(&roots_task);
}
@ -1517,7 +1520,11 @@ void ShenandoahHeap::op_final_mark() {
}
if (ShenandoahVerify) {
verifier()->verify_roots_no_forwarded();
if (ShenandoahConcurrentRoots::should_do_concurrent_roots()) {
verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::JNIHandleRoots);
} else {
verifier()->verify_roots_no_forwarded();
}
verifier()->verify_during_evacuation();
}
} else {
@ -1578,6 +1585,30 @@ void ShenandoahHeap::op_cleanup() {
free_set()->recycle_trash();
}
class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask {
private:
ShenandoahJNIHandleRoots<true /*concurrent*/> _jni_roots;
public:
ShenandoahConcurrentRootsEvacUpdateTask() :
AbstractGangTask("Shenandoah Evacuate/Update Concurrent Roots Task") {
}
void work(uint worker_id) {
ShenandoahEvacOOMScope oom;
ShenandoahEvacuateUpdateRootsClosure cl;
_jni_roots.oops_do<ShenandoahEvacuateUpdateRootsClosure>(&cl);
}
};
void ShenandoahHeap::op_roots() {
if (is_evacuation_in_progress() &&
ShenandoahConcurrentRoots::should_do_concurrent_roots()) {
ShenandoahConcurrentRootsEvacUpdateTask task;
workers()->run_task(&task);
}
}
void ShenandoahHeap::op_reset() {
reset_mark_bitmap();
}
@ -2559,6 +2590,22 @@ void ShenandoahHeap::entry_updaterefs() {
try_inject_alloc_failure();
op_updaterefs();
}
void ShenandoahHeap::entry_roots() {
ShenandoahGCPhase phase(ShenandoahPhaseTimings::conc_roots);
static const char* msg = "Concurrent roots processing";
GCTraceTime(Info, gc) time(msg, NULL, GCCause::_no_gc, true);
EventMark em("%s", msg);
ShenandoahWorkerScope scope(workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing(),
"concurrent root processing");
try_inject_alloc_failure();
op_roots();
}
void ShenandoahHeap::entry_cleanup() {
ShenandoahGCPhase phase(ShenandoahPhaseTimings::conc_cleanup);

@ -391,6 +391,7 @@ public:
void entry_reset();
void entry_mark();
void entry_preclean();
void entry_roots();
void entry_cleanup();
void entry_evac();
void entry_updaterefs();
@ -414,6 +415,7 @@ private:
void op_reset();
void op_mark();
void op_preclean();
void op_roots();
void op_cleanup();
void op_conc_evac();
void op_stw_evac();

@ -306,6 +306,7 @@ class outputStream;
f(conc_mark, "Concurrent Marking") \
f(conc_termination, " Termination") \
f(conc_preclean, "Concurrent Precleaning") \
f(conc_roots, "Concurrent Roots") \
f(conc_evac, "Concurrent Evacuation") \
f(conc_update_refs, "Concurrent Update Refs") \
f(conc_cleanup, "Concurrent Cleanup") \

@ -71,10 +71,6 @@ void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
_jvmti_root.oops_do(cl, worker_id);
}
ShenandoahJNIHandleRoots::ShenandoahJNIHandleRoots() :
ShenandoahSerialRoot(&JNIHandles::oops_do, ShenandoahPhaseTimings::JNIRoots) {
}
ShenandoahThreadRoots::ShenandoahThreadRoots(bool is_par) : _is_par(is_par) {
Threads::change_thread_claim_token();
}
@ -148,21 +144,22 @@ ShenandoahRootProcessor::~ShenandoahRootProcessor() {
_heap->phase_timings()->record_workers_end(_phase);
}
ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool include_concurrent_roots) :
ShenandoahRootProcessor(phase),
_thread_roots(n_workers > 1),
_weak_roots(n_workers) {
_weak_roots(n_workers),
_include_concurrent_roots(include_concurrent_roots) {
}
void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {
MarkingCodeBlobClosure blobsCl(oops, CodeBlobToOopClosure::FixRelocations);
CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
CLDToOopClosure* weak_clds = ShenandoahHeap::heap()->unload_classes() ? NULL : &clds;
AlwaysTrueClosure always_true;
_serial_roots.oops_do(oops, worker_id);
_jni_roots.oops_do(oops, worker_id);
if (_include_concurrent_roots) {
_jni_roots.oops_do<OopClosure>(oops, worker_id);
}
_thread_roots.oops_do(oops, NULL, worker_id);
_cld_roots.clds_do(&clds, &clds, worker_id);

@ -61,9 +61,15 @@ public:
void oops_do(OopClosure* cl, uint worker_id);
};
class ShenandoahJNIHandleRoots : public ShenandoahSerialRoot {
template <bool CONCURRENT>
class ShenandoahJNIHandleRoots {
private:
OopStorage::ParState<CONCURRENT, false /* is_const */> _itr;
public:
ShenandoahJNIHandleRoots();
template <typename T>
void oops_do(T* cl, uint worker_id = 0);
};
class ShenandoahThreadRoots {
@ -129,11 +135,11 @@ public:
template <typename ITR>
class ShenandoahRootScanner : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahCodeCacheRoots<ITR> _code_roots;
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots<false /*concurrent*/> _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahCodeCacheRoots<ITR> _code_roots;
public:
ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase);
@ -157,16 +163,17 @@ typedef ShenandoahRootScanner<ShenandoahCsetCodeRootsIterator> ShenandoahCSetRoo
// Evacuate all roots at a safepoint
class ShenandoahRootEvacuator : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots<false /*concurrent*/> _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
bool _include_concurrent_roots;
public:
ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase);
ShenandoahRootEvacuator(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool include_concurrent_roots);
void roots_do(uint worker_id, OopClosure* oops);
};
@ -174,14 +181,14 @@ public:
// Update all roots at a safepoint
class ShenandoahRootUpdater : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots<false /*concurrent*/> _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahCodeCacheRoots<ShenandoahCsetCodeRootsIterator> _code_roots;
const bool _update_code_cache;
const bool _update_code_cache;
public:
ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase, bool update_code_cache);
@ -193,12 +200,12 @@ public:
// Adjuster all roots at a safepoint during full gc
class ShenandoahRootAdjuster : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahSerialRoots _serial_roots;
ShenandoahJNIHandleRoots<false /*concurrent*/> _jni_roots;
ShenandoahClassLoaderDataRoots _cld_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahWeakRoots _weak_roots;
ShenandoahStringDedupRoots _dedup_roots;
ShenandoahCodeCacheRoots<ShenandoahAllCodeRootsIterator> _code_roots;
public:

@ -24,12 +24,31 @@
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
#include "classfile/classLoaderDataGraph.hpp"
#include "gc/shared/oopStorageParState.inline.hpp"
#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahRootProcessor.hpp"
#include "gc/shenandoah/shenandoahTimingTracker.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "memory/resourceArea.hpp"
template <bool CONCURRENT>
ShenandoahJNIHandleRoots<CONCURRENT>::ShenandoahJNIHandleRoots() :
_itr(JNIHandles::global_handles()) {
}
template <bool CONCURRENT>
template <typename T>
void ShenandoahJNIHandleRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) {
if (CONCURRENT) {
_itr.oops_do(cl);
} else {
ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIRoots, worker_id);
_itr.oops_do(cl);
}
}
template <typename IsAlive, typename KeepAlive>
void ShenandoahWeakRoots::oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) {
_task.work<IsAlive, KeepAlive>(worker_id, is_alive, keep_alive);

@ -30,6 +30,7 @@
uint ShenandoahWorkerPolicy::_prev_par_marking = 0;
uint ShenandoahWorkerPolicy::_prev_conc_marking = 0;
uint ShenandoahWorkerPolicy::_prev_conc_evac = 0;
uint ShenandoahWorkerPolicy::_prev_conc_root_proc = 0;
uint ShenandoahWorkerPolicy::_prev_fullgc = 0;
uint ShenandoahWorkerPolicy::_prev_degengc = 0;
uint ShenandoahWorkerPolicy::_prev_stw_traversal = 0;
@ -63,6 +64,16 @@ uint ShenandoahWorkerPolicy::calc_workers_for_final_marking() {
return _prev_par_marking;
}
// Calculate workers for concurrent root processing
uint ShenandoahWorkerPolicy::calc_workers_for_conc_root_processing() {
uint active_workers = (_prev_conc_root_proc == 0) ? ConcGCThreads : _prev_conc_root_proc;
_prev_conc_root_proc =
WorkerPolicy::calc_active_conc_workers(ConcGCThreads,
active_workers,
Threads::number_of_non_daemon_threads());
return _prev_conc_root_proc;
}
// Calculate workers for concurrent evacuation (concurrent GC)
uint ShenandoahWorkerPolicy::calc_workers_for_conc_evac() {
uint active_workers = (_prev_conc_evac == 0) ? ConcGCThreads : _prev_conc_evac;

@ -30,6 +30,7 @@ class ShenandoahWorkerPolicy : AllStatic {
private:
static uint _prev_par_marking;
static uint _prev_conc_marking;
static uint _prev_conc_root_proc;
static uint _prev_conc_evac;
static uint _prev_fullgc;
static uint _prev_degengc;
@ -50,6 +51,9 @@ public:
// Calculate the number of workers for final marking
static uint calc_workers_for_final_marking();
// Calculate workers for concurrent root processing
static uint calc_workers_for_conc_root_processing();
// Calculate workers for concurrent evacuation (concurrent GC)
static uint calc_workers_for_conc_evac();