diff -r 535144bfa542 -r d2f118d3f8e7 src/hotspot/share/gc/shared/workerPolicy.cpp --- /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; + } +}