--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/workerPolicy.cpp Fri Dec 07 12:46:31 2018 +0800
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, 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/shared/collectedHeap.hpp"
+#include "gc/shared/workerPolicy.hpp"
+#include "logging/log.hpp"
+#include "memory/universe.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/vm_version.hpp"
+
+bool WorkerPolicy::_debug_perturbation = false;
+uint WorkerPolicy::_parallel_worker_threads = 0;
+bool WorkerPolicy::_parallel_worker_threads_initialized = false;
+
+uint WorkerPolicy::nof_parallel_worker_threads(uint num,
+ uint den,
+ uint switch_pt) {
+ if (FLAG_IS_DEFAULT(ParallelGCThreads)) {
+ assert(ParallelGCThreads == 0, "Default ParallelGCThreads is not 0");
+ uint threads;
+ // For very large machines, there are diminishing returns
+ // for large numbers of worker threads. Instead of
+ // hogging the whole system, use a fraction of the workers for every
+ // processor after the first 8. For example, on a 72 cpu machine
+ // and a chosen fraction of 5/8
+ // use 8 + (72 - 8) * (5/8) == 48 worker threads.
+ uint ncpus = (uint) os::initial_active_processor_count();
+ threads = (ncpus <= switch_pt) ?
+ ncpus :
+ (switch_pt + ((ncpus - switch_pt) * num) / den);
+#ifndef _LP64
+ // On 32-bit binaries the virtual address space available to the JVM
+ // is usually limited to 2-3 GB (depends on the platform).
+ // Do not use up address space with too many threads (stacks and per-thread
+ // data). Note that x86 apps running on Win64 have 2 stacks per thread.
+ // GC may more generally scale down threads by max heap size (etc), but the
+ // consequences of over-provisioning threads are higher on 32-bit JVMS,
+ // so add hard limit here:
+ threads = MIN2(threads, (2 * switch_pt));
+#endif
+ return threads;
+ } else {
+ return ParallelGCThreads;
+ }
+}
+
+uint WorkerPolicy::calc_parallel_worker_threads() {
+ uint den = VM_Version::parallel_worker_threads_denominator();
+ return nof_parallel_worker_threads(5, den, 8);
+}
+
+uint WorkerPolicy::parallel_worker_threads() {
+ if (!_parallel_worker_threads_initialized) {
+ if (FLAG_IS_DEFAULT(ParallelGCThreads)) {
+ _parallel_worker_threads = WorkerPolicy::calc_parallel_worker_threads();
+ } else {
+ _parallel_worker_threads = ParallelGCThreads;
+ }
+ _parallel_worker_threads_initialized = true;
+ }
+ return _parallel_worker_threads;
+}
+
+// If the number of GC threads was set on the command line, use it.
+// Else
+// Calculate the number of GC threads based on the number of Java threads.
+// Calculate the number of GC threads based on the size of the heap.
+// Use the larger.
+uint WorkerPolicy::calc_default_active_workers(uintx total_workers,
+ const uintx min_workers,
+ uintx active_workers,
+ uintx application_workers) {
+ // If the user has specifically set the number of GC threads, use them.
+
+ // If the user has turned off using a dynamic number of GC threads
+ // or the users has requested a specific number, set the active
+ // number of workers to all the workers.
+
+ uintx new_active_workers = total_workers;
+ uintx prev_active_workers = active_workers;
+ uintx active_workers_by_JT = 0;
+ uintx active_workers_by_heap_size = 0;
+
+ // Always use at least min_workers but use up to
+ // GCThreadsPerJavaThreads * application threads.
+ active_workers_by_JT =
+ MAX2((uintx) GCWorkersPerJavaThread * application_workers,
+ min_workers);
+
+ // Choose a number of GC threads based on the current size
+ // of the heap. This may be complicated because the size of
+ // the heap depends on factors such as the throughput goal.
+ // Still a large heap should be collected by more GC threads.
+ active_workers_by_heap_size =
+ MAX2((size_t) 2U, Universe::heap()->capacity() / HeapSizePerGCThread);
+
+ uintx max_active_workers =
+ MAX2(active_workers_by_JT, active_workers_by_heap_size);
+
+ new_active_workers = MIN2(max_active_workers, (uintx) total_workers);
+
+ // Increase GC workers instantly but decrease them more
+ // slowly.
+ if (new_active_workers < prev_active_workers) {
+ new_active_workers =
+ MAX2(min_workers, (prev_active_workers + new_active_workers) / 2);
+ }
+
+ // Check once more that the number of workers is within the limits.
+ assert(min_workers <= total_workers, "Minimum workers not consistent with total workers");
+ assert(new_active_workers >= min_workers, "Minimum workers not observed");
+ assert(new_active_workers <= total_workers, "Total workers not observed");
+
+ if (ForceDynamicNumberOfGCThreads) {
+ // Assume this is debugging and jiggle the number of GC threads.
+ if (new_active_workers == prev_active_workers) {
+ if (new_active_workers < total_workers) {
+ new_active_workers++;
+ } else if (new_active_workers > min_workers) {
+ new_active_workers--;
+ }
+ }
+ if (new_active_workers == total_workers) {
+ if (_debug_perturbation) {
+ new_active_workers = min_workers;
+ }
+ _debug_perturbation = !_debug_perturbation;
+ }
+ assert((new_active_workers <= ParallelGCThreads) &&
+ (new_active_workers >= min_workers),
+ "Jiggled active workers too much");
+ }
+
+ log_trace(gc, task)("WorkerPolicy::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,
+ active_workers, new_active_workers, prev_active_workers,
+ active_workers_by_JT, active_workers_by_heap_size);
+ assert(new_active_workers > 0, "Always need at least 1");
+ return new_active_workers;
+}
+
+uint WorkerPolicy::calc_active_workers(uintx total_workers,
+ uintx active_workers,
+ uintx application_workers) {
+ // If the user has specifically set the number of GC threads, use them.
+
+ // If the user has turned off using a dynamic number of GC threads
+ // or the users has requested a specific number, set the active
+ // number of workers to all the workers.
+
+ uint new_active_workers;
+ if (!UseDynamicNumberOfGCThreads ||
+ (!FLAG_IS_DEFAULT(ParallelGCThreads) && !ForceDynamicNumberOfGCThreads)) {
+ new_active_workers = total_workers;
+ } else {
+ uintx min_workers = (total_workers == 1) ? 1 : 2;
+ new_active_workers = calc_default_active_workers(total_workers,
+ min_workers,
+ active_workers,
+ application_workers);
+ }
+ assert(new_active_workers > 0, "Always need at least 1");
+ return new_active_workers;
+}
+
+uint WorkerPolicy::calc_active_conc_workers(uintx total_workers,
+ uintx active_workers,
+ uintx application_workers) {
+ if (!UseDynamicNumberOfGCThreads ||
+ (!FLAG_IS_DEFAULT(ConcGCThreads) && !ForceDynamicNumberOfGCThreads)) {
+ return ConcGCThreads;
+ } else {
+ uint no_of_gc_threads = calc_default_active_workers(total_workers,
+ 1, /* Minimum number of workers */
+ active_workers,
+ application_workers);
+ return no_of_gc_threads;
+ }
+}