< 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)

*** 21,41 **** * questions. * */ #include "precompiled.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/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" --- 21,43 ---- * questions. * */ #include "precompiled.hpp" + #include "aot/aotLoader.hpp" + #include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.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/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcTimer.hpp" ***************
*** 43,54 **** --- 45,62 ---- #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,68 **** --- 64,78 ---- #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,82 **** --- 83,179 ---- 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,183 **** 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); }; ! 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 PSRefProcTaskExecutor: public AbstractRefProcTaskExecutor { ! virtual void execute(ProcessTask& task, uint ergo_workers); ! }; ! 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())); } } ! manager->execute_and_wait(q); } // 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 --- 220,265 ---- guarantee(_promotion_manager->stacks_empty(), "stacks should be empty at this point"); } }; ! class PSRefProcTaskExecutor: public AbstractRefProcTaskExecutor { ! virtual void execute(ProcessTask& process_task, uint ergo_workers); }; ! class PSRefProcTask : public AbstractGangTask { ! typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; ! TaskTerminator _terminator; ! ProcessTask& _task; ! uint _active_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); ! if (_task.marks_oops_alive() && _active_workers > 1) { ! steal_task(*_terminator.terminator(), worker_id); } } ! }; ! ! 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,236 **** } 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. --- 301,443 ---- } 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. ***************
*** 337,401 **** // 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(); 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); } scavenge_midpoint.update(); // Process reference objects discovered during scavenge --- 544,567 ---- // 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(); ! 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); ! 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,615 **** 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"); --- 770,779 ---- ***************
*** 621,631 **** 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 --- 785,794 ---- ***************
*** 699,715 **** } } 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) { --- 862,871 ----
< prev index next >