< prev index next >

src/hotspot/share/gc/parallel/psScavenge.cpp

8224665: Parallel GC: Use WorkGang (7: remove task manager)

8224664: Parallel GC: Use WorkGang (6: PSRefProcTaskProxy)

8224663: Parallel GC: Use WorkGang (5: ScavengeRootsTask)

8224659: Parallel GC: Use WorkGang (1: PCRefProcTask)
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "aot/aotLoader.hpp"
+#include "classfile/classLoaderDataGraph.hpp"
 #include "classfile/stringTable.hpp"
 #include "code/codeCache.hpp"
-#include "gc/parallel/gcTaskManager.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
 #include "gc/parallel/psAdaptiveSizePolicy.hpp"
 #include "gc/parallel/psClosure.inline.hpp"
+#include "gc/parallel/psCompactionManager.hpp"
 #include "gc/parallel/psMarkSweepProxy.hpp"
 #include "gc/parallel/psParallelCompact.inline.hpp"
 #include "gc/parallel/psPromotionManager.inline.hpp"
+#include "gc/parallel/psRootType.inline.hpp"
 #include "gc/parallel/psScavenge.inline.hpp"
-#include "gc/parallel/psTasks.hpp"
 #include "gc/shared/gcCause.hpp"
 #include "gc/shared/gcHeapSummary.hpp"
 #include "gc/shared/gcId.hpp"
 #include "gc/shared/gcLocker.hpp"
 #include "gc/shared/gcTimer.hpp"

@@ -43,12 +45,18 #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" +#include "gc/shared/scavengableNMethods.hpp" #include "gc/shared/spaceDecorator.hpp" #include "gc/shared/weakProcessor.hpp" +#include "gc/shared/workerPolicy.hpp" +#include "gc/shared/workgroup.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "logging/log.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp"
@@ -56,13 +64,15 #include "runtime/biasedLocking.hpp" #include "runtime/handles.inline.hpp" #include "runtime/threadCritical.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "services/management.hpp" #include "services/memoryService.hpp" #include "utilities/stack.inline.hpp" + HeapWord* PSScavenge::_to_space_top_before_gc = NULL; int PSScavenge::_consecutive_skipped_scavenges = 0; SpanSubjectToDiscoveryClosure PSScavenge::_span_based_discoverer; ReferenceProcessor* PSScavenge::_ref_processor = NULL; PSCardTable* PSScavenge::_card_table = NULL;
@@ -73,10 +83,97 elapsedTimer PSScavenge::_accumulated_time; STWGCTimer PSScavenge::_gc_timer; ParallelScavengeTracer PSScavenge::_gc_tracer; CollectorCounters* PSScavenge::_counters = NULL; +void scavenge_roots_task(Parallel::RootType::Value root_type, uint which) { + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + + PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); + PSScavengeRootsClosure roots_closure(pm); + PSPromoteRootsClosure roots_to_old_closure(pm); + + switch (root_type) { + case Parallel::RootType::universe: + Universe::oops_do(&roots_closure); + break; + + case Parallel::RootType::jni_handles: + JNIHandles::oops_do(&roots_closure); + break; + + case Parallel::RootType::object_synchronizer: + ObjectSynchronizer::oops_do(&roots_closure); + break; + + case Parallel::RootType::system_dictionary: + SystemDictionary::oops_do(&roots_closure); + break; + + case Parallel::RootType::class_loader_data: + { + PSScavengeCLDClosure cld_closure(pm); + ClassLoaderDataGraph::cld_do(&cld_closure); + } + break; + + case Parallel::RootType::management: + Management::oops_do(&roots_closure); + break; + + case Parallel::RootType::jvmti: + JvmtiExport::oops_do(&roots_closure); + break; + + case Parallel::RootType::code_cache: + { + MarkingCodeBlobClosure code_closure(&roots_to_old_closure, CodeBlobToOopClosure::FixRelocations); + ScavengableNMethods::nmethods_do(&code_closure); + AOTLoader::oops_do(&roots_closure); + } + break; + +#if INCLUDE_JVMCI + case Parallel::RootType::jvmci: + JVMCI::oops_do(&roots_closure); + break; +#endif + + case Parallel::RootType::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 + pm->drain_stacks(false); +} + +void steal_task(ParallelTaskTerminator& terminator, uint worker_id) { + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + + PSPromotionManager* pm = + PSPromotionManager::gc_thread_promotion_manager(worker_id); + pm->drain_stacks(true); + guarantee(pm->stacks_empty(), + "stacks should be empty at this point"); + + while (true) { + StarTask p; + if (PSPromotionManager::steal_depth(worker_id, p)) { + TASKQUEUE_STATS_ONLY(pm->record_steal(p)); + pm->process_popped_location_depth(p); + pm->drain_stacks_depth(true); + } else { + if (terminator.offer_termination()) { + break; + } + } + } + guarantee(pm->stacks_empty(), "stacks should be empty at this point"); +} + // Define before use class PSIsAliveClosure: public BoolObjectClosure { public: bool do_object_b(oop p) { return (!PSScavenge::is_obj_in_young(p)) || p->is_forwarded();
@@ -123,61 +220,46 guarantee(_promotion_manager->stacks_empty(), "stacks should be empty at this point"); } }; -class PSRefProcTaskProxy: public GCTask { - typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; - ProcessTask & _rp_task; - uint _work_id; -public: - PSRefProcTaskProxy(ProcessTask & rp_task, uint work_id) - : _rp_task(rp_task), - _work_id(work_id) - { } - -private: - virtual char* name() { return (char *)"Process referents by policy in parallel"; } - virtual void do_it(GCTaskManager* manager, uint which); +class PSRefProcTaskExecutor: public AbstractRefProcTaskExecutor { + virtual void execute(ProcessTask& process_task, uint ergo_workers); }; -void PSRefProcTaskProxy::do_it(GCTaskManager* manager, uint which) -{ - PSPromotionManager* promotion_manager = - PSPromotionManager::gc_thread_promotion_manager(which); - assert(promotion_manager != NULL, "sanity check"); - PSKeepAliveClosure keep_alive(promotion_manager); - PSEvacuateFollowersClosure evac_followers(promotion_manager); - PSIsAliveClosure is_alive; - _rp_task.work(_work_id, is_alive, keep_alive, evac_followers); -} +class PSRefProcTask : public AbstractGangTask { + typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; + TaskTerminator _terminator; + ProcessTask& _task; + uint _active_workers; -class PSRefProcTaskExecutor: public AbstractRefProcTaskExecutor { - virtual void execute(ProcessTask& task, uint ergo_workers); -}; +public: + PSRefProcTask(ProcessTask& task, uint active_workers) + : AbstractGangTask("PSRefProcTask"), + _terminator(active_workers, PSPromotionManager::stack_array_depth()), + _task(task), + _active_workers(active_workers) { + } + + virtual void work(uint worker_id) { + PSPromotionManager* promotion_manager = + PSPromotionManager::gc_thread_promotion_manager(worker_id); + assert(promotion_manager != NULL, "sanity check"); + PSKeepAliveClosure keep_alive(promotion_manager); + PSEvacuateFollowersClosure evac_followers(promotion_manager); + PSIsAliveClosure is_alive; + _task.work(worker_id, is_alive, keep_alive, evac_followers); -void PSRefProcTaskExecutor::execute(ProcessTask& task, uint ergo_workers) -{ - GCTaskQueue* q = GCTaskQueue::create(); - GCTaskManager* manager = ParallelScavengeHeap::gc_task_manager(); - uint active_workers = manager->active_workers(); - - assert(active_workers == ergo_workers, - "Ergonomically chosen workers (%u) must be equal to active workers (%u)", - ergo_workers, active_workers); - - for(uint i=0; i < active_workers; i++) { - q->enqueue(new PSRefProcTaskProxy(task, i)); - } - TaskTerminator terminator(active_workers, - (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth()); - if (task.marks_oops_alive() && active_workers > 1) { - for (uint j = 0; j < active_workers; j++) { - q->enqueue(new StealTask(terminator.terminator())); + if (_task.marks_oops_alive() && _active_workers > 1) { + steal_task(*_terminator.terminator(), worker_id); } } - manager->execute_and_wait(q); +}; + +void PSRefProcTaskExecutor::execute(ProcessTask& process_task, uint ergo_workers) { + PSRefProcTask task(process_task, ergo_workers); + ParallelScavengeHeap::heap()->workers().run_task(&task); } // This method contains all heap specific policy for invoking scavenge. // PSScavenge::invoke_no_policy() will do nothing but attempt to // scavenge. It will not clean up after failed promotions, bail out if
@@ -219,18 +301,143 } return full_gc_done; } -class PSAddThreadRootsTaskClosure : public ThreadClosure { -private: - GCTaskQueue* _q; +class PSThreadRootsTaskClosure : public ThreadClosure { + uint _worker_id; +public: + PSThreadRootsTaskClosure(uint worker_id) : _worker_id(worker_id) { } + virtual void do_thread(Thread* thread) { + assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + + PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(_worker_id); + PSScavengeRootsClosure roots_closure(pm); + MarkingCodeBlobClosure roots_in_blobs(&roots_closure, CodeBlobToOopClosure::FixRelocations); + + thread->oops_do(&roots_closure, &roots_in_blobs); + + // Do the real work + pm->drain_stacks(false); + } +}; +// +// OldToYoungRootsTask +// +// This task is used to scan old to young roots in parallel +// +// A GC thread executing this tasks divides the generation (old gen) +// into slices and takes a stripe in the slice as its part of the +// work. +// +// +===============+ slice 0 +// | stripe 0 | +// +---------------+ +// | stripe 1 | +// +---------------+ +// | stripe 2 | +// +---------------+ +// | stripe 3 | +// +===============+ slice 1 +// | stripe 0 | +// +---------------+ +// | stripe 1 | +// +---------------+ +// | stripe 2 | +// +---------------+ +// | stripe 3 | +// +===============+ slice 2 +// ... +// +// A task is created for each stripe. In this case there are 4 tasks +// created. A GC thread first works on its stripe within slice 0 +// and then moves to its stripe in the next slice until all stripes +// exceed the top of the generation. Note that having fewer GC threads +// than stripes works because all the tasks are executed so all stripes +// will be covered. In this example if 4 tasks have been created to cover +// all the stripes and there are only 3 threads, one of the threads will +// get the tasks with the 4th stripe. However, there is a dependence in +// PSCardTable::scavenge_contents_parallel() on the number +// of tasks created. In scavenge_contents_parallel the distance +// to the next stripe is calculated based on the number of tasks. +// If the stripe width is ssize, a task's next stripe is at +// ssize * number_of_tasks (= slice_stride). In this case after +// finishing stripe 0 in slice 0, the thread finds the stripe 0 in slice1 +// by adding slice_stride to the start of stripe 0 in slice 0 to get +// to the start of stride 0 in slice 1. + +class ScavengeRootsTask : public AbstractGangTask { + StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do + EnumClaimer<Parallel::RootType::Value> _enum_claimer; + PSOldGen* _old_gen; + HeapWord* _gen_top; + uint _active_workers; + bool _is_empty; + TaskTerminator _terminator; public: - PSAddThreadRootsTaskClosure(GCTaskQueue* q) : _q(q) { } - void do_thread(Thread* t) { - _q->enqueue(new ThreadRootsTask(t)); + ScavengeRootsTask( + PSOldGen* old_gen, + HeapWord* gen_top, + uint active_workers, + bool is_empty) + : AbstractGangTask("ScavengeRootsTask"), + _strong_roots_scope(active_workers), + _enum_claimer(Parallel::RootType::sentinel), + _old_gen(old_gen), + _gen_top(gen_top), + _active_workers(active_workers), + _is_empty(is_empty), + _terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) { + } + + virtual void work(uint worker_id) { + ResourceMark rm; + + if (!_is_empty) { + // There are only old-to-young pointers if there are objects + // in the old gen. + + // There are not old-to-young pointers if the old gen is empty. + assert(!_old_gen->object_space()->is_empty(), + "Should not be called is there is no work"); + assert(_old_gen != NULL, "Sanity"); + assert(_old_gen->object_space()->contains(_gen_top) || _gen_top == _old_gen->object_space()->top(), "Sanity"); + assert(worker_id < ParallelGCThreads, "Sanity"); + + { + PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); + PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); + + card_table->scavenge_contents_parallel(_old_gen->start_array(), + _old_gen->object_space(), + _gen_top, + pm, + worker_id, + _active_workers); + + // Do the real work + pm->drain_stacks(false); + } + } + + for (Parallel::RootType::Value root_type; _enum_claimer.try_claim(root_type); /* empty */) { + scavenge_roots_task(root_type, worker_id); + } + + PSThreadRootsTaskClosure closure(worker_id); + Threads::possibly_parallel_threads_do(true /*parallel */, &closure); + + + // If active_workers can exceed 1, add a StrealTask. + // PSPromotionManager::drain_stacks_depth() does not fully drain its + // stacks and expects a StealTask to complete the draining if + // ParallelGCThreads is > 1. + + if (_active_workers > 1) { + steal_task(*_terminator.terminator() , worker_id); + } } }; // This method contains no policy. You should probably // be calling invoke() instead.
@@ -337,65 +544,24 // creating the promotion_manager. We pass the top // values to the card_table, to prevent it from // straying into the promotion labs. HeapWord* old_top = old_gen->object_space()->top(); - // Release all previously held resources - gc_task_manager()->release_all_resources(); - - // Set the number of GC threads to be used in this collection - gc_task_manager()->set_active_gang(); - gc_task_manager()->task_idle_workers(); - // Get the active number of workers here and use that value - // throughout the methods. - uint active_workers = gc_task_manager()->active_workers(); + uint active_workers = ParallelScavengeHeap::heap()->workers().update_active_workers(WorkerPolicy::calc_active_workers( + ParallelScavengeHeap::heap()->workers().total_workers(), + ParallelScavengeHeap::heap()->workers().active_workers(), + Threads::number_of_non_daemon_threads())); PSPromotionManager::pre_scavenge(); // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { GCTraceTime(Debug, gc, phases) tm("Scavenge", &_gc_timer); - ParallelScavengeHeap::ParStrongRootsScope psrs; - - GCTaskQueue* q = GCTaskQueue::create(); - if (!old_gen->object_space()->is_empty()) { - // There are only old-to-young pointers if there are objects - // in the old gen. - uint stripe_total = active_workers; - for(uint i=0; i < stripe_total; i++) { - q->enqueue(new OldToYoungRootsTask(old_gen, old_top, i, stripe_total)); - } - } - - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::universe)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jni_handles)); - // We scan the thread roots in parallel - PSAddThreadRootsTaskClosure cl(q); - Threads::java_threads_and_vm_thread_do(&cl); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::object_synchronizer)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti)); - q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); - JVMCI_ONLY(q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmci));) - - TaskTerminator terminator(active_workers, - (TaskQueueSetSuper*) promotion_manager->stack_array_depth()); - // If active_workers can exceed 1, add a StrealTask. - // PSPromotionManager::drain_stacks_depth() does not fully drain its - // stacks and expects a StealTask to complete the draining if - // ParallelGCThreads is > 1. - if (gc_task_manager()->workers() > 1) { - for (uint j = 0; j < active_workers; j++) { - q->enqueue(new StealTask(terminator.terminator())); - } - } - - gc_task_manager()->execute_and_wait(q); + ScavengeRootsTask task(old_gen, old_top, active_workers, old_gen->object_space()->is_empty()); + ParallelScavengeHeap::heap()->workers().run_task(&task); } scavenge_midpoint.update(); // Process reference objects discovered during scavenge
@@ -604,12 +770,10 MetaspaceUtils::print_metaspace_change(pre_gc_values.metadata_used()); // Track memory usage and detect low memory MemoryService::track_memory_usage(); heap->update_counters(); - - gc_task_manager()->release_idle_workers(); } if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification Universe::verify("After GC");
@@ -621,11 +785,10 scavenge_exit.update(); log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, scavenge_entry.ticks(), scavenge_midpoint.ticks(), scavenge_exit.ticks()); - gc_task_manager()->print_task_time_stamps(); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif
@@ -699,17 +862,10 } } return result; } - // Used to add tasks -GCTaskManager* const PSScavenge::gc_task_manager() { - assert(ParallelScavengeHeap::gc_task_manager() != NULL, - "shouldn't return NULL"); - return ParallelScavengeHeap::gc_task_manager(); -} - // Adaptive size policy support. When the young generation/old generation // boundary moves, _young_generation_boundary must be reset void PSScavenge::set_young_generation_boundary(HeapWord* v) { _young_generation_boundary = v; if (UseCompressedOops) {
< prev index next >