8224665: Parallel GC: Use WorkGang (7: remove task manager)
Reviewed-by: stefank, kbarrett, tschatzl
--- 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<Monitor*>* 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<Monitor*>(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().
- }
-}
--- 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<mtGC> {
-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<mtGC> {
- 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<Monitor*>* _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<Monitor*>* freelist() {
- return _freelist;
- }
-};
-
-#endif // SHARE_GC_PARALLEL_GCTASKMANAGER_HPP
--- 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;
- }
- }
- }
-}
--- 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<mtGC>
-{
- 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
--- 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 {
--- 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();
--- 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") \
\
--- 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"
--- 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:
--- 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();
}
--- 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;
--- 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);
--- 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);
--- 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"
--- 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) {
--- 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;
--- 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;
--- 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
//