--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Thu Aug 06 22:07:30 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -25,8 +25,8 @@
#include "precompiled.hpp"
#include "gc/parallel/gcTaskManager.hpp"
#include "gc/parallel/gcTaskThread.hpp"
-#include "gc/shared/adaptiveSizePolicy.hpp"
#include "gc/shared/gcId.hpp"
+#include "gc/shared/workerManager.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
@@ -34,6 +34,7 @@
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.inline.hpp"
+#include "runtime/os.hpp"
//
// GCTask
@@ -372,10 +373,28 @@
GCTaskManager::GCTaskManager(uint workers) :
_workers(workers),
_active_workers(0),
- _idle_workers(0) {
+ _idle_workers(0),
+ _created_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;
+ _created_workers = WorkerManager::add_workers(this,
+ _active_workers,
+ (uint) _workers,
+ _created_workers,
+ worker_type,
+ initializing);
+ _active_workers = MIN2(_created_workers, _active_workers);
+}
+
void GCTaskManager::initialize() {
if (TraceGCTaskManager) {
tty->print_cr("GCTaskManager::initialize: workers: %u", workers());
@@ -394,28 +413,30 @@
// 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.
- uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers(), mtGC);
+ _processor_assignment = NEW_C_HEAP_ARRAY(uint, workers(), mtGC);
if (!BindGCTaskThreadsToCPUs ||
- !os::distribute_processes(workers(), processor_assignment)) {
+ !os::distribute_processes(workers(), _processor_assignment)) {
for (uint a = 0; a < workers(); a += 1) {
- processor_assignment[a] = sentinel_worker();
+ _processor_assignment[a] = sentinel_worker();
}
}
+
_thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers(), mtGC);
- for (uint t = 0; t < workers(); t += 1) {
- set_thread(t, GCTaskThread::create(this, t, processor_assignment[t]));
+ _active_workers = ParallelGCThreads;
+ if (UseDynamicNumberOfGCThreads && !FLAG_IS_CMDLINE(ParallelGCThreads)) {
+ _active_workers = 1U;
}
+
Log(gc, task, thread) log;
if (log.is_trace()) {
ResourceMark rm;
outputStream* out = log.trace_stream();
out->print("GCTaskManager::initialize: distribution:");
for (uint t = 0; t < workers(); t += 1) {
- out->print(" %u", processor_assignment[t]);
+ out->print(" %u", _processor_assignment[t]);
}
out->cr();
}
- FREE_C_HEAP_ARRAY(uint, processor_assignment);
}
reset_busy_workers();
set_unblocked();
@@ -426,9 +447,8 @@
reset_completed_tasks();
reset_barriers();
reset_emptied_queue();
- for (uint s = 0; s < workers(); s += 1) {
- thread(s)->start();
- }
+
+ add_workers(true);
}
GCTaskManager::~GCTaskManager() {
@@ -437,13 +457,17 @@
NoopGCTask::destroy(_noop_task);
_noop_task = NULL;
if (_thread != NULL) {
- for (uint i = 0; i < workers(); i += 1) {
+ 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;
@@ -470,6 +494,9 @@
"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",
@@ -499,7 +526,7 @@
// is starting). Try later to release enough idle_workers
// to allow the desired number of active_workers.
more_inactive_workers =
- workers() - active_workers() - idle_workers();
+ created_workers() - active_workers() - idle_workers();
if (more_inactive_workers < 0) {
int reduced_active_workers = active_workers() + more_inactive_workers;
set_active_workers(reduced_active_workers);
@@ -507,7 +534,7 @@
}
log_trace(gc, task)("JT: %d workers %d active %d idle %d more %d",
Threads::number_of_non_daemon_threads(),
- workers(),
+ created_workers(),
active_workers(),
idle_workers(),
more_inactive_workers);
@@ -517,7 +544,7 @@
q->enqueue(IdleGCTask::create_on_c_heap());
increment_idle_workers();
}
- assert(workers() == active_workers() + 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
@@ -539,14 +566,15 @@
if (!log_is_enabled(Debug, gc, task, time)) {
return;
}
- for(uint i=0; i<ParallelGCThreads; i++) {
+ 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 = workers();
+ uint num_thr = created_workers();
for (uint i = 0; i < num_thr; i++) {
thread(i)->print_on(st);
st->cr();
@@ -555,19 +583,20 @@
void GCTaskManager::threads_do(ThreadClosure* tc) {
assert(tc != NULL, "Null ThreadClosure");
- uint num_thr = workers();
+ 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 < workers(), "index out of bounds");
+ 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;
@@ -728,7 +757,7 @@
void GCTaskManager::release_all_resources() {
// If you want this to be done atomically, do it in a WaitForBarrierGCTask.
- for (uint i = 0; i < workers(); i += 1) {
+ for (uint i = 0; i < created_workers(); i += 1) {
set_resource_flag(i, true);
}
}
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Thu Aug 06 22:07:30 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -370,6 +370,7 @@
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.
@@ -381,6 +382,8 @@
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) {
@@ -546,6 +549,13 @@
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);
};
//
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Thu Aug 06 22:07:30 2015 -0700
@@ -44,9 +44,6 @@
_time_stamps(NULL),
_time_stamp_index(0)
{
- if (!os::create_thread(this, os::pgc_thread))
- vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GC thread. Out of system resources.");
-
set_id(which);
set_name("ParGC Thread#%d", which);
}
@@ -57,10 +54,6 @@
}
}
-void GCTaskThread::start() {
- os::start_thread(this);
-}
-
GCTaskTimeStamp* GCTaskThread::time_stamp_at(uint index) {
guarantee(index < GCTaskTimeStampEntries, "increase GCTaskTimeStampEntries");
if (_time_stamps == NULL) {
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp Thu Aug 06 22:07:30 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -48,13 +48,13 @@
bool _is_working; // True if participating in GC tasks
- public:
// 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;
@@ -65,8 +65,6 @@
return true;
}
virtual void run();
- // Methods.
- void start();
void print_task_time_stamps();
--- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp Thu Aug 06 22:07:30 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, 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
@@ -130,10 +130,7 @@
uintx max_active_workers =
MAX2(active_workers_by_JT, active_workers_by_heap_size);
- // Limit the number of workers to the the number created,
- // (workers()).
- new_active_workers = MIN2(max_active_workers,
- (uintx) total_workers);
+ new_active_workers = MIN2(max_active_workers, (uintx) total_workers);
// Increase GC workers instantly but decrease them more
// slowly.
@@ -167,7 +164,7 @@
"Jiggled active workers too much");
}
- log_trace(gc, task)("GCTaskManager::calc_default_active_workers() : "
+ log_trace(gc, task)("GCTaskManager::calc_default_active_workers() : "
"active_workers(): " UINTX_FORMAT " new_active_workers: " UINTX_FORMAT " "
"prev_active_workers: " UINTX_FORMAT "\n"
" active_workers_by_JT: " UINTX_FORMAT " active_workers_by_heap_size: " UINTX_FORMAT,
--- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp Thu Aug 06 22:07:30 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/workerManager.hpp Thu Aug 06 22:07:30 2015 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 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_VM_GC_SHARED_WORKERMANAGER_HPP
+#define SHARE_VM_GC_SHARED_WORKERMANAGER_HPP
+
+#include "gc/shared/adaptiveSizePolicy.hpp"
+
+class WorkerManager : public AllStatic {
+ public:
+ // Create additional workers as needed.
+ // active_workers - number of workers being requested for an upcoming
+ // parallel task.
+ // total_workers - total number of workers. This is the maximum
+ // number possible.
+ // created_workers - number of workers already created. This maybe
+ // less than, equal to, or greater than active workers. If greater than
+ // or equal to active_workers, nothing is done.
+ // worker_type - type of thread.
+ // initializing - true if this is called to get the initial number of
+ // GC workers.
+ // If initializing is true, do a vm exit if the workers cannot be created.
+ // The initializing = true case is for JVM start up and failing to
+ // create all the worker at start should considered a problem so exit.
+ // If initializing = false, there are already some number of worker
+ // threads and a failure would not be optimal but should not be fatal.
+ template <class WorkerType>
+ static uint add_workers (WorkerType* holder,
+ uint active_workers,
+ uint total_workers,
+ uint created_workers,
+ os::ThreadType worker_type,
+ bool initializing) {
+ uint start = created_workers;
+ uint end = MIN2(active_workers, total_workers);
+ for (uint worker_id = start; worker_id < end; worker_id += 1) {
+ WorkerThread* new_worker = holder->install_worker(worker_id);
+ assert(new_worker != NULL, "Failed to allocate GangWorker");
+ if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
+ if(initializing) {
+ vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
+ "Cannot create worker GC thread. Out of system resources.");
+ }
+ }
+ created_workers++;
+ os::start_thread(new_worker);
+ }
+
+ log_trace(gc, task)("AdaptiveSizePolicy::add_workers() : "
+ "active_workers: %u created_workers: %u",
+ active_workers, created_workers);
+
+ return created_workers;
+ }
+};
+#endif // SHARE_VM_GC_SHARED_WORKERMANAGER_HPP
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Aug 06 22:07:30 2015 -0700
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/workgroup.hpp"
+#include "gc/shared/workerManager.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/atomic.inline.hpp"
@@ -35,37 +36,45 @@
// Definitions of WorkGang methods.
// The current implementation will exit if the allocation
-// of any worker fails. Still, return a boolean so that
-// a future implementation can possibly do a partial
-// initialization of the workers and report such to the
-// caller.
-bool AbstractWorkGang::initialize_workers() {
+// of any worker fails.
+void AbstractWorkGang::initialize_workers() {
log_develop_trace(gc, workgang)("Constructing work gang %s with %u threads", name(), total_workers());
_workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
if (_workers == NULL) {
vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
- return false;
+ }
+
+ _active_workers = ParallelGCThreads;
+ if (UseDynamicNumberOfGCThreads && !FLAG_IS_CMDLINE(ParallelGCThreads)) {
+ _active_workers = 1U;
}
+
+ add_workers(true);
+}
+
+
+AbstractGangWorker* AbstractWorkGang::install_worker(uint worker_id) {
+ AbstractGangWorker* new_worker = allocate_worker(worker_id);
+ set_thread(worker_id, new_worker);
+ return new_worker;
+}
+
+void AbstractWorkGang::add_workers(bool initializing) {
+
os::ThreadType worker_type;
if (are_ConcurrentGC_threads()) {
worker_type = os::cgc_thread;
} else {
worker_type = os::pgc_thread;
}
- for (uint worker = 0; worker < total_workers(); worker += 1) {
- AbstractGangWorker* new_worker = allocate_worker(worker);
- assert(new_worker != NULL, "Failed to allocate GangWorker");
- _workers[worker] = new_worker;
- if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
- vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
- "Cannot create worker GC thread. Out of system resources.");
- return false;
- }
- if (!DisableStartThread) {
- os::start_thread(new_worker);
- }
- }
- return true;
+
+ _created_workers = WorkerManager::add_workers(this,
+ _active_workers,
+ _total_workers,
+ _created_workers,
+ worker_type,
+ initializing);
+ _active_workers = MIN2(_created_workers, _active_workers);
}
AbstractGangWorker* AbstractWorkGang::worker(uint i) const {
@@ -79,7 +88,7 @@
}
void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
- uint workers = total_workers();
+ uint workers = created_workers();
for (uint i = 0; i < workers; i++) {
worker(i)->print_on(st);
st->cr();
@@ -88,7 +97,7 @@
void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
assert(tc != NULL, "Null ThreadClosure");
- uint workers = total_workers();
+ uint workers = created_workers();
for (uint i = 0; i < workers; i++) {
tc->do_thread(worker(i));
}
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Apr 28 15:40:45 2016 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Aug 06 22:07:30 2015 -0700
@@ -112,6 +112,8 @@
uint _total_workers;
// The currently active workers in this gang.
uint _active_workers;
+ // The count of created workers in the gang.
+ uint _created_workers;
// Printing support.
const char* _name;
@@ -120,23 +122,32 @@
const bool _are_GC_task_threads;
const bool _are_ConcurrentGC_threads;
+ void set_thread(uint worker_id, AbstractGangWorker* worker) {
+ _workers[worker_id] = worker;
+ }
+
public:
AbstractWorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) :
_name(name),
_total_workers(workers),
_active_workers(UseDynamicNumberOfGCThreads ? 1U : workers),
+ _created_workers(0),
_are_GC_task_threads(are_GC_task_threads),
_are_ConcurrentGC_threads(are_ConcurrentGC_threads)
{ }
// Initialize workers in the gang. Return true if initialization succeeded.
- bool initialize_workers();
+ void initialize_workers();
bool are_GC_task_threads() const { return _are_GC_task_threads; }
bool are_ConcurrentGC_threads() const { return _are_ConcurrentGC_threads; }
uint total_workers() const { return _total_workers; }
+ uint created_workers() const {
+ return _created_workers;
+ }
+
virtual uint active_workers() const {
assert(_active_workers <= _total_workers,
"_active_workers: %u > _total_workers: %u", _active_workers, _total_workers);
@@ -144,22 +155,29 @@
"Unless dynamic should use total workers");
return _active_workers;
}
+
void set_active_workers(uint v) {
assert(v <= _total_workers,
"Trying to set more workers active than there are");
_active_workers = MIN2(v, _total_workers);
+ add_workers(false /* exit_on_failure */);
assert(v != 0, "Trying to set active workers to 0");
- _active_workers = MAX2(1U, _active_workers);
assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers,
"Unless dynamic should use total workers");
log_info(gc, task)("GC Workers: using %d out of %d", _active_workers, _total_workers);
}
+ // Add GC workers as needed.
+ void add_workers(bool initializing);
+
// Return the Ith worker.
AbstractGangWorker* worker(uint i) const;
void threads_do(ThreadClosure* tc) const;
+ // Create a GC worker and install it into the work gang.
+ virtual AbstractGangWorker* install_worker(uint which);
+
// Debugging.
const char* name() const { return _name; }