8224660: Parallel GC: Use WorkGang (2: MarksFromRootsTask)
authorlkorinth
Fri, 16 Aug 2019 09:18:23 +0200
changeset 57768 fc82b6cb8b14
parent 57767 b3e44e1b135d
child 57769 f7ca942a2714
8224660: Parallel GC: Use WorkGang (2: MarksFromRootsTask) Reviewed-by: stefank, kbarrett, tschatzl
src/hotspot/share/gc/parallel/pcTasks.cpp
src/hotspot/share/gc/parallel/pcTasks.hpp
src/hotspot/share/gc/parallel/psCompactionManager.hpp
src/hotspot/share/gc/parallel/psParallelCompact.cpp
src/hotspot/share/gc/parallel/psRootType.hpp
--- 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 */