< prev index next >

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

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

*** 21,39 **** --- 21,42 ---- * 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/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" ***************
*** 43,55 **** --- 46,63 ---- #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" ***************
*** 57,69 **** --- 65,79 ---- #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; ***************
*** 74,83 **** --- 84,180 ---- 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(); ***************
*** 220,237 **** } return full_gc_done; } ! class PSAddThreadRootsTaskClosure : public ThreadClosure { ! private: ! GCTaskQueue* _q; public: ! PSAddThreadRootsTaskClosure(GCTaskQueue* q) : _q(q) { } ! void do_thread(Thread* t) { ! _q->enqueue(new ThreadRootsTask(t)); } }; // This method contains no policy. You should probably // be calling invoke() instead. --- 317,459 ---- } return full_gc_done; } ! 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: ! 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. ***************
*** 358,406 **** // 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); } scavenge_midpoint.update(); // Process reference objects discovered during scavenge --- 580,592 ---- // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { GCTraceTime(Debug, gc, phases) tm("Scavenge", &_gc_timer); ! 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
< prev index next >