8224660: Parallel GC: Use WorkGang (2: MarksFromRootsTask)
Reviewed-by: stefank, kbarrett, tschatzl
--- a/src/hotspot/share/gc/parallel/pcTasks.cpp Fri Aug 16 09:18:19 2019 +0200
+++ b/src/hotspot/share/gc/parallel/pcTasks.cpp Fri Aug 16 09:18:23 2019 +0200
@@ -48,116 +48,6 @@
#include "utilities/stack.inline.hpp"
//
-// ThreadRootsMarkingTask
-//
-
-void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) {
- assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
-
- ResourceMark rm;
-
- ParCompactionManager* cm =
- ParCompactionManager::gc_thread_compaction_manager(which);
-
- PCMarkAndPushClosure mark_and_push_closure(cm);
- MarkingCodeBlobClosure mark_and_push_in_blobs(&mark_and_push_closure, !CodeBlobToOopClosure::FixRelocations);
-
- _thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
-
- // Do the real work
- cm->follow_marking_stacks();
-}
-
-
-void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
- assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
-
- ParCompactionManager* cm =
- ParCompactionManager::gc_thread_compaction_manager(which);
- PCMarkAndPushClosure mark_and_push_closure(cm);
-
- switch (_root_type) {
- case universe:
- Universe::oops_do(&mark_and_push_closure);
- break;
-
- case jni_handles:
- JNIHandles::oops_do(&mark_and_push_closure);
- break;
-
- case threads:
- {
- ResourceMark rm;
- MarkingCodeBlobClosure each_active_code_blob(&mark_and_push_closure, !CodeBlobToOopClosure::FixRelocations);
- Threads::oops_do(&mark_and_push_closure, &each_active_code_blob);
- }
- break;
-
- case object_synchronizer:
- ObjectSynchronizer::oops_do(&mark_and_push_closure);
- break;
-
- case management:
- Management::oops_do(&mark_and_push_closure);
- break;
-
- case jvmti:
- JvmtiExport::oops_do(&mark_and_push_closure);
- break;
-
- case system_dictionary:
- SystemDictionary::oops_do(&mark_and_push_closure);
- break;
-
- case class_loader_data: {
- CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_strong);
- ClassLoaderDataGraph::always_strong_cld_do(&cld_closure);
- }
- break;
-
- case code_cache:
- // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
- //ScavengableNMethods::scavengable_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
- AOTLoader::oops_do(&mark_and_push_closure);
- break;
-
- default:
- fatal("Unknown root type");
- }
-
- // Do the real work
- cm->follow_marking_stacks();
-}
-
-
-//
-// StealMarkingTask
-//
-
-StealMarkingTask::StealMarkingTask(ParallelTaskTerminator* t) :
- _terminator(t) {}
-
-void StealMarkingTask::do_it(GCTaskManager* manager, uint which) {
- assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
-
- ParCompactionManager* cm =
- ParCompactionManager::gc_thread_compaction_manager(which);
-
- oop obj = NULL;
- ObjArrayTask task;
- do {
- while (ParCompactionManager::steal_objarray(which, task)) {
- cm->follow_array((objArrayOop)task.obj(), task.index());
- cm->follow_marking_stacks();
- }
- while (ParCompactionManager::steal(which, obj)) {
- cm->follow_contents(obj);
- cm->follow_marking_stacks();
- }
- } while (!terminator()->offer_termination());
-}
-
-//
// CompactionWithStealingTask
//
--- a/src/hotspot/share/gc/parallel/pcTasks.hpp Fri Aug 16 09:18:19 2019 +0200
+++ b/src/hotspot/share/gc/parallel/pcTasks.hpp Fri Aug 16 09:18:23 2019 +0200
@@ -66,72 +66,6 @@
class ParallelTaskTerminator;
-class ThreadRootsMarkingTask : public GCTask {
- private:
- Thread* _thread;
-
- public:
- ThreadRootsMarkingTask(Thread* root) : _thread(root) {}
-
- char* name() { return (char *)"thread-roots-marking-task"; }
-
- virtual void do_it(GCTaskManager* manager, uint which);
-};
-
-
-//
-// MarkFromRootsTask
-//
-// This task marks from all the roots to all live
-// objects.
-//
-//
-
-class MarkFromRootsTask : public GCTask {
- public:
- enum RootType {
- universe = 1,
- jni_handles = 2,
- threads = 3,
- object_synchronizer = 4,
- management = 5,
- jvmti = 6,
- system_dictionary = 7,
- class_loader_data = 8,
- code_cache = 9
- };
- private:
- RootType _root_type;
- public:
- MarkFromRootsTask(RootType value) : _root_type(value) {}
-
- char* name() { return (char *)"mark-from-roots-task"; }
-
- virtual void do_it(GCTaskManager* manager, uint which);
-};
-
-
-//
-// StealMarkingTask
-//
-// This task is used to distribute work to idle threads.
-//
-
-class StealMarkingTask : public GCTask {
- private:
- ParallelTaskTerminator* const _terminator;
- private:
-
- public:
- char* name() { return (char *)"steal-marking-task"; }
-
- StealMarkingTask(ParallelTaskTerminator* t);
-
- ParallelTaskTerminator* terminator() { return _terminator; }
-
- virtual void do_it(GCTaskManager* manager, uint which);
-};
-
//
// CompactionWithStealingTask
//
--- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp Fri Aug 16 09:18:19 2019 +0200
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp Fri Aug 16 09:18:23 2019 +0200
@@ -45,6 +45,7 @@
friend class RefProcTaskExecutor;
friend class IdleGCTask;
friend class PCRefProcTask;
+ friend class MarkFromRootsTask;
public:
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp Fri Aug 16 09:18:19 2019 +0200
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp Fri Aug 16 09:18:23 2019 +0200
@@ -40,6 +40,7 @@
#include "gc/parallel/psOldGen.hpp"
#include "gc/parallel/psParallelCompact.inline.hpp"
#include "gc/parallel/psPromotionManager.inline.hpp"
+#include "gc/parallel/psRootType.hpp"
#include "gc/parallel/psScavenge.hpp"
#include "gc/parallel/psYoungGen.hpp"
#include "gc/shared/gcCause.hpp"
@@ -56,6 +57,7 @@
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "gc/shared/workerPolicy.hpp"
+#include "gc/shared/workgroup.hpp"
#include "logging/log.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/resourceArea.hpp"
@@ -2087,15 +2089,82 @@
class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure {
private:
- GCTaskQueue* _q;
+ uint _worker_id;
public:
- PCAddThreadRootsMarkingTaskClosure(GCTaskQueue* q) : _q(q) { }
- void do_thread(Thread* t) {
- _q->enqueue(new ThreadRootsMarkingTask(t));
+ PCAddThreadRootsMarkingTaskClosure(uint worker_id) : _worker_id(worker_id) { }
+ void do_thread(Thread* thread) {
+ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
+
+ ResourceMark rm;
+
+ ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(_worker_id);
+
+ PCMarkAndPushClosure mark_and_push_closure(cm);
+ MarkingCodeBlobClosure mark_and_push_in_blobs(&mark_and_push_closure, !CodeBlobToOopClosure::FixRelocations);
+
+ thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
+
+ // Do the real work
+ cm->follow_marking_stacks();
}
};
+static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_id) {
+ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
+
+ ParCompactionManager* cm =
+ ParCompactionManager::gc_thread_compaction_manager(worker_id);
+ PCMarkAndPushClosure mark_and_push_closure(cm);
+
+ switch (root_type) {
+ case ParallelRootType::universe:
+ Universe::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::jni_handles:
+ JNIHandles::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::object_synchronizer:
+ ObjectSynchronizer::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::management:
+ Management::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::jvmti:
+ JvmtiExport::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::system_dictionary:
+ SystemDictionary::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::class_loader_data:
+ {
+ CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_strong);
+ ClassLoaderDataGraph::always_strong_cld_do(&cld_closure);
+ }
+ break;
+
+ case ParallelRootType::code_cache:
+ // Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
+ //ScavengableNMethods::scavengable_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
+ AOTLoader::oops_do(&mark_and_push_closure);
+ break;
+
+ case ParallelRootType::sentinel:
+ DEBUG_ONLY(default:) // DEBUG_ONLY hack will create compile error on release builds (-Wswitch) and runtime check on debug builds
+ fatal("Bad enumeration value: %u", root_type);
+ break;
+ }
+
+ // Do the real work
+ cm->follow_marking_stacks();
+}
+
static void steal_marking_work(ParallelTaskTerminator& terminator, uint worker_id) {
assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
@@ -2116,6 +2185,39 @@
} while (!terminator.offer_termination());
}
+class MarkFromRootsTask : public AbstractGangTask {
+ typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
+ StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do
+ SequentialSubTasksDone _subtasks;
+ TaskTerminator _terminator;
+ uint _active_workers;
+
+public:
+ MarkFromRootsTask(uint active_workers) :
+ AbstractGangTask("MarkFromRootsTask"),
+ _strong_roots_scope(active_workers),
+ _subtasks(),
+ _terminator(active_workers, ParCompactionManager::stack_array()),
+ _active_workers(active_workers) {
+ _subtasks.set_n_threads(active_workers);
+ _subtasks.set_n_tasks(ParallelRootType::sentinel);
+ }
+
+ virtual void work(uint worker_id) {
+ for (uint task = 0; _subtasks.try_claim_task(task); /*empty*/ ) {
+ mark_from_roots_work(static_cast<ParallelRootType::Value>(task), worker_id);
+ }
+ _subtasks.all_tasks_completed();
+
+ PCAddThreadRootsMarkingTaskClosure closure(worker_id);
+ Threads::possibly_parallel_threads_do(true /*parallel */, &closure);
+
+ if (_active_workers > 1) {
+ steal_marking_work(*_terminator.terminator(), worker_id);
+ }
+ }
+};
+
class PCRefProcTask : public AbstractGangTask {
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
ProcessTask& _task;
@@ -2177,29 +2279,8 @@
{
GCTraceTime(Debug, gc, phases) tm("Par Mark", &_gc_timer);
- ParallelScavengeHeap::ParStrongRootsScope psrs;
-
- GCTaskQueue* q = GCTaskQueue::create();
-
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::universe));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jni_handles));
- // We scan the thread roots in parallel
- PCAddThreadRootsMarkingTaskClosure cl(q);
- Threads::java_threads_and_vm_thread_do(&cl);
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::object_synchronizer));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache));
-
- if (active_gc_threads > 1) {
- for (uint j = 0; j < active_gc_threads; j++) {
- q->enqueue(new StealMarkingTask(terminator.terminator()));
- }
- }
-
- gc_task_manager()->execute_and_wait(q);
+ MarkFromRootsTask task(active_gc_threads);
+ ParallelScavengeHeap::heap()->workers().run_task(&task);
}
// Process reference objects found during marking
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/psRootType.hpp Fri Aug 16 09:18:23 2019 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ */
+
+#ifndef SHARE_GC_PARALLEL_PSROOTTYPE_HPP
+#define SHARE_GC_PARALLEL_PSROOTTYPE_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/macros.hpp"
+
+class ParallelRootType : public AllStatic {
+public:
+ // Order and compactness of this enum is of importance.
+ // The order reflects the order these roots are to be processed,
+ // We do not want any holes in the enum as we enumerate these values by incrementing them.
+ enum Value {
+ universe,
+ jni_handles,
+ object_synchronizer,
+ management,
+ system_dictionary,
+ class_loader_data,
+ jvmti,
+ code_cache,
+ //"threads" are handled in parallel as a special case
+ sentinel
+ };
+};
+
+#endif /* SHARE_GC_PARALLEL_PSROOTTYPE_HPP */