< 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 >