< prev index next >
src/hotspot/share/compiler/compileBroker.cpp
Print this page
rev 49521 : 8198756: Lazy allocation of compiler threads
Reviewed-by: kvn
*** 48,57 ****
--- 48,58 ----
#include "runtime/atomic.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaCalls.hpp"
+ #include "runtime/jniHandles.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/timerTrace.hpp"
*** 115,124 ****
--- 116,136 ----
volatile jint CompileBroker::_should_compile_new_jobs = run_compilation;
// The installed compiler(s)
AbstractCompiler* CompileBroker::_compilers[2];
+ // The maximum numbers of compiler threads to be determined during startup.
+ int CompileBroker::_c1_count = 0;
+ int CompileBroker::_c2_count = 0;
+
+ // An array of compiler names as Java String objects
+ jobject* CompileBroker::_compiler1_objects = NULL;
+ jobject* CompileBroker::_compiler2_objects = NULL;
+
+ CompileLog** CompileBroker::_compiler1_logs = NULL;
+ CompileLog** CompileBroker::_compiler2_logs = NULL;
+
// These counters are used to assign an unique ID to each compilation.
volatile jint CompileBroker::_compilation_id = 0;
volatile jint CompileBroker::_osr_compilation_id = 0;
// Debugging information
*** 285,294 ****
--- 297,331 ----
CompileTask::free(task);
}
}
/**
+ * Check if a CompilerThread can be removed and update count if requested.
+ */
+ static bool can_remove(CompilerThread *ct, bool do_it) {
+ assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
+ AbstractCompiler *compiler = ct->compiler();
+ int compiler_count = compiler->num_compiler_threads();
+ // Keep at least 1 compiler thread of each type.
+ if (compiler_count < 2) return false;
+ // Keep alive for at least some time.
+ if (ct->idle_time_millis() < 500) return false;
+
+ // We only allow the last compiler thread of each type to get removed.
+ jobject last_compiler = (compiler->is_c1()) ? CompileBroker::compiler1_object(compiler_count - 1)
+ : CompileBroker::compiler2_object(compiler_count - 1);
+ if (ct->threadObj() == JNIHandles::resolve_non_null(last_compiler)) {
+ if (do_it) {
+ assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
+ compiler->set_num_compiler_threads(compiler_count - 1);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Add a CompileTask to a CompileQueue.
*/
void CompileQueue::add(CompileTask* task) {
assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
*** 381,390 ****
--- 418,432 ----
// code cache if it is unnecessary.
// We need a timed wait here, since compiler threads can exit if compilation
// is disabled forever. We use 5 seconds wait time; the exiting of compiler threads
// is not critical and we do not want idle compiler threads to wake up too often.
MethodCompileQueue_lock->wait(!Mutex::_no_safepoint_check_flag, 5*1000);
+
+ if (UseDynamicNumberOfCompilerThreads && _first == NULL) {
+ // Still nothing to compile. Give caller a chance to stop this thread.
+ if (can_remove(CompilerThread::current(), false)) return NULL;
+ }
}
if (CompileBroker::is_compilation_disabled_forever()) {
return NULL;
}
*** 530,541 ****
// No need to initialize compilation system if we do not use it.
if (!UseCompiler) {
return;
}
// Set the interface to the current compiler(s).
! int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
! int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
#if INCLUDE_JVMCI
if (EnableJVMCI) {
// This is creating a JVMCICompiler singleton.
JVMCICompiler* jvmci = new JVMCICompiler();
--- 572,583 ----
// No need to initialize compilation system if we do not use it.
if (!UseCompiler) {
return;
}
// Set the interface to the current compiler(s).
! _c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
! _c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
#if INCLUDE_JVMCI
if (EnableJVMCI) {
// This is creating a JVMCICompiler singleton.
JVMCICompiler* jvmci = new JVMCICompiler();
*** 543,581 ****
if (UseJVMCICompiler) {
_compilers[1] = jvmci;
if (FLAG_IS_DEFAULT(JVMCIThreads)) {
if (BootstrapJVMCI) {
// JVMCI will bootstrap so give it more threads
! c2_count = MIN2(32, os::active_processor_count());
}
} else {
! c2_count = JVMCIThreads;
}
if (FLAG_IS_DEFAULT(JVMCIHostThreads)) {
} else {
! c1_count = JVMCIHostThreads;
}
}
}
#endif // INCLUDE_JVMCI
#ifdef COMPILER1
! if (c1_count > 0) {
_compilers[0] = new Compiler();
}
#endif // COMPILER1
#ifdef COMPILER2
if (true JVMCI_ONLY( && !UseJVMCICompiler)) {
! if (c2_count > 0) {
_compilers[1] = new C2Compiler();
}
}
#endif // COMPILER2
// Start the compiler thread(s) and the sweeper thread
! init_compiler_sweeper_threads(c1_count, c2_count);
// totalTime performance counter is always created as it is required
// by the implementation of java.lang.management.CompilationMBean.
{
EXCEPTION_MARK;
_perf_total_compilation =
--- 585,623 ----
if (UseJVMCICompiler) {
_compilers[1] = jvmci;
if (FLAG_IS_DEFAULT(JVMCIThreads)) {
if (BootstrapJVMCI) {
// JVMCI will bootstrap so give it more threads
! _c2_count = MIN2(32, os::active_processor_count());
}
} else {
! _c2_count = JVMCIThreads;
}
if (FLAG_IS_DEFAULT(JVMCIHostThreads)) {
} else {
! _c1_count = JVMCIHostThreads;
}
}
}
#endif // INCLUDE_JVMCI
#ifdef COMPILER1
! if (_c1_count > 0) {
_compilers[0] = new Compiler();
}
#endif // COMPILER1
#ifdef COMPILER2
if (true JVMCI_ONLY( && !UseJVMCICompiler)) {
! if (_c2_count > 0) {
_compilers[1] = new C2Compiler();
}
}
#endif // COMPILER2
// Start the compiler thread(s) and the sweeper thread
! init_compiler_sweeper_threads();
// totalTime performance counter is always created as it is required
// by the implementation of java.lang.management.CompilationMBean.
{
EXCEPTION_MARK;
_perf_total_compilation =
*** 677,709 ****
// prior to this will be silently ignored.
void CompileBroker::compilation_init_phase2() {
_initialized = true;
}
! JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, CompilerCounters* counters,
! AbstractCompiler* comp, bool compiler_thread, TRAPS) {
! JavaThread* thread = NULL;
! Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_0);
InstanceKlass* klass = InstanceKlass::cast(k);
! instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_0);
! Handle string = java_lang_String::create_from_str(name, CHECK_0);
// Initialize thread_oop to put it into the system threadGroup
! Handle thread_group (THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
! JavaCalls::call_special(&result, thread_oop,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
! CHECK_0);
{
MutexLocker mu(Threads_lock, THREAD);
if (compiler_thread) {
thread = new CompilerThread(queue, counters);
} else {
thread = new CodeCacheSweeperThread();
}
// At this point the new CompilerThread data-races with this startup
// thread (which I believe is the primoridal thread and NOT the VM
--- 719,760 ----
// prior to this will be silently ignored.
void CompileBroker::compilation_init_phase2() {
_initialized = true;
}
! Handle CompileBroker::create_thread_oop(const char* name, TRAPS) {
! Klass* k = SystemDictionary::find(vmSymbols::java_lang_Thread(), Handle(), Handle(), CHECK_NH);
! assert(k != NULL, "must be initialized");
InstanceKlass* klass = InstanceKlass::cast(k);
! instanceHandle thread_handle = klass->allocate_instance_handle(CHECK_NH);
! Handle string = java_lang_String::create_from_str(name, CHECK_NH);
// Initialize thread_oop to put it into the system threadGroup
! Handle thread_group(THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
! JavaCalls::call_special(&result, thread_handle,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
! CHECK_NH);
+ return thread_handle;
+ }
+
+
+ JavaThread* CompileBroker::make_thread(jobject thread_handle, CompileQueue* queue,
+ AbstractCompiler* comp, bool compiler_thread, TRAPS) {
+ JavaThread* thread = NULL;
{
MutexLocker mu(Threads_lock, THREAD);
if (compiler_thread) {
+ if (!InjectCompilerCreationFailure || comp->num_compiler_threads() == 0) {
+ CompilerCounters* counters = new CompilerCounters();
thread = new CompilerThread(queue, counters);
+ }
} else {
thread = new CodeCacheSweeperThread();
}
// At this point the new CompilerThread data-races with this startup
// thread (which I believe is the primoridal thread and NOT the VM
*** 718,734 ****
// exceptions anyway, check and abort if this fails. But first release the
// lock.
if (thread != NULL && thread->osthread() != NULL) {
! java_lang_Thread::set_thread(thread_oop(), thread);
// Note that this only sets the JavaThread _priority field, which by
// definition is limited to Java priorities and not OS priorities.
// The os-priority is set in the CompilerThread startup code itself
! java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
// Note that we cannot call os::set_priority because it expects Java
// priorities and we are *explicitly* using OS priorities so that it's
// possible to set the compiler thread priority higher than any Java
// thread.
--- 769,785 ----
// exceptions anyway, check and abort if this fails. But first release the
// lock.
if (thread != NULL && thread->osthread() != NULL) {
! java_lang_Thread::set_thread(JNIHandles::resolve_non_null(thread_handle), thread);
// Note that this only sets the JavaThread _priority field, which by
// definition is limited to Java priorities and not OS priorities.
// The os-priority is set in the CompilerThread startup code itself
! java_lang_Thread::set_priority(JNIHandles::resolve_non_null(thread_handle), NearMaxPriority);
// Note that we cannot call os::set_priority because it expects Java
// priorities and we are *explicitly* using OS priorities so that it's
// possible to set the compiler thread priority higher than any Java
// thread.
*** 741,763 ****
native_prio = os::java_to_os_priority[NearMaxPriority];
}
}
os::set_native_priority(thread, native_prio);
! java_lang_Thread::set_daemon(thread_oop());
! thread->set_threadObj(thread_oop());
if (compiler_thread) {
thread->as_CompilerThread()->set_compiler(comp);
}
Threads::add(thread);
Thread::start(thread);
}
}
// First release lock before aborting VM.
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
// Let go of Threads_lock before yielding
--- 792,820 ----
native_prio = os::java_to_os_priority[NearMaxPriority];
}
}
os::set_native_priority(thread, native_prio);
! java_lang_Thread::set_daemon(JNIHandles::resolve_non_null(thread_handle));
! thread->set_threadObj(JNIHandles::resolve_non_null(thread_handle));
if (compiler_thread) {
thread->as_CompilerThread()->set_compiler(comp);
}
Threads::add(thread);
Thread::start(thread);
}
}
// First release lock before aborting VM.
if (thread == NULL || thread->osthread() == NULL) {
+ if (UseDynamicNumberOfCompilerThreads && comp->num_compiler_threads() > 0) {
+ if (thread != NULL) {
+ thread->smr_delete();
+ }
+ return NULL;
+ }
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
// Let go of Threads_lock before yielding
*** 765,819 ****
return thread;
}
! void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_compiler_count) {
EXCEPTION_MARK;
#if !defined(ZERO)
! assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?");
#endif // !ZERO
// Initialize the compilation queue
! if (c2_compiler_count > 0) {
const char* name = JVMCI_ONLY(UseJVMCICompiler ? "JVMCI compile queue" :) "C2 compile queue";
_c2_compile_queue = new CompileQueue(name);
! _compilers[1]->set_num_compiler_threads(c2_compiler_count);
}
! if (c1_compiler_count > 0) {
_c1_compile_queue = new CompileQueue("C1 compile queue");
! _compilers[0]->set_num_compiler_threads(c1_compiler_count);
}
- int compiler_count = c1_compiler_count + c2_compiler_count;
-
char name_buffer[256];
! const bool compiler_thread = true;
! for (int i = 0; i < c2_compiler_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
! CompilerCounters* counters = new CompilerCounters();
! make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK);
}
! for (int i = c2_compiler_count; i < compiler_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "C1 CompilerThread%d", i);
! CompilerCounters* counters = new CompilerCounters();
! // C1
! make_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], compiler_thread, CHECK);
}
if (UsePerfData) {
! PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK);
}
if (MethodFlushing) {
// Initialize the sweeper thread
! make_thread("Sweeper thread", NULL, NULL, NULL, false, CHECK);
}
}
/**
* Set the methods on the stack as on_stack so that redefine classes doesn't
* reclaim them. This method is executed at a safepoint.
*/
--- 822,948 ----
return thread;
}
! void CompileBroker::init_compiler_sweeper_threads() {
EXCEPTION_MARK;
#if !defined(ZERO)
! assert(_c2_count > 0 || _c1_count > 0, "No compilers?");
#endif // !ZERO
// Initialize the compilation queue
! if (_c2_count > 0) {
const char* name = JVMCI_ONLY(UseJVMCICompiler ? "JVMCI compile queue" :) "C2 compile queue";
_c2_compile_queue = new CompileQueue(name);
! _compiler2_objects = NEW_C_HEAP_ARRAY(jobject, _c2_count, mtCompiler);
! _compiler2_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c2_count, mtCompiler);
}
! if (_c1_count > 0) {
_c1_compile_queue = new CompileQueue("C1 compile queue");
! _compiler1_objects = NEW_C_HEAP_ARRAY(jobject, _c1_count, mtCompiler);
! _compiler1_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c1_count, mtCompiler);
}
char name_buffer[256];
!
! for (int i = 0; i < _c2_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
! jobject thread_handle = JNIHandles::make_global(create_thread_oop(name_buffer, THREAD));
! _compiler2_objects[i] = thread_handle;
! _compiler2_logs[i] = NULL;
!
! if (!UseDynamicNumberOfCompilerThreads || i == 0) {
! JavaThread *ct = make_thread(thread_handle, _c2_compile_queue, _compilers[1], /* compiler_thread */ true, CHECK);
! assert(ct != NULL, "should have been handled for initial thread");
! _compilers[1]->set_num_compiler_threads(i + 1);
! if (TraceCompilerThreads) {
! ResourceMark rm;
! MutexLocker mu(Threads_lock);
! tty->print_cr("Added initial compiler thread %s", ct->get_thread_name());
! }
! }
}
! for (int i = 0; i < _c1_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "C1 CompilerThread%d", i);
! jobject thread_handle = JNIHandles::make_global(create_thread_oop(name_buffer, THREAD));
! _compiler1_objects[i] = thread_handle;
! _compiler1_logs[i] = NULL;
!
! if (!UseDynamicNumberOfCompilerThreads || i == 0) {
! JavaThread *ct = make_thread(thread_handle, _c1_compile_queue, _compilers[0], /* compiler_thread */ true, CHECK);
! assert(ct != NULL, "should have been handled for initial thread");
! _compilers[0]->set_num_compiler_threads(i + 1);
! if (TraceCompilerThreads) {
! ResourceMark rm;
! MutexLocker mu(Threads_lock);
! tty->print_cr("Added initial compiler thread %s", ct->get_thread_name());
! }
! }
}
if (UsePerfData) {
! PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, _c1_count + _c2_count, CHECK);
}
if (MethodFlushing) {
// Initialize the sweeper thread
! jobject thread_handle = JNIHandles::make_local(THREAD, create_thread_oop("Sweeper thread", THREAD)());
! make_thread(thread_handle, NULL, NULL, /* compiler_thread */ false, CHECK);
}
}
+ void CompileBroker::possibly_add_compiler_threads() {
+ EXCEPTION_MARK;
+
+ julong available_memory = os::available_memory();
+ // Only do attempt to start additional threads if the lock is free.
+ if (!CompileThread_lock->try_lock()) return;
+
+ if (_c2_compile_queue != NULL) {
+ int old_c2_count = _compilers[1]->num_compiler_threads();
+ int new_c2_count = MIN3(_c2_count,
+ _c2_compile_queue->size() / 2,
+ (int)(available_memory / 200*M));
+
+ for (int i = old_c2_count; i < new_c2_count; i++) {
+ JavaThread *ct = make_thread(compiler2_object(i), _c2_compile_queue, _compilers[1], true, CHECK);
+ if (ct == NULL) break;
+ _compilers[1]->set_num_compiler_threads(i + 1);
+ if (TraceCompilerThreads) {
+ ResourceMark rm;
+ MutexLocker mu(Threads_lock);
+ tty->print_cr("Added compiler thread %s (available memory: %dMB)",
+ ct->get_thread_name(), (int)(available_memory/M));
+ }
+ }
+ }
+
+ if (_c1_compile_queue != NULL) {
+ int old_c1_count = _compilers[0]->num_compiler_threads();
+ int new_c1_count = MIN3(_c1_count,
+ _c1_compile_queue->size() / 2,
+ (int)(available_memory / 100*M));
+
+ for (int i = old_c1_count; i < new_c1_count; i++) {
+ JavaThread *ct = make_thread(compiler1_object(i), _c1_compile_queue, _compilers[0], true, CHECK);
+ if (ct == NULL) break;
+ _compilers[0]->set_num_compiler_threads(i + 1);
+ if (TraceCompilerThreads) {
+ ResourceMark rm;
+ MutexLocker mu(Threads_lock);
+ tty->print_cr("Added compiler thread %s (available memory: %dMB)",
+ ct->get_thread_name(), (int)(available_memory/M));
+ }
+ }
+ }
+
+ CompileThread_lock->unlock();
+ }
+
/**
* Set the methods on the stack as on_stack so that redefine classes doesn't
* reclaim them. This method is executed at a safepoint.
*/
*** 1544,1553 ****
--- 1673,1724 ----
// the compiler runtime(s) (e.g., nmethod::is_compiled_by_c1()) which then
// fail. This can be done later if necessary.
}
}
+ /**
+ * Helper function to create new or reuse old CompileLog.
+ */
+ CompileLog* CompileBroker::get_log(CompilerThread* ct) {
+ if (!LogCompilation) return NULL;
+
+ AbstractCompiler *compiler = ct->compiler();
+ bool c1 = compiler->is_c1();
+
+ // Find Compiler number by its threadObj.
+ jobject* compiler_objects = c1 ? _compiler1_objects : _compiler2_objects;
+ oop compiler_obj = ct->threadObj();
+ int compiler_number = 0;
+ bool found = false;
+ for (; compiler_number < (c1 ? _c1_count : _c2_count); compiler_number++) {
+ if (JNIHandles::resolve_non_null(compiler_objects[compiler_number]) == compiler_obj) {
+ found = true;
+ break;
+ }
+ }
+ assert(found, "Compiler must exist at this point");
+
+ // Determine pointer for this threads log.
+ assert(_compiler1_logs != NULL, "must be initialized at this point");
+ assert(_compiler2_logs != NULL, "must be initialized at this point");
+ CompileLog** log_ptr = c1 ? &_compiler1_logs[compiler_number]
+ : &_compiler2_logs[compiler_number];
+
+ // Return old one if it exists.
+ CompileLog* log = *log_ptr;
+ if (log != NULL) {
+ ct->init_log(log);
+ return log;
+ }
+
+ // Create a new one and remember it.
+ init_compiler_thread_log();
+ log = ct->log();
+ *log_ptr = log;
+ return log;
+ }
+
// ------------------------------------------------------------------
// CompileBroker::compiler_thread_loop
//
// The main loop run by a CompilerThread.
void CompileBroker::compiler_thread_loop() {
*** 1566,1579 ****
ciObjectFactory::initialize();
}
}
// Open a log.
! if (LogCompilation) {
! init_compiler_thread_log();
! }
! CompileLog* log = thread->log();
if (log != NULL) {
log->begin_elem("start_compile_thread name='%s' thread='" UINTX_FORMAT "' process='%d'",
thread->name(),
os::current_thread_id(),
os::current_process_id());
--- 1737,1747 ----
ciObjectFactory::initialize();
}
}
// Open a log.
! CompileLog* log = get_log(thread);
if (log != NULL) {
log->begin_elem("start_compile_thread name='%s' thread='" UINTX_FORMAT "' process='%d'",
thread->name(),
os::current_thread_id(),
os::current_process_id());
*** 1584,1593 ****
--- 1752,1763 ----
// If compiler thread/runtime initialization fails, exit the compiler thread
if (!init_compiler_runtime()) {
return;
}
+ thread->start_idle_timer();
+
// Poll for new compilation tasks as long as the JVM runs. Compilation
// should only be disabled if something went wrong while initializing the
// compiler runtimes. This, in turn, should not happen. The only known case
// when compiler runtime initialization fails is if there is not enough free
// space in the code cache to generate the necessary stubs, etc.
*** 1595,1607 ****
--- 1765,1792 ----
// We need this HandleMark to avoid leaking VM handles.
HandleMark hm(thread);
CompileTask* task = queue->get();
if (task == NULL) {
+ if (UseDynamicNumberOfCompilerThreads) {
+ // Access compiler_count under lock to enforce consistency.
+ MutexLocker only_one(CompileThread_lock);
+ if (can_remove(thread, true)) {
+ if (TraceCompilerThreads) {
+ tty->print_cr("Removing compiler thread %s after it was " JLONG_FORMAT " ms idle",
+ thread->name(), thread->idle_time_millis());
+ }
+ return; // Stop this thread.
+ }
+ }
continue;
}
+ if (UseDynamicNumberOfCompilerThreads) {
+ possibly_add_compiler_threads();
+ }
+
// Give compiler threads an extra quanta. They tend to be bursty and
// this helps the compiler to finish up the job.
if (CompilerThreadHintNoPreempt) {
os::hint_no_preempt();
}
*** 1616,1625 ****
--- 1801,1811 ----
// Never compile a method if breakpoints are present in it
if (method()->number_of_breakpoints() == 0) {
// Compile the method.
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
invoke_compiler_on_method(task);
+ thread->start_idle_timer();
} else {
// After compilation is disabled, remove remaining methods from queue
method->clear_queued_for_compilation();
task->set_failure_reason("compilation is disabled");
}
< prev index next >