--- old/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2019-06-18 16:47:54.897053866 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2019-06-18 16:47:54.353053073 -0400 @@ -377,6 +377,9 @@ // 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(); --- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-06-18 16:47:56.217055788 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-06-18 16:47:55.700055035 -0400 @@ -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 @@ 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 @@ } 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 @@ free_set()->recycle_trash(); } +class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask { +private: + ShenandoahJNIHandleRoots _jni_roots; + +public: + ShenandoahConcurrentRootsEvacUpdateTask() : + AbstractGangTask("Shenandoah Evacuate/Update Concurrent Roots Task") { + } + + void work(uint worker_id) { + ShenandoahEvacOOMScope oom; + ShenandoahEvacuateUpdateRootsClosure cl; + _jni_roots.oops_do(&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 @@ 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); --- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp 2019-06-18 16:47:57.692057936 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp 2019-06-18 16:47:57.034056977 -0400 @@ -391,6 +391,7 @@ 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 @@ void op_reset(); void op_mark(); void op_preclean(); + void op_roots(); void op_cleanup(); void op_conc_evac(); void op_stw_evac(); --- old/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp 2019-06-18 16:48:01.679063741 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp 2019-06-18 16:47:58.401058968 -0400 @@ -306,6 +306,7 @@ 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") \ --- old/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2019-06-18 16:48:03.025065701 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2019-06-18 16:48:02.492064925 -0400 @@ -71,10 +71,6 @@ _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 @@ _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(oops, worker_id); + } _thread_roots.oops_do(oops, NULL, worker_id); _cld_roots.clds_do(&clds, &clds, worker_id); --- old/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp 2019-06-18 16:48:04.347067626 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp 2019-06-18 16:48:03.818066856 -0400 @@ -61,9 +61,15 @@ void oops_do(OopClosure* cl, uint worker_id); }; -class ShenandoahJNIHandleRoots : public ShenandoahSerialRoot { +template +class ShenandoahJNIHandleRoots { +private: + OopStorage::ParState _itr; public: ShenandoahJNIHandleRoots(); + + template + void oops_do(T* cl, uint worker_id = 0); }; class ShenandoahThreadRoots { @@ -129,11 +135,11 @@ template class ShenandoahRootScanner : public ShenandoahRootProcessor { private: - ShenandoahSerialRoots _serial_roots; - ShenandoahJNIHandleRoots _jni_roots; - ShenandoahClassLoaderDataRoots _cld_roots; - ShenandoahThreadRoots _thread_roots; - ShenandoahCodeCacheRoots _code_roots; + ShenandoahSerialRoots _serial_roots; + ShenandoahJNIHandleRoots<> _jni_roots; + ShenandoahClassLoaderDataRoots _cld_roots; + ShenandoahThreadRoots _thread_roots; + ShenandoahCodeCacheRoots _code_roots; public: ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase); @@ -157,16 +163,17 @@ // 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<> _jni_roots; + ShenandoahClassLoaderDataRoots _cld_roots; + ShenandoahThreadRoots _thread_roots; + ShenandoahWeakRoots _weak_roots; + ShenandoahStringDedupRoots _dedup_roots; ShenandoahCodeCacheRoots _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 @@ // 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<> _jni_roots; + ShenandoahClassLoaderDataRoots _cld_roots; + ShenandoahThreadRoots _thread_roots; + ShenandoahWeakRoots _weak_roots; + ShenandoahStringDedupRoots _dedup_roots; ShenandoahCodeCacheRoots _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 @@ // 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<> _jni_roots; + ShenandoahClassLoaderDataRoots _cld_roots; + ShenandoahThreadRoots _thread_roots; + ShenandoahWeakRoots _weak_roots; + ShenandoahStringDedupRoots _dedup_roots; ShenandoahCodeCacheRoots _code_roots; public: --- old/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp 2019-06-18 16:48:05.518069331 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp 2019-06-18 16:48:05.038068632 -0400 @@ -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 +ShenandoahJNIHandleRoots::ShenandoahJNIHandleRoots() : + _itr(JNIHandles::global_handles()) { +} + +template +template +void ShenandoahJNIHandleRoots::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 void ShenandoahWeakRoots::oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) { _task.work(worker_id, is_alive, keep_alive); --- old/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.cpp 2019-06-18 16:48:06.630070951 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.cpp 2019-06-18 16:48:06.146070246 -0400 @@ -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 @@ 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; --- old/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp 2019-06-18 16:48:07.890072785 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahWorkerPolicy.hpp 2019-06-18 16:48:07.374072034 -0400 @@ -30,6 +30,7 @@ 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 @@ // 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(); --- /dev/null 2019-06-03 18:05:13.248999865 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp 2019-06-18 16:48:08.648073889 -0400 @@ -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; +} --- /dev/null 2019-06-03 18:05:13.248999865 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp 2019-06-18 16:48:09.869075667 -0400 @@ -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