# HG changeset patch # User lkorinth # Date 1565939918 -7200 # Node ID 5cbc3bd9fdfd97bb2b58619100fdffff810a523b # Parent 2410b04f074f94bd3d557e486cc31e87ba5425aa 8224665: Parallel GC: Use WorkGang (7: remove task manager) Reviewed-by: stefank, kbarrett, tschatzl diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/gcTaskManager.cpp --- a/src/hotspot/share/gc/parallel/gcTaskManager.cpp Fri Aug 16 09:18:35 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1074 +0,0 @@ -/* - * Copyright (c) 2002, 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. - * - */ - -#include "precompiled.hpp" -#include "gc/parallel/gcTaskManager.hpp" -#include "gc/parallel/gcTaskThread.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/workerManager.hpp" -#include "gc/shared/workerPolicy.hpp" -#include "logging/log.hpp" -#include "logging/logStream.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/orderAccess.hpp" -#include "runtime/os.hpp" - -// -// GCTask -// - -const char* GCTask::Kind::to_string(kind value) { - const char* result = "unknown GCTask kind"; - switch (value) { - default: - result = "unknown GCTask kind"; - break; - case unknown_task: - result = "unknown task"; - break; - case ordinary_task: - result = "ordinary task"; - break; - case wait_for_barrier_task: - result = "wait for barrier task"; - break; - case noop_task: - result = "noop task"; - break; - case idle_task: - result = "idle task"; - break; - } - return result; -}; - -GCTask::GCTask() { - initialize(Kind::ordinary_task, GCId::current()); -} - -GCTask::GCTask(Kind::kind kind) { - initialize(kind, GCId::current()); -} - -GCTask::GCTask(Kind::kind kind, uint gc_id) { - initialize(kind, gc_id); -} - -void GCTask::initialize(Kind::kind kind, uint gc_id) { - _kind = kind; - _affinity = GCTaskManager::sentinel_worker(); - _older = NULL; - _newer = NULL; - _gc_id = gc_id; -} - -void GCTask::destruct() { - assert(older() == NULL, "shouldn't have an older task"); - assert(newer() == NULL, "shouldn't have a newer task"); - // Nothing to do. -} - -NOT_PRODUCT( -void GCTask::print(const char* message) const { - tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT, - p2i(newer()), p2i(this), affinity(), p2i(older())); -} -) - -// -// GCTaskQueue -// - -GCTaskQueue* GCTaskQueue::create() { - GCTaskQueue* result = new GCTaskQueue(false); - if (TraceGCTaskQueue) { - tty->print_cr("GCTaskQueue::create()" - " returns " INTPTR_FORMAT, p2i(result)); - } - return result; -} - -GCTaskQueue* GCTaskQueue::create_on_c_heap() { - GCTaskQueue* result = new(ResourceObj::C_HEAP, mtGC) GCTaskQueue(true); - if (TraceGCTaskQueue) { - tty->print_cr("GCTaskQueue::create_on_c_heap()" - " returns " INTPTR_FORMAT, - p2i(result)); - } - return result; -} - -GCTaskQueue::GCTaskQueue(bool on_c_heap) : - _is_c_heap_obj(on_c_heap) { - initialize(); - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::GCTaskQueue() constructor", - p2i(this)); - } -} - -void GCTaskQueue::destruct() { - // Nothing to do. -} - -void GCTaskQueue::destroy(GCTaskQueue* that) { - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::destroy()" - " is_c_heap_obj: %s", - p2i(that), - that->is_c_heap_obj() ? "true" : "false"); - } - // That instance may have been allocated as a CHeapObj, - // in which case we have to free it explicitly. - if (that != NULL) { - that->destruct(); - assert(that->is_empty(), "should be empty"); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } - } -} - -void GCTaskQueue::initialize() { - set_insert_end(NULL); - set_remove_end(NULL); - set_length(0); -} - -// Enqueue one task. -void GCTaskQueue::enqueue(GCTask* task) { - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::enqueue(task: " - INTPTR_FORMAT ")", - p2i(this), p2i(task)); - print("before:"); - } - assert(task != NULL, "shouldn't have null task"); - assert(task->older() == NULL, "shouldn't be on queue"); - assert(task->newer() == NULL, "shouldn't be on queue"); - task->set_newer(NULL); - task->set_older(insert_end()); - if (is_empty()) { - set_remove_end(task); - } else { - insert_end()->set_newer(task); - } - set_insert_end(task); - increment_length(); - verify_length(); - if (TraceGCTaskQueue) { - print("after:"); - } -} - -// Enqueue a whole list of tasks. Empties the argument list. -void GCTaskQueue::enqueue(GCTaskQueue* list) { - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::enqueue(list: " - INTPTR_FORMAT ")", - p2i(this), p2i(list)); - print("before:"); - list->print("list:"); - } - if (list->is_empty()) { - // Enqueueing the empty list: nothing to do. - return; - } - uint list_length = list->length(); - if (is_empty()) { - // Enqueueing to empty list: just acquire elements. - set_insert_end(list->insert_end()); - set_remove_end(list->remove_end()); - set_length(list_length); - } else { - // Prepend argument list to our queue. - list->remove_end()->set_older(insert_end()); - insert_end()->set_newer(list->remove_end()); - set_insert_end(list->insert_end()); - set_length(length() + list_length); - // empty the argument list. - } - list->initialize(); - if (TraceGCTaskQueue) { - print("after:"); - list->print("list:"); - } - verify_length(); -} - -// Dequeue one task. -GCTask* GCTaskQueue::dequeue() { - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::dequeue()", p2i(this)); - print("before:"); - } - assert(!is_empty(), "shouldn't dequeue from empty list"); - GCTask* result = remove(); - assert(result != NULL, "shouldn't have NULL task"); - if (TraceGCTaskQueue) { - tty->print_cr(" return: " INTPTR_FORMAT, p2i(result)); - print("after:"); - } - return result; -} - -// Dequeue one task, preferring one with affinity. -GCTask* GCTaskQueue::dequeue(uint affinity) { - if (TraceGCTaskQueue) { - tty->print_cr("[" INTPTR_FORMAT "]" - " GCTaskQueue::dequeue(%u)", p2i(this), affinity); - print("before:"); - } - assert(!is_empty(), "shouldn't dequeue from empty list"); - // Look down to the next barrier for a task with this affinity. - GCTask* result = NULL; - for (GCTask* element = remove_end(); - element != NULL; - element = element->newer()) { - if (element->is_barrier_task()) { - // Don't consider barrier tasks, nor past them. - result = NULL; - break; - } - if (element->affinity() == affinity) { - result = remove(element); - break; - } - } - // If we didn't find anything with affinity, just take the next task. - if (result == NULL) { - result = remove(); - } - if (TraceGCTaskQueue) { - tty->print_cr(" return: " INTPTR_FORMAT, p2i(result)); - print("after:"); - } - return result; -} - -GCTask* GCTaskQueue::remove() { - // Dequeue from remove end. - GCTask* result = remove_end(); - assert(result != NULL, "shouldn't have null task"); - assert(result->older() == NULL, "not the remove_end"); - set_remove_end(result->newer()); - if (remove_end() == NULL) { - assert(insert_end() == result, "not a singleton"); - set_insert_end(NULL); - } else { - remove_end()->set_older(NULL); - } - result->set_newer(NULL); - decrement_length(); - assert(result->newer() == NULL, "shouldn't be on queue"); - assert(result->older() == NULL, "shouldn't be on queue"); - verify_length(); - return result; -} - -GCTask* GCTaskQueue::remove(GCTask* task) { - // This is slightly more work, and has slightly fewer asserts - // than removing from the remove end. - assert(task != NULL, "shouldn't have null task"); - GCTask* result = task; - if (result->newer() != NULL) { - result->newer()->set_older(result->older()); - } else { - assert(insert_end() == result, "not youngest"); - set_insert_end(result->older()); - } - if (result->older() != NULL) { - result->older()->set_newer(result->newer()); - } else { - assert(remove_end() == result, "not oldest"); - set_remove_end(result->newer()); - } - result->set_newer(NULL); - result->set_older(NULL); - decrement_length(); - verify_length(); - return result; -} - -NOT_PRODUCT( -// Count the elements in the queue and verify the length against -// that count. -void GCTaskQueue::verify_length() const { - uint count = 0; - for (GCTask* element = insert_end(); - element != NULL; - element = element->older()) { - - count++; - } - assert(count == length(), "Length does not match queue"); -} - -void GCTaskQueue::print(const char* message) const { - tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:" - " insert_end: " INTPTR_FORMAT - " remove_end: " INTPTR_FORMAT - " length: %d" - " %s", - p2i(this), p2i(insert_end()), p2i(remove_end()), length(), message); - uint count = 0; - for (GCTask* element = insert_end(); - element != NULL; - element = element->older()) { - element->print(" "); - count++; - tty->cr(); - } - tty->print("Total tasks: %d", count); -} -) - -// -// SynchronizedGCTaskQueue -// - -SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg, - Monitor * lock_arg) : - _unsynchronized_queue(queue_arg), - _lock(lock_arg) { - assert(unsynchronized_queue() != NULL, "null queue"); - assert(lock() != NULL, "null lock"); -} - -SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { - // Nothing to do. -} - -// -// GCTaskManager -// -GCTaskManager::GCTaskManager(uint workers) : - _workers(workers), - _created_workers(0), - _active_workers(0), - _idle_workers(0) { - initialize(); -} - -GCTaskThread* GCTaskManager::install_worker(uint t) { - GCTaskThread* new_worker = GCTaskThread::create(this, t, _processor_assignment[t]); - set_thread(t, new_worker); - return new_worker; -} - -void GCTaskManager::add_workers(bool initializing) { - os::ThreadType worker_type = os::pgc_thread; - uint previous_created_workers = _created_workers; - - _created_workers = WorkerManager::add_workers(this, - _active_workers, - _workers, - _created_workers, - worker_type, - initializing); - _active_workers = MIN2(_created_workers, _active_workers); - - WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing); -} - -const char* GCTaskManager::group_name() { - return "ParGC Thread"; -} - -void GCTaskManager::initialize() { - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::initialize: workers: %u", workers()); - } - assert(workers() != 0, "no workers"); - _monitor = new Monitor(Mutex::barrier, // rank - "GCTaskManager monitor", // name - Mutex::_allow_vm_block_flag, // allow_vm_block - Monitor::_safepoint_check_never); - // The queue for the GCTaskManager must be a CHeapObj. - GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); - _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); - _noop_task = NoopGCTask::create_on_c_heap(); - _resource_flag = NEW_C_HEAP_ARRAY(bool, workers(), mtGC); - { - // Set up worker threads. - // Distribute the workers among the available processors, - // unless we were told not to, or if the os doesn't want to. - _processor_assignment = NEW_C_HEAP_ARRAY(uint, workers(), mtGC); - if (!BindGCTaskThreadsToCPUs || - !os::distribute_processes(workers(), _processor_assignment)) { - for (uint a = 0; a < workers(); a += 1) { - _processor_assignment[a] = sentinel_worker(); - } - } - - _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers(), mtGC); - _active_workers = ParallelGCThreads; - if (UseDynamicNumberOfGCThreads && !FLAG_IS_CMDLINE(ParallelGCThreads)) { - _active_workers = 1U; - } - - Log(gc, task, thread) log; - if (log.is_trace()) { - LogStream ls(log.trace()); - ls.print("GCTaskManager::initialize: distribution:"); - for (uint t = 0; t < workers(); t += 1) { - ls.print(" %u", _processor_assignment[t]); - } - ls.cr(); - } - } - reset_busy_workers(); - set_unblocked(); - for (uint w = 0; w < workers(); w += 1) { - set_resource_flag(w, false); - } - reset_delivered_tasks(); - reset_completed_tasks(); - reset_barriers(); - reset_emptied_queue(); - - add_workers(true); -} - -GCTaskManager::~GCTaskManager() { - assert(busy_workers() == 0, "still have busy workers"); - assert(queue()->is_empty(), "still have queued work"); - NoopGCTask::destroy(_noop_task); - _noop_task = NULL; - if (_thread != NULL) { - for (uint i = 0; i < created_workers(); i += 1) { - GCTaskThread::destroy(thread(i)); - set_thread(i, NULL); - } - FREE_C_HEAP_ARRAY(GCTaskThread*, _thread); - _thread = NULL; - } - if (_processor_assignment != NULL) { - FREE_C_HEAP_ARRAY(uint, _processor_assignment); - _processor_assignment = NULL; - } - if (_resource_flag != NULL) { - FREE_C_HEAP_ARRAY(bool, _resource_flag); - _resource_flag = NULL; - } - if (queue() != NULL) { - GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue(); - GCTaskQueue::destroy(unsynchronized_queue); - SynchronizedGCTaskQueue::destroy(queue()); - _queue = NULL; - } - if (monitor() != NULL) { - delete monitor(); - _monitor = NULL; - } -} - -void GCTaskManager::set_active_gang() { - _active_workers = - WorkerPolicy::calc_active_workers(workers(), - active_workers(), - Threads::number_of_non_daemon_threads()); - - assert(!all_workers_active() || active_workers() == ParallelGCThreads, - "all_workers_active() is incorrect: " - "active %d ParallelGCThreads %u", active_workers(), - ParallelGCThreads); - _active_workers = MIN2(_active_workers, _workers); - // "add_workers" does not guarantee any additional workers - add_workers(false); - log_trace(gc, task)("GCTaskManager::set_active_gang(): " - "all_workers_active() %d workers %d " - "active %d ParallelGCThreads %u", - all_workers_active(), workers(), active_workers(), - ParallelGCThreads); -} - -// Create IdleGCTasks for inactive workers. -// Creates tasks in a ResourceArea and assumes -// an appropriate ResourceMark. -void GCTaskManager::task_idle_workers() { - { - int more_inactive_workers = 0; - { - // Stop any idle tasks from exiting their IdleGCTask's - // and get the count for additional IdleGCTask's under - // the GCTaskManager's monitor so that the "more_inactive_workers" - // count is correct. - MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - _wait_helper.set_should_wait(true); - // active_workers are a number being requested. idle_workers - // are the number currently idle. If all the workers are being - // requested to be active but some are already idle, reduce - // the number of active_workers to be consistent with the - // number of idle_workers. The idle_workers are stuck in - // idle tasks and will no longer be release (since a new GC - // is starting). Try later to release enough idle_workers - // to allow the desired number of active_workers. - more_inactive_workers = - created_workers() - active_workers() - idle_workers(); - if (more_inactive_workers < 0) { - int reduced_active_workers = active_workers() + more_inactive_workers; - update_active_workers(reduced_active_workers); - more_inactive_workers = 0; - } - log_trace(gc, task)("JT: %d workers %d active %d idle %d more %d", - Threads::number_of_non_daemon_threads(), - created_workers(), - active_workers(), - idle_workers(), - more_inactive_workers); - } - GCTaskQueue* q = GCTaskQueue::create(); - for(uint i = 0; i < (uint) more_inactive_workers; i++) { - q->enqueue(IdleGCTask::create_on_c_heap()); - increment_idle_workers(); - } - assert(created_workers() == active_workers() + idle_workers(), - "total workers should equal active + inactive"); - add_list(q); - // GCTaskQueue* q was created in a ResourceArea so a - // destroy() call is not needed. - } -} - -void GCTaskManager::release_idle_workers() { - { - MutexLocker ml(monitor(), - Mutex::_no_safepoint_check_flag); - _wait_helper.set_should_wait(false); - monitor()->notify_all(); - // Release monitor - } -} - -void GCTaskManager::print_task_time_stamps() { - if (!log_is_enabled(Debug, gc, task, time)) { - return; - } - uint num_thr = created_workers(); - for(uint i=0; i < num_thr; i++) { - GCTaskThread* t = thread(i); - t->print_task_time_stamps(); - } -} - -void GCTaskManager::print_threads_on(outputStream* st) { - uint num_thr = created_workers(); - for (uint i = 0; i < num_thr; i++) { - thread(i)->print_on(st); - st->cr(); - } -} - -void GCTaskManager::threads_do(ThreadClosure* tc) { - assert(tc != NULL, "Null ThreadClosure"); - uint num_thr = created_workers(); - for (uint i = 0; i < num_thr; i++) { - tc->do_thread(thread(i)); - } -} - -GCTaskThread* GCTaskManager::thread(uint which) { - assert(which < created_workers(), "index out of bounds"); - assert(_thread[which] != NULL, "shouldn't have null thread"); - return _thread[which]; -} - -void GCTaskManager::set_thread(uint which, GCTaskThread* value) { - // "_created_workers" may not have been updated yet so use workers() - assert(which < workers(), "index out of bounds"); - assert(value != NULL, "shouldn't have null thread"); - _thread[which] = value; -} - -void GCTaskManager::add_task(GCTask* task) { - assert(task != NULL, "shouldn't have null task"); - MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])", - p2i(task), GCTask::Kind::to_string(task->kind())); - } - queue()->enqueue(task); - // Notify with the lock held to avoid missed notifies. - if (TraceGCTaskManager) { - tty->print_cr(" GCTaskManager::add_task (%s)->notify_all", - monitor()->name()); - } - (void) monitor()->notify_all(); - // Release monitor(). -} - -void GCTaskManager::add_list(GCTaskQueue* list) { - assert(list != NULL, "shouldn't have null task"); - MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::add_list(%u)", list->length()); - } - queue()->enqueue(list); - // Notify with the lock held to avoid missed notifies. - if (TraceGCTaskManager) { - tty->print_cr(" GCTaskManager::add_list (%s)->notify_all", - monitor()->name()); - } - (void) monitor()->notify_all(); - // Release monitor(). -} - -// GC workers wait in get_task() for new work to be added -// to the GCTaskManager's queue. When new work is added, -// a notify is sent to the waiting GC workers which then -// compete to get tasks. If a GC worker wakes up and there -// is no work on the queue, it is given a noop_task to execute -// and then loops to find more work. - -GCTask* GCTaskManager::get_task(uint which) { - GCTask* result = NULL; - // Grab the queue lock. - MonitorLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - // Wait while the queue is block or - // there is nothing to do, except maybe release resources. - while (is_blocked() || - (queue()->is_empty() && !should_release_resources(which))) { - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::get_task(%u)" - " blocked: %s" - " empty: %s" - " release: %s", - which, - is_blocked() ? "true" : "false", - queue()->is_empty() ? "true" : "false", - should_release_resources(which) ? "true" : "false"); - tty->print_cr(" => (%s)->wait()", - monitor()->name()); - } - ml.wait(0); - } - // We've reacquired the queue lock here. - // Figure out which condition caused us to exit the loop above. - if (!queue()->is_empty()) { - if (UseGCTaskAffinity) { - result = queue()->dequeue(which); - } else { - result = queue()->dequeue(); - } - if (result->is_barrier_task()) { - assert(which != sentinel_worker(), - "blocker shouldn't be bogus"); - set_blocking_worker(which); - } - } else { - // The queue is empty, but we were woken up. - // Just hand back a Noop task, - // in case someone wanted us to release resources, or whatever. - result = noop_task(); - } - assert(result != NULL, "shouldn't have null task"); - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]", - which, p2i(result), GCTask::Kind::to_string(result->kind())); - tty->print_cr(" %s", result->name()); - } - if (!result->is_idle_task()) { - increment_busy_workers(); - increment_delivered_tasks(); - } - return result; - // Release monitor(). -} - -void GCTaskManager::note_completion(uint which) { - MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - if (TraceGCTaskManager) { - tty->print_cr("GCTaskManager::note_completion(%u)", which); - } - // If we are blocked, check if the completing thread is the blocker. - if (blocking_worker() == which) { - assert(blocking_worker() != sentinel_worker(), - "blocker shouldn't be bogus"); - increment_barriers(); - set_unblocked(); - } - increment_completed_tasks(); - uint active = decrement_busy_workers(); - if ((active == 0) && (queue()->is_empty())) { - increment_emptied_queue(); - if (TraceGCTaskManager) { - tty->print_cr(" GCTaskManager::note_completion(%u) done", which); - } - } - if (TraceGCTaskManager) { - tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", - which, monitor()->name()); - tty->print_cr(" " - " blocked: %s" - " empty: %s" - " release: %s", - is_blocked() ? "true" : "false", - queue()->is_empty() ? "true" : "false", - should_release_resources(which) ? "true" : "false"); - tty->print_cr(" " - " delivered: %u" - " completed: %u" - " barriers: %u" - " emptied: %u", - delivered_tasks(), - completed_tasks(), - barriers(), - emptied_queue()); - } - // Tell everyone that a task has completed. - (void) monitor()->notify_all(); - // Release monitor(). -} - -uint GCTaskManager::increment_busy_workers() { - assert(queue()->own_lock(), "don't own the lock"); - _busy_workers += 1; - return _busy_workers; -} - -uint GCTaskManager::decrement_busy_workers() { - assert(queue()->own_lock(), "don't own the lock"); - assert(_busy_workers > 0, "About to make a mistake"); - _busy_workers -= 1; - return _busy_workers; -} - -void GCTaskManager::release_all_resources() { - // If you want this to be done atomically, do it in a WaitForBarrierGCTask. - for (uint i = 0; i < created_workers(); i += 1) { - set_resource_flag(i, true); - } -} - -bool GCTaskManager::should_release_resources(uint which) { - // This can be done without a lock because each thread reads one element. - return resource_flag(which); -} - -void GCTaskManager::note_release(uint which) { - // This can be done without a lock because each thread writes one element. - set_resource_flag(which, false); -} - -// "list" contains tasks that are ready to execute. Those -// tasks are added to the GCTaskManager's queue of tasks and -// then the GC workers are notified that there is new work to -// do. -// -// Typically different types of tasks can be added to the "list". -// For example in PSScavenge OldToYoungRootsTask, SerialOldToYoungRootsTask, -// ScavengeRootsTask, and StealTask tasks are all added to the list -// and then the GC workers are notified of new work. The tasks are -// handed out in the order in which they are added to the list -// (although execution is not necessarily in that order). As long -// as any tasks are running the GCTaskManager will wait for execution -// to complete. GC workers that execute a stealing task remain in -// the stealing task until all stealing tasks have completed. The load -// balancing afforded by the stealing tasks work best if the stealing -// tasks are added last to the list. - -void GCTaskManager::execute_and_wait(GCTaskQueue* list) { - WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); - list->enqueue(fin); - // The barrier task will be read by one of the GC - // workers once it is added to the list of tasks. - // Be sure that is globally visible before the - // GC worker reads it (which is after the task is added - // to the list of tasks below). - OrderAccess::storestore(); - add_list(list); - fin->wait_for(true /* reset */); - // We have to release the barrier tasks! - WaitForBarrierGCTask::destroy(fin); -} - -bool GCTaskManager::resource_flag(uint which) { - assert(which < workers(), "index out of bounds"); - return _resource_flag[which]; -} - -void GCTaskManager::set_resource_flag(uint which, bool value) { - assert(which < workers(), "index out of bounds"); - _resource_flag[which] = value; -} - -// -// NoopGCTask -// - -NoopGCTask* NoopGCTask::create_on_c_heap() { - NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(); - return result; -} - -void NoopGCTask::destroy(NoopGCTask* that) { - if (that != NULL) { - that->destruct(); - FreeHeap(that); - } -} - -// This task should never be performing GC work that require -// a valid GC id. -NoopGCTask::NoopGCTask() : GCTask(GCTask::Kind::noop_task, GCId::undefined()) { } - -void NoopGCTask::destruct() { - // This has to know it's superclass structure, just like the constructor. - this->GCTask::destruct(); - // Nothing else to do. -} - -// -// IdleGCTask -// - -IdleGCTask* IdleGCTask::create() { - IdleGCTask* result = new IdleGCTask(false); - assert(UseDynamicNumberOfGCThreads, - "Should only be used with dynamic GC thread"); - return result; -} - -IdleGCTask* IdleGCTask::create_on_c_heap() { - IdleGCTask* result = new(ResourceObj::C_HEAP, mtGC) IdleGCTask(true); - assert(UseDynamicNumberOfGCThreads, - "Should only be used with dynamic GC thread"); - return result; -} - -void IdleGCTask::do_it(GCTaskManager* manager, uint which) { - WaitHelper* wait_helper = manager->wait_helper(); - log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask:::do_it() should_wait: %s", - p2i(this), wait_helper->should_wait() ? "true" : "false"); - - MonitorLocker ml(manager->monitor(), Mutex::_no_safepoint_check_flag); - log_trace(gc, task)("--- idle %d", which); - // Increment has to be done when the idle tasks are created. - // manager->increment_idle_workers(); - ml.notify_all(); - while (wait_helper->should_wait()) { - log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask::do_it() [" INTPTR_FORMAT "] (%s)->wait()", - p2i(this), p2i(manager->monitor()), manager->monitor()->name()); - ml.wait(0); - } - manager->decrement_idle_workers(); - - log_trace(gc, task)("--- release %d", which); - log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask::do_it() returns should_wait: %s", - p2i(this), wait_helper->should_wait() ? "true" : "false"); - // Release monitor(). -} - -void IdleGCTask::destroy(IdleGCTask* that) { - if (that != NULL) { - that->destruct(); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } - } -} - -void IdleGCTask::destruct() { - // This has to know it's superclass structure, just like the constructor. - this->GCTask::destruct(); - // Nothing else to do. -} - -// -// WaitForBarrierGCTask -// -WaitForBarrierGCTask* WaitForBarrierGCTask::create() { - WaitForBarrierGCTask* result = new WaitForBarrierGCTask(); - return result; -} - -WaitForBarrierGCTask::WaitForBarrierGCTask() : GCTask(GCTask::Kind::wait_for_barrier_task) { } - -void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { - if (that != NULL) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destroy()", p2i(that)); - } - that->destruct(); - } -} - -void WaitForBarrierGCTask::destruct() { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destruct()", p2i(this)); - } - this->GCTask::destruct(); - // Clean up that should be in the destructor, - // except that ResourceMarks don't call destructors. - _wait_helper.release_monitor(); -} - -void WaitForBarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { - // Wait for this to be the only busy worker. - assert(manager->monitor()->owned_by_self(), "don't own the lock"); - assert(manager->is_blocked(), "manager isn't blocked"); - while (manager->busy_workers() > 1) { - if (TraceGCTaskManager) { - tty->print_cr("WaitForBarrierGCTask::do_it(%u) waiting on %u workers", - which, manager->busy_workers()); - } - manager->monitor()->wait_without_safepoint_check(0); - } -} - -void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it() waiting for idle", - p2i(this)); - } - { - // First, wait for the barrier to arrive. - MutexLocker ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - // Release manager->lock(). - } - // Then notify the waiter. - _wait_helper.notify(); -} - -WaitHelper::WaitHelper() : _monitor(MonitorSupply::reserve()), _should_wait(true) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitHelper::WaitHelper()" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); - } -} - -void WaitHelper::release_monitor() { - assert(_monitor != NULL, ""); - MonitorSupply::release(_monitor); - _monitor = NULL; -} - -WaitHelper::~WaitHelper() { - release_monitor(); -} - -void WaitHelper::wait_for(bool reset) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::wait_for()" - " should_wait: %s", - p2i(this), should_wait() ? "true" : "false"); - } - { - // Grab the lock and check again. - MonitorLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - while (should_wait()) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::wait_for()" - " [" INTPTR_FORMAT "] (%s)->wait()", - p2i(this), p2i(monitor()), monitor()->name()); - } - ml.wait(0); - } - // Reset the flag in case someone reuses this task. - if (reset) { - set_should_wait(true); - } - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::wait_for() returns" - " should_wait: %s", - p2i(this), should_wait() ? "true" : "false"); - } - // Release monitor(). - } -} - -void WaitHelper::notify() { - MutexLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - set_should_wait(false); - // Waiter doesn't miss the notify in the wait_for method - // since it checks the flag after grabbing the monitor. - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it()" - " [" INTPTR_FORMAT "] (%s)->notify_all()", - p2i(this), p2i(monitor()), monitor()->name()); - } - monitor()->notify_all(); -} - -Mutex* MonitorSupply::_lock = NULL; -GrowableArray* MonitorSupply::_freelist = NULL; - -Monitor* MonitorSupply::reserve() { - Monitor* result = NULL; - // Lazy initialization: possible race. - if (lock() == NULL) { - _lock = new Mutex(Mutex::barrier, // rank - "MonitorSupply mutex", // name - Mutex::_allow_vm_block_flag); // allow_vm_block - } - { - MutexLocker ml(lock()); - // Lazy initialization. - if (freelist() == NULL) { - _freelist = - new(ResourceObj::C_HEAP, mtGC) GrowableArray(ParallelGCThreads, - true); - } - if (! freelist()->is_empty()) { - result = freelist()->pop(); - } else { - result = new Monitor(Mutex::barrier, // rank - "MonitorSupply monitor", // name - Mutex::_allow_vm_block_flag, // allow_vm_block - Monitor::_safepoint_check_never); - } - guarantee(result != NULL, "shouldn't return NULL"); - assert(!result->is_locked(), "shouldn't be locked"); - // release lock(). - } - return result; -} - -void MonitorSupply::release(Monitor* instance) { - assert(instance != NULL, "shouldn't release NULL"); - assert(!instance->is_locked(), "shouldn't be locked"); - { - MutexLocker ml(lock()); - freelist()->push(instance); - // release lock(). - } -} diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/gcTaskManager.hpp --- a/src/hotspot/share/gc/parallel/gcTaskManager.hpp Fri Aug 16 09:18:35 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,668 +0,0 @@ -/* - * Copyright (c) 2002, 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_GCTASKMANAGER_HPP -#define SHARE_GC_PARALLEL_GCTASKMANAGER_HPP - -#include "runtime/mutex.hpp" -#include "utilities/growableArray.hpp" - -// -// The GCTaskManager is a queue of GCTasks, and accessors -// to allow the queue to be accessed from many threads. -// - -// Forward declarations of types defined in this file. -class GCTask; -class GCTaskQueue; -class SynchronizedGCTaskQueue; -class GCTaskManager; -// Some useful subclasses of GCTask. You can also make up your own. -class NoopGCTask; -class WaitForBarrierGCTask; -class IdleGCTask; -// A free list of Monitor*'s. -class MonitorSupply; - -// Forward declarations of classes referenced in this file via pointer. -class GCTaskThread; -class Mutex; -class Monitor; -class ThreadClosure; - -// The abstract base GCTask. -class GCTask : public ResourceObj { -public: - // Known kinds of GCTasks, for predicates. - class Kind : AllStatic { - public: - enum kind { - unknown_task, - ordinary_task, - wait_for_barrier_task, - noop_task, - idle_task - }; - static const char* to_string(kind value); - }; -private: - // Instance state. - Kind::kind _kind; // For runtime type checking. - uint _affinity; // Which worker should run task. - GCTask* _newer; // Tasks are on doubly-linked ... - GCTask* _older; // ... lists. - uint _gc_id; // GC Id to use for the thread that executes this task -public: - virtual char* name() { return (char *)"task"; } - - uint gc_id() { return _gc_id; } - - // Abstract do_it method - virtual void do_it(GCTaskManager* manager, uint which) = 0; - // Accessors - Kind::kind kind() const { - return _kind; - } - uint affinity() const { - return _affinity; - } - GCTask* newer() const { - return _newer; - } - void set_newer(GCTask* n) { - _newer = n; - } - GCTask* older() const { - return _older; - } - void set_older(GCTask* p) { - _older = p; - } - // Predicates. - bool is_ordinary_task() const { - return kind()==Kind::ordinary_task; - } - bool is_barrier_task() const { - return kind()==Kind::wait_for_barrier_task; - } - bool is_noop_task() const { - return kind()==Kind::noop_task; - } - bool is_idle_task() const { - return kind()==Kind::idle_task; - } - void print(const char* message) const PRODUCT_RETURN; -protected: - // Constructors: Only create subclasses. - // An ordinary GCTask. - GCTask(); - // A GCTask of a particular kind, usually barrier or noop. - GCTask(Kind::kind kind); - GCTask(Kind::kind kind, uint gc_id); - // We want a virtual destructor because virtual methods, - // but since ResourceObj's don't have their destructors - // called, we don't have one at all. Instead we have - // this method, which gets called by subclasses to clean up. - virtual void destruct(); - // Methods. - void initialize(Kind::kind kind, uint gc_id); -}; - -// A doubly-linked list of GCTasks. -// The list is not synchronized, because sometimes we want to -// build up a list and then make it available to other threads. -// See also: SynchronizedGCTaskQueue. -class GCTaskQueue : public ResourceObj { -private: - // Instance state. - GCTask* _insert_end; // Tasks are enqueued at this end. - GCTask* _remove_end; // Tasks are dequeued from this end. - uint _length; // The current length of the queue. - const bool _is_c_heap_obj; // Is this a CHeapObj? -public: - // Factory create and destroy methods. - // Create as ResourceObj. - static GCTaskQueue* create(); - // Create as CHeapObj. - static GCTaskQueue* create_on_c_heap(); - // Destroyer. - static void destroy(GCTaskQueue* that); - // Accessors. - // These just examine the state of the queue. - bool is_empty() const { - assert(((insert_end() == NULL && remove_end() == NULL) || - (insert_end() != NULL && remove_end() != NULL)), - "insert_end and remove_end don't match"); - assert((insert_end() != NULL) || (_length == 0), "Not empty"); - return insert_end() == NULL; - } - uint length() const { - return _length; - } - // Methods. - // Enqueue one task. - void enqueue(GCTask* task); - // Enqueue a list of tasks. Empties the argument list. - void enqueue(GCTaskQueue* list); - // Dequeue one task. - GCTask* dequeue(); - // Dequeue one task, preferring one with affinity. - GCTask* dequeue(uint affinity); -protected: - // Constructor. Clients use factory, but there might be subclasses. - GCTaskQueue(bool on_c_heap); - // Destructor-like method. - // Because ResourceMark doesn't call destructors. - // This method cleans up like one. - virtual void destruct(); - // Accessors. - GCTask* insert_end() const { - return _insert_end; - } - void set_insert_end(GCTask* value) { - _insert_end = value; - } - GCTask* remove_end() const { - return _remove_end; - } - void set_remove_end(GCTask* value) { - _remove_end = value; - } - void increment_length() { - _length += 1; - } - void decrement_length() { - _length -= 1; - } - void set_length(uint value) { - _length = value; - } - bool is_c_heap_obj() const { - return _is_c_heap_obj; - } - // Methods. - void initialize(); - GCTask* remove(); // Remove from remove end. - GCTask* remove(GCTask* task); // Remove from the middle. - void print(const char* message) const PRODUCT_RETURN; - // Debug support - void verify_length() const PRODUCT_RETURN; -}; - -// A GCTaskQueue that can be synchronized. -// This "has-a" GCTaskQueue and a mutex to do the exclusion. -class SynchronizedGCTaskQueue : public CHeapObj { -private: - // Instance state. - GCTaskQueue* _unsynchronized_queue; // Has-a unsynchronized queue. - Monitor * _lock; // Lock to control access. -public: - // Factory create and destroy methods. - static SynchronizedGCTaskQueue* create(GCTaskQueue* queue, Monitor * lock) { - return new SynchronizedGCTaskQueue(queue, lock); - } - static void destroy(SynchronizedGCTaskQueue* that) { - if (that != NULL) { - delete that; - } - } - // Accessors - GCTaskQueue* unsynchronized_queue() const { - return _unsynchronized_queue; - } - Monitor * lock() const { - return _lock; - } - // GCTaskQueue wrapper methods. - // These check that you hold the lock - // and then call the method on the queue. - bool is_empty() const { - guarantee(own_lock(), "don't own the lock"); - return unsynchronized_queue()->is_empty(); - } - void enqueue(GCTask* task) { - guarantee(own_lock(), "don't own the lock"); - unsynchronized_queue()->enqueue(task); - } - void enqueue(GCTaskQueue* list) { - guarantee(own_lock(), "don't own the lock"); - unsynchronized_queue()->enqueue(list); - } - GCTask* dequeue() { - guarantee(own_lock(), "don't own the lock"); - return unsynchronized_queue()->dequeue(); - } - GCTask* dequeue(uint affinity) { - guarantee(own_lock(), "don't own the lock"); - return unsynchronized_queue()->dequeue(affinity); - } - uint length() const { - guarantee(own_lock(), "don't own the lock"); - return unsynchronized_queue()->length(); - } - // For guarantees. - bool own_lock() const { - return lock()->owned_by_self(); - } -protected: - // Constructor. Clients use factory, but there might be subclasses. - SynchronizedGCTaskQueue(GCTaskQueue* queue, Monitor * lock); - // Destructor. Not virtual because no virtuals. - ~SynchronizedGCTaskQueue(); -}; - -class WaitHelper { - private: - Monitor* _monitor; - volatile bool _should_wait; - public: - WaitHelper(); - ~WaitHelper(); - void wait_for(bool reset); - void notify(); - void set_should_wait(bool value) { - _should_wait = value; - } - - Monitor* monitor() const { - return _monitor; - } - bool should_wait() const { - return _should_wait; - } - void release_monitor(); -}; - -// Dynamic number of GC threads -// -// GC threads wait in get_task() for work (i.e., a task) to perform. -// When the number of GC threads was static, the number of tasks -// created to do a job was equal to or greater than the maximum -// number of GC threads (ParallelGCThreads). The job might be divided -// into a number of tasks greater than the number of GC threads for -// load balancing (i.e., over partitioning). The last task to be -// executed by a GC thread in a job is a work stealing task. A -// GC thread that gets a work stealing task continues to execute -// that task until the job is done. In the static number of GC threads -// case, tasks are added to a queue (FIFO). The work stealing tasks are -// the last to be added. Once the tasks are added, the GC threads grab -// a task and go. A single thread can do all the non-work stealing tasks -// and then execute a work stealing and wait for all the other GC threads -// to execute their work stealing task. -// In the dynamic number of GC threads implementation, idle-tasks are -// created to occupy the non-participating or "inactive" threads. An -// idle-task makes the GC thread wait on a barrier that is part of the -// GCTaskManager. The GC threads that have been "idled" in a IdleGCTask -// are released once all the active GC threads have finished their work -// stealing tasks. The GCTaskManager does not wait for all the "idled" -// GC threads to resume execution. When those GC threads do resume -// execution in the course of the thread scheduling, they call get_tasks() -// as all the other GC threads do. Because all the "idled" threads are -// not required to execute in order to finish a job, it is possible for -// a GC thread to still be "idled" when the next job is started. Such -// a thread stays "idled" for the next job. This can result in a new -// job not having all the expected active workers. For example if on -// job requests 4 active workers out of a total of 10 workers so the -// remaining 6 are "idled", if the next job requests 6 active workers -// but all 6 of the "idled" workers are still idle, then the next job -// will only get 4 active workers. -// The implementation for the parallel old compaction phase has an -// added complication. In the static case parold partitions the chunks -// ready to be filled into stacks, one for each GC thread. A GC thread -// executing a draining task (drains the stack of ready chunks) -// claims a stack according to it's id (the unique ordinal value assigned -// to each GC thread). In the dynamic case not all GC threads will -// actively participate so stacks with ready to fill chunks can only be -// given to the active threads. An initial implementation chose stacks -// number 1-n to get the ready chunks and required that GC threads -// 1-n be the active workers. This was undesirable because it required -// certain threads to participate. In the final implementation a -// list of stacks equal in number to the active workers are filled -// with ready chunks. GC threads that participate get a stack from -// the task (DrainStacksCompactionTask), empty the stack, and then add it to a -// recycling list at the end of the task. If the same GC thread gets -// a second task, it gets a second stack to drain and returns it. The -// stacks are added to a recycling list so that later stealing tasks -// for this tasks can get a stack from the recycling list. Stealing tasks -// use the stacks in its work in a way similar to the draining tasks. -// A thread is not guaranteed to get anything but a stealing task and -// a thread that only gets a stealing task has to get a stack. A failed -// implementation tried to have the GC threads keep the stack they used -// during a draining task for later use in the stealing task but that didn't -// work because as noted a thread is not guaranteed to get a draining task. -// -// For PSScavenge and ParCompactionManager the GC threads are -// held in the GCTaskThread** _thread array in GCTaskManager. - - -class GCTaskManager : public CHeapObj { - friend class ParCompactionManager; - friend class PSParallelCompact; - friend class PSScavenge; - friend class PSRefProcTaskExecutor; - friend class RefProcTaskExecutor; - friend class GCTaskThread; - friend class IdleGCTask; -private: - // Instance state. - const uint _workers; // Number of workers. - Monitor* _monitor; // Notification of changes. - SynchronizedGCTaskQueue* _queue; // Queue of tasks. - GCTaskThread** _thread; // Array of worker threads. - uint _created_workers; // Number of workers created. - uint _active_workers; // Number of active workers. - uint _busy_workers; // Number of busy workers. - uint _blocking_worker; // The worker that's blocking. - bool* _resource_flag; // Array of flag per threads. - uint _delivered_tasks; // Count of delivered tasks. - uint _completed_tasks; // Count of completed tasks. - uint _barriers; // Count of barrier tasks. - uint _emptied_queue; // Times we emptied the queue. - NoopGCTask* _noop_task; // The NoopGCTask instance. - WaitHelper _wait_helper; // Used by inactive worker - volatile uint _idle_workers; // Number of idled workers - uint* _processor_assignment; // Worker to cpu mappings. May - // be used lazily -public: - // Factory create and destroy methods. - static GCTaskManager* create(uint workers) { - return new GCTaskManager(workers); - } - static void destroy(GCTaskManager* that) { - if (that != NULL) { - delete that; - } - } - // Accessors. - uint busy_workers() const { - return _busy_workers; - } - volatile uint idle_workers() const { - return _idle_workers; - } - // Pun between Monitor* and Mutex* - Monitor* monitor() const { - return _monitor; - } - Monitor * lock() const { - return _monitor; - } - WaitHelper* wait_helper() { - return &_wait_helper; - } - // Methods. - // Add the argument task to be run. - void add_task(GCTask* task); - // Add a list of tasks. Removes task from the argument list. - void add_list(GCTaskQueue* list); - // Claim a task for argument worker. - GCTask* get_task(uint which); - // Note the completion of a task by the argument worker. - void note_completion(uint which); - // Is the queue blocked from handing out new tasks? - bool is_blocked() const { - return (blocking_worker() != sentinel_worker()); - } - // Request that all workers release their resources. - void release_all_resources(); - // Ask if a particular worker should release its resources. - bool should_release_resources(uint which); // Predicate. - // Note the release of resources by the argument worker. - void note_release(uint which); - // Create IdleGCTasks for inactive workers and start workers - void task_idle_workers(); - // Release the workers in IdleGCTasks - void release_idle_workers(); - // Constants. - // A sentinel worker identifier. - static uint sentinel_worker() { - return (uint) -1; // Why isn't there a max_uint? - } - - // Execute the task queue and wait for the completion. - void execute_and_wait(GCTaskQueue* list); - - void print_task_time_stamps(); - void print_threads_on(outputStream* st); - void threads_do(ThreadClosure* tc); - -protected: - // Constructors. Clients use factory, but there might be subclasses. - // Create a GCTaskManager with the appropriate number of workers. - GCTaskManager(uint workers); - // Make virtual if necessary. - ~GCTaskManager(); - // Accessors. - uint workers() const { - return _workers; - } - uint update_active_workers(uint v) { - assert(v <= _workers, "Trying to set more workers active than there are"); - _active_workers = MIN2(v, _workers); - assert(v != 0, "Trying to set active workers to 0"); - _active_workers = MAX2(1U, _active_workers); - return _active_workers; - } - // Sets the number of threads that will be used in a collection - void set_active_gang(); - - SynchronizedGCTaskQueue* queue() const { - return _queue; - } - NoopGCTask* noop_task() const { - return _noop_task; - } - // Bounds-checking per-thread data accessors. - GCTaskThread* thread(uint which); - void set_thread(uint which, GCTaskThread* value); - bool resource_flag(uint which); - void set_resource_flag(uint which, bool value); - // Modifier methods with some semantics. - // Is any worker blocking handing out new tasks? - uint blocking_worker() const { - return _blocking_worker; - } - void set_blocking_worker(uint value) { - _blocking_worker = value; - } - void set_unblocked() { - set_blocking_worker(sentinel_worker()); - } - // Count of busy workers. - void reset_busy_workers() { - _busy_workers = 0; - } - uint increment_busy_workers(); - uint decrement_busy_workers(); - // Count of tasks delivered to workers. - uint delivered_tasks() const { - return _delivered_tasks; - } - void increment_delivered_tasks() { - _delivered_tasks += 1; - } - void reset_delivered_tasks() { - _delivered_tasks = 0; - } - // Count of tasks completed by workers. - uint completed_tasks() const { - return _completed_tasks; - } - void increment_completed_tasks() { - _completed_tasks += 1; - } - void reset_completed_tasks() { - _completed_tasks = 0; - } - // Count of barrier tasks completed. - uint barriers() const { - return _barriers; - } - void increment_barriers() { - _barriers += 1; - } - void reset_barriers() { - _barriers = 0; - } - // Count of how many times the queue has emptied. - uint emptied_queue() const { - return _emptied_queue; - } - void increment_emptied_queue() { - _emptied_queue += 1; - } - void reset_emptied_queue() { - _emptied_queue = 0; - } - void increment_idle_workers() { - _idle_workers++; - } - void decrement_idle_workers() { - _idle_workers--; - } - // Other methods. - void initialize(); - - public: - // Return true if all workers are currently active. - bool all_workers_active() { return workers() == active_workers(); } - uint active_workers() const { - return _active_workers; - } - uint created_workers() const { - return _created_workers; - } - // Create a GC worker and install into GCTaskManager - GCTaskThread* install_worker(uint worker_id); - // Add GC workers as needed. - void add_workers(bool initializing); - // Base name (without worker id #) of threads. - const char* group_name(); -}; - -// -// Some exemplary GCTasks. -// - -// A noop task that does nothing, -// except take us around the GCTaskThread loop. -class NoopGCTask : public GCTask { -public: - // Factory create and destroy methods. - static NoopGCTask* create_on_c_heap(); - static void destroy(NoopGCTask* that); - - virtual char* name() { return (char *)"noop task"; } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which) { - // Nothing to do. - } -protected: - // Constructor. - NoopGCTask(); - // Destructor-like method. - void destruct(); -}; - -// A WaitForBarrierGCTask is a GCTask -// with a method you can call to wait until -// the BarrierGCTask is done. -class WaitForBarrierGCTask : public GCTask { - friend class GCTaskManager; - friend class IdleGCTask; -private: - // Instance state. - WaitHelper _wait_helper; - WaitForBarrierGCTask(); -public: - virtual char* name() { return (char *) "waitfor-barrier-task"; } - - // Factory create and destroy methods. - static WaitForBarrierGCTask* create(); - static void destroy(WaitForBarrierGCTask* that); - // Methods. - void do_it(GCTaskManager* manager, uint which); -protected: - // Destructor-like method. - void destruct(); - - // Methods. - // Wait for this to be the only task running. - void do_it_internal(GCTaskManager* manager, uint which); - - void wait_for(bool reset) { - _wait_helper.wait_for(reset); - } -}; - -// Task that is used to idle a GC task when fewer than -// the maximum workers are wanted. -class IdleGCTask : public GCTask { - const bool _is_c_heap_obj; // Was allocated on the heap. - public: - bool is_c_heap_obj() { - return _is_c_heap_obj; - } - // Factory create and destroy methods. - static IdleGCTask* create(); - static IdleGCTask* create_on_c_heap(); - static void destroy(IdleGCTask* that); - - virtual char* name() { return (char *)"idle task"; } - // Methods from GCTask. - virtual void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. - IdleGCTask(bool on_c_heap) : - GCTask(GCTask::Kind::idle_task), - _is_c_heap_obj(on_c_heap) { - // Nothing to do. - } - // Destructor-like method. - void destruct(); -}; - -class MonitorSupply : public AllStatic { -private: - // State. - // Control multi-threaded access. - static Mutex* _lock; - // The list of available Monitor*'s. - static GrowableArray* _freelist; -public: - // Reserve a Monitor*. - static Monitor* reserve(); - // Release a Monitor*. - static void release(Monitor* instance); -private: - // Accessors. - static Mutex* lock() { - return _lock; - } - static GrowableArray* freelist() { - return _freelist; - } -}; - -#endif // SHARE_GC_PARALLEL_GCTASKMANAGER_HPP diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/gcTaskThread.cpp --- a/src/hotspot/share/gc/parallel/gcTaskThread.cpp Fri Aug 16 09:18:35 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2002, 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. - * - */ - -#include "precompiled.hpp" -#include "gc/parallel/gcTaskManager.hpp" -#include "gc/parallel/gcTaskThread.hpp" -#include "gc/shared/gcId.hpp" -#include "logging/log.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" -#include "runtime/handles.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" - -GCTaskThread::GCTaskThread(GCTaskManager* manager, - uint which, - uint processor_id) : - _manager(manager), - _processor_id(processor_id), - _time_stamps(NULL), - _time_stamp_index(0) -{ - set_id(which); - set_name("%s#%d", manager->group_name(), which); -} - -GCTaskThread::~GCTaskThread() { - if (_time_stamps != NULL) { - FREE_C_HEAP_ARRAY(GCTaskTimeStamp, _time_stamps); - } -} - -void GCTaskThread::add_task_timestamp(const char* name, jlong t_entry, jlong t_exit) { - if (_time_stamp_index < GCTaskTimeStampEntries) { - GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index); - time_stamp->set_name(name); - time_stamp->set_entry_time(t_entry); - time_stamp->set_exit_time(t_exit); - } else { - if (_time_stamp_index == GCTaskTimeStampEntries) { - log_warning(gc, task, time)("GC-thread %u: Too many timestamps, ignoring future ones. " - "Increase GCTaskTimeStampEntries to get more info.", - id()); - } - // Let _time_stamp_index keep counting to give the user an idea about how many - // are needed. - } - _time_stamp_index++; -} - -GCTaskTimeStamp* GCTaskThread::time_stamp_at(uint index) { - assert(index < GCTaskTimeStampEntries, "Precondition"); - if (_time_stamps == NULL) { - // We allocate the _time_stamps array lazily since logging can be enabled dynamically - GCTaskTimeStamp* time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC); - if (!Atomic::replace_if_null(time_stamps, &_time_stamps)) { - // Someone already setup the time stamps - FREE_C_HEAP_ARRAY(GCTaskTimeStamp, time_stamps); - } - } - return &(_time_stamps[index]); -} - -void GCTaskThread::print_task_time_stamps() { - assert(log_is_enabled(Debug, gc, task, time), "Sanity"); - - // Since _time_stamps is now lazily allocated we need to check that it - // has in fact been allocated when calling this function. - if (_time_stamps != NULL) { - log_debug(gc, task, time)("GC-Thread %u entries: %d%s", id(), - _time_stamp_index, - _time_stamp_index >= GCTaskTimeStampEntries ? " (overflow)" : ""); - const uint max_index = MIN2(_time_stamp_index, GCTaskTimeStampEntries); - for (uint i = 0; i < max_index; i++) { - GCTaskTimeStamp* time_stamp = time_stamp_at(i); - log_debug(gc, task, time)("\t[ %s " JLONG_FORMAT " " JLONG_FORMAT " ]", - time_stamp->name(), - time_stamp->entry_time(), - time_stamp->exit_time()); - } - - // Reset after dumping the data - _time_stamp_index = 0; - } -} - -// GC workers get tasks from the GCTaskManager and execute -// them in this method. If there are no tasks to execute, -// the GC workers wait in the GCTaskManager's get_task() -// for tasks to be enqueued for execution. - -void GCTaskThread::run() { - // Bind yourself to your processor. - if (processor_id() != GCTaskManager::sentinel_worker()) { - log_trace(gc, task, thread)("GCTaskThread::run: binding to processor %u", processor_id()); - if (!os::bind_to_processor(processor_id())) { - DEBUG_ONLY( - log_warning(gc)("Couldn't bind GCTaskThread %u to processor %u", - which(), processor_id()); - ) - } - } - // Part of thread setup. - // ??? Are these set up once here to make subsequent ones fast? - HandleMark hm_outer; - ResourceMark rm_outer; - - TimeStamp timer; - - for (;/* ever */;) { - // These are so we can flush the resources allocated in the inner loop. - HandleMark hm_inner; - ResourceMark rm_inner; - for (; /* break */; ) { - // This will block until there is a task to be gotten. - GCTask* task = manager()->get_task(which()); - GCIdMark gc_id_mark(task->gc_id()); - // Record if this is an idle task for later use. - bool is_idle_task = task->is_idle_task(); - // In case the update is costly - if (log_is_enabled(Debug, gc, task, time)) { - timer.update(); - } - - jlong entry_time = timer.ticks(); - char* name = task->name(); - - // If this is the barrier task, it can be destroyed - // by the GC task manager once the do_it() executes. - task->do_it(manager(), which()); - - // Use the saved value of is_idle_task because references - // using "task" are not reliable for the barrier task. - if (!is_idle_task) { - manager()->note_completion(which()); - - if (log_is_enabled(Debug, gc, task, time)) { - timer.update(); - add_task_timestamp(name, entry_time, timer.ticks()); - } - } else { - // idle tasks complete outside the normal accounting - // so that a task can complete without waiting for idle tasks. - // They have to be terminated separately. - IdleGCTask::destroy((IdleGCTask*)task); - } - - // Check if we should release our inner resources. - if (manager()->should_release_resources(which())) { - manager()->note_release(which()); - break; - } - } - } -} diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/gcTaskThread.hpp --- a/src/hotspot/share/gc/parallel/gcTaskThread.hpp Fri Aug 16 09:18:35 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2002, 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_GCTASKTHREAD_HPP -#define SHARE_GC_PARALLEL_GCTASKTHREAD_HPP - -#include "runtime/thread.hpp" - -// Forward declarations of classes defined here. -class GCTaskThread; -class GCTaskTimeStamp; - -// Declarations of classes referenced in this file via pointer. -class GCTaskManager; - -class GCTaskThread : public WorkerThread { - friend class GCTaskManager; -private: - // Instance state. - GCTaskManager* _manager; // Manager for worker. - const uint _processor_id; // Which processor the worker is on. - - GCTaskTimeStamp* _time_stamps; - uint _time_stamp_index; - - GCTaskTimeStamp* time_stamp_at(uint index); - void add_task_timestamp(const char* name, jlong t_entry, jlong t_exit); - - // Factory create and destroy methods. - static GCTaskThread* create(GCTaskManager* manager, - uint which, - uint processor_id) { - return new GCTaskThread(manager, which, processor_id); - } - public: - - static void destroy(GCTaskThread* manager) { - if (manager != NULL) { - delete manager; - } - } - // Methods from Thread. - bool is_GC_task_thread() const { - return true; - } - virtual void run(); - - void print_task_time_stamps(); - -protected: - // Constructor. Clients use factory, but there could be subclasses. - GCTaskThread(GCTaskManager* manager, uint which, uint processor_id); - // Destructor: virtual destructor because of virtual methods. - virtual ~GCTaskThread(); - // Accessors. - GCTaskManager* manager() const { - return _manager; - } - uint which() const { - return id(); - } - uint processor_id() const { - return _processor_id; - } -}; - -class GCTaskTimeStamp : public CHeapObj -{ - private: - jlong _entry_time; - jlong _exit_time; - const char* _name; - - public: - jlong entry_time() { return _entry_time; } - jlong exit_time() { return _exit_time; } - const char* name() const { return _name; } - - void set_entry_time(jlong time) { _entry_time = time; } - void set_exit_time(jlong time) { _exit_time = time; } - void set_name(const char* name) { _name = name; } -}; - -#endif // SHARE_GC_PARALLEL_GCTASKTHREAD_HPP diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -28,7 +28,6 @@ #include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp" #include "gc/parallel/adjoiningVirtualSpaces.hpp" #include "gc/parallel/parallelArguments.hpp" -#include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psAdaptiveSizePolicy.hpp" @@ -59,7 +58,6 @@ PSOldGen* ParallelScavengeHeap::_old_gen = NULL; PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = NULL; PSGCAdaptivePolicyCounters* ParallelScavengeHeap::_gc_policy_counters = NULL; -GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL; jint ParallelScavengeHeap::initialize() { const size_t reserved_heap_size = ParallelArguments::heap_reserved_size_bytes(); @@ -116,9 +114,6 @@ _gc_policy_counters = new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 2, _size_policy); - // Set up the GCTaskManager - _gc_task_manager = GCTaskManager::create(ParallelGCThreads); - if (UseParallelOldGC && !PSParallelCompact::initialize()) { return JNI_ENOMEM; } @@ -605,11 +600,11 @@ } void ParallelScavengeHeap::gc_threads_do(ThreadClosure* tc) const { - PSScavenge::gc_task_manager()->threads_do(tc); + ParallelScavengeHeap::heap()->workers().threads_do(tc); } void ParallelScavengeHeap::print_gc_threads_on(outputStream* st) const { - PSScavenge::gc_task_manager()->print_threads_on(st); + ParallelScavengeHeap::heap()->workers().print_worker_threads_on(st); } void ParallelScavengeHeap::print_tracing_info() const { diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -45,7 +45,6 @@ class AdjoiningGenerations; class GCHeapSummary; -class GCTaskManager; class MemoryManager; class MemoryPool; class PSAdaptiveSizePolicy; @@ -69,9 +68,6 @@ AdjoiningGenerations* _gens; unsigned int _death_march_count; - // The task manager - static GCTaskManager* _gc_task_manager; - GCMemoryManager* _young_manager; GCMemoryManager* _old_manager; @@ -136,8 +132,6 @@ static ParallelScavengeHeap* heap(); - static GCTaskManager* const gc_task_manager() { return _gc_task_manager; } - CardTableBarrierSet* barrier_set(); PSCardTable* card_table(); diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/parallel_globals.hpp --- a/src/hotspot/share/gc/parallel/parallel_globals.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -62,12 +62,6 @@ "limiter (a number between 0-100)") \ range(0, 100) \ \ - develop(bool, TraceGCTaskManager, false, \ - "Trace actions of the GC task manager") \ - \ - develop(bool, TraceGCTaskQueue, false, \ - "Trace actions of the GC task queues") \ - \ develop(bool, TraceParallelOldGCMarkingPhase, false, \ "Trace marking phase in ParallelOldGC") \ \ diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psCardTable.cpp --- a/src/hotspot/share/gc/parallel/psCardTable.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psCardTable.hpp" diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psCardTable.hpp --- a/src/hotspot/share/gc/parallel/psCardTable.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -31,7 +31,6 @@ class MutableSpace; class ObjectStartArray; class PSPromotionManager; -class GCTaskQueue; class PSCardTable: public CardTable { private: diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psCompactionManager.cpp --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" -#include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/objectStartArray.hpp" #include "gc/parallel/parMarkBitMap.inline.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" @@ -68,12 +67,12 @@ } void ParCompactionManager::initialize(ParMarkBitMap* mbm) { - assert(PSParallelCompact::gc_task_manager() != NULL, + assert(ParallelScavengeHeap::heap() != NULL, "Needed for initialization"); _mark_bitmap = mbm; - uint parallel_gc_threads = PSParallelCompact::gc_task_manager()->workers(); + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); assert(_manager_array == NULL, "Attempt to initialize twice"); _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1, mtGC); @@ -100,12 +99,12 @@ _manager_array[parallel_gc_threads] = new ParCompactionManager(); guarantee(_manager_array[parallel_gc_threads] != NULL, "Could not create ParCompactionManager"); - assert(PSParallelCompact::gc_task_manager()->workers() != 0, + assert(ParallelScavengeHeap::heap()->workers().total_workers() != 0, "Not initialized?"); } void ParCompactionManager::reset_all_bitmap_query_caches() { - uint parallel_gc_threads = PSParallelCompact::gc_task_manager()->workers(); + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); for (uint i=0; i<=parallel_gc_threads; i++) { _manager_array[i]->reset_bitmap_query_cache(); } diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psCompactionManager.hpp --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -43,7 +43,6 @@ friend class CompactionWithStealingTask; friend class UpdateAndFillClosure; friend class RefProcTaskExecutor; - friend class IdleGCTask; friend class PCRefProcTask; friend class MarkFromRootsTask; friend class UpdateDensePrefixAndCompactionTask; diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psParallelCompact.cpp --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -30,7 +30,6 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" -#include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/parallelArguments.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/parMarkBitMap.inline.hpp" @@ -1018,9 +1017,6 @@ DEBUG_ONLY(mark_bitmap()->verify_clear();) DEBUG_ONLY(summary_data().verify_clear();) - // Have worker threads release resources the next time they run a task. - gc_task_manager()->release_all_resources(); - ParCompactionManager::reset_all_bitmap_query_caches(); } @@ -1785,7 +1781,7 @@ // Get the compaction manager reserved for the VM thread. ParCompactionManager* const vmthread_cm = - ParCompactionManager::manager_array(gc_task_manager()->workers()); + ParCompactionManager::manager_array(ParallelScavengeHeap::heap()->workers().total_workers()); { ResourceMark rm; @@ -1797,10 +1793,6 @@ Threads::number_of_non_daemon_threads()); ParallelScavengeHeap::heap()->workers().update_active_workers(active_workers); - // Set the number of GC threads to be used in this collection - gc_task_manager()->set_active_gang(); - gc_task_manager()->task_idle_workers(); - GCTraceCPUTime tcpu; GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause, true); @@ -1936,7 +1928,6 @@ // Track memory usage and detect low memory MemoryService::track_memory_usage(); heap->update_counters(); - gc_task_manager()->release_idle_workers(); heap->post_full_gc_dump(&_gc_timer); } @@ -1975,7 +1966,6 @@ log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, marking_start.ticks(), compaction_start.ticks(), collection_exit.ticks()); - gc_task_manager()->print_task_time_stamps(); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); @@ -1999,7 +1989,7 @@ assert(young_gen->virtual_space()->alignment() == old_gen->virtual_space()->alignment(), "alignments do not match"); - // We also return false when it's a heterogenous heap because old generation cannot absorb data from eden + // We also return false when it's a heterogeneous heap because old generation cannot absorb data from eden // when it is allocated on different memory (example, nv-dimm) than young. if (!(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary) || ParallelArguments::is_heterogeneous_heap()) { @@ -2080,12 +2070,6 @@ return true; } -GCTaskManager* const PSParallelCompact::gc_task_manager() { - assert(ParallelScavengeHeap::gc_task_manager() != NULL, - "shouldn't return NULL"); - return ParallelScavengeHeap::gc_task_manager(); -} - class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { private: uint _worker_id; @@ -2264,10 +2248,7 @@ GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - uint parallel_gc_threads = heap->gc_task_manager()->workers(); - uint active_gc_threads = heap->gc_task_manager()->active_workers(); - TaskQueueSetSuper* qset = ParCompactionManager::stack_array(); - TaskTerminator terminator(active_gc_threads, qset); + uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers(); PCMarkAndPushClosure mark_and_push_closure(cm); ParCompactionManager::FollowStackClosure follow_stack_closure(cm); diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psParallelCompact.hpp --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -40,8 +40,7 @@ class ParCompactionManager; class ParallelTaskTerminator; class PSParallelCompact; -class GCTaskManager; -class GCTaskQueue; +class PreGCValues; class MoveAndUpdateClosure; class RefProcTaskExecutor; class ParallelOldTracer; @@ -1114,9 +1113,6 @@ static unsigned int total_invocations() { return _total_invocations; } static CollectorCounters* counters() { return _counters; } - // Used to add tasks - static GCTaskManager* const gc_task_manager(); - // Marking support static inline bool mark_obj(oop obj); static inline bool is_marked(oop obj); diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psPromotionManager.cpp --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "classfile/javaClasses.inline.hpp" -#include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/mutableSpace.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/parallel/psOldGen.hpp" diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psScavenge.cpp --- a/src/hotspot/share/gc/parallel/psScavenge.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -27,7 +27,6 @@ #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" @@ -500,15 +499,6 @@ Threads::number_of_non_daemon_threads()); ParallelScavengeHeap::heap()->workers().update_active_workers(active_workers); - // 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(); - - assert(active_workers == gc_task_manager()->active_workers(), "sanity, taskmanager and workgang ought to agree"); - PSPromotionManager::pre_scavenge(); // We'll use the promotion manager again later. @@ -728,8 +718,6 @@ // 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) { @@ -745,7 +733,6 @@ 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(); @@ -823,13 +810,6 @@ 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) { diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/gc/parallel/psScavenge.hpp --- a/src/hotspot/share/gc/parallel/psScavenge.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -33,8 +33,6 @@ #include "oops/oop.hpp" #include "utilities/stack.hpp" -class GCTaskManager; -class GCTaskQueue; class OopStack; class ReferenceProcessor; class ParallelScavengeHeap; @@ -111,8 +109,6 @@ assert(_ref_processor != NULL, "Sanity"); return _ref_processor; } - // Used to add tasks - static GCTaskManager* const gc_task_manager(); // The promotion managers tell us if they encountered overflow static void set_survivor_overflow(bool state) { _survivor_overflow = state; diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/runtime/mutexLocker.cpp --- a/src/hotspot/share/runtime/mutexLocker.cpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/runtime/mutexLocker.cpp Fri Aug 16 09:18:38 2019 +0200 @@ -126,8 +126,6 @@ Mutex* OldSets_lock = NULL; Monitor* RootRegionScan_lock = NULL; -Monitor* GCTaskManager_lock = NULL; - Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; Monitor* PeriodicTask_lock = NULL; diff -r 2410b04f074f -r 5cbc3bd9fdfd src/hotspot/share/runtime/thread.hpp --- a/src/hotspot/share/runtime/thread.hpp Fri Aug 16 09:18:35 2019 +0200 +++ b/src/hotspot/share/runtime/thread.hpp Fri Aug 16 09:18:38 2019 +0200 @@ -83,7 +83,6 @@ class DeoptResourceMark; class jvmtiDeferredLocalVariableSet; -class GCTaskQueue; class ThreadClosure; class ICRefillVerifier; class IdealGraphPrinter; @@ -108,7 +107,6 @@ // - ConcurrentGCThread // - WorkerThread // - GangWorker -// - GCTaskThread // - WatcherThread // - JfrThreadSampler //