Mercurial > hg > graal-jvmci-8
changeset 22762:9d78d44d3aac
improved JVMCI support for blocking compilation (GRAAL-1387)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Fri, 08 Jan 2016 17:30:33 +0100 |
parents | f2206f5bb62e |
children | 94b7354ef0e0 |
files | src/share/vm/compiler/compileBroker.cpp src/share/vm/compiler/compileBroker.hpp src/share/vm/runtime/advancedThresholdPolicy.cpp src/share/vm/runtime/compilationPolicy.cpp src/share/vm/runtime/compilationPolicy.hpp src/share/vm/runtime/simpleThresholdPolicy.cpp |
diffstat | 6 files changed, 131 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/vm/compiler/compileBroker.cpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Jan 08 17:30:33 2016 +0100 @@ -237,6 +237,11 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); +#ifdef COMPILERJVMCI + if (task->is_blocking() && CompileBroker::compiler(task->comp_level())->is_jvmci()) { + task->set_jvmci_compiler_thread(thread); + } +#endif CompileLog* log = thread->log(); if (log != NULL) task->log_task_start(log); } @@ -256,25 +261,17 @@ task->mark_complete(); #ifdef COMPILERJVMCI if (CompileBroker::compiler(task->comp_level())->is_jvmci()) { - // Blocking JVMCI compilations are performed with a timeout so as - // to avoid deadlock between an application thread and a JVMCI - // compiler thread (both of which execute Java code). - if (task->has_waiter()) { - // Notify the waiting thread that the compilation has completed - // and let it free the CompileTask. - task->lock()->notify_all(); - } else { - // The waiting thread timed out did not free the task. + if (!task->has_waiter()) { + // The waiting thread timed out and thus did not free the task. free_task = true; } - } else { + task->set_jvmci_compiler_thread(NULL); + } +#endif + if (!free_task) { // Notify the waiting thread that the compilation has completed. task->lock()->notify_all(); } -#else - // Notify the waiting thread that the compilation has completed. - task->lock()->notify_all(); -#endif } if (free_task) { // The task can only be freed once the task lock is released. @@ -308,7 +305,7 @@ } else { task = new CompileTask(); DEBUG_ONLY(_num_allocated_tasks++;) - assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?"); + NOT_COMPILERJVMCI(assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?");) task->set_next(NULL); task->set_is_free(true); } @@ -351,6 +348,7 @@ _osr_bci = osr_bci; _is_blocking = is_blocking; COMPILERJVMCI_PRESENT(_has_waiter = CompileBroker::compiler(comp_level)->is_jvmci();) + COMPILERJVMCI_PRESENT(_jvmci_compiler_thread = NULL;) _comp_level = comp_level; _num_inlined_bytecodes = 0; @@ -1713,11 +1711,59 @@ return new_task; } -// 1 second should be long enough to complete most JVMCI compilations -// and not too long to stall a blocking JVMCI compilation that -// is trying to acquire a lock held by the app thread that submitted the -// compilation. -static const long BLOCKING_JVMCI_COMPILATION_TIMEOUT = 1000; +#ifdef COMPILERJVMCI +// The number of milliseconds to wait before checking if the +// JVMCI compiler has become blocked during compilation. +static const long BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE = 500; + +// The number of successive times the above check is allowed to +// see a blocked JVMCI compiler thread before unblocking the +// thread waiting for the compilation to finish. +static const int BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS = 5; + +/** + * Waits for a JVMCI compiler to complete a given task. This thread + * waits until either the task completes or it sees the JVMCI compiler + * thread is blocked for N consecutive milliseconds where N is + * BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE * + * BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS. + * + * @return true if this thread needs to free/recycle the task + */ +bool CompileBroker::wait_for_jvmci_completion(CompileTask* task, JavaThread* thread) { + MutexLocker waiter(task->lock(), thread); + int consecutively_blocked = 0; + while (task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE)) { + CompilerThread* jvmci_compiler_thread = task->jvmci_compiler_thread(); + if (jvmci_compiler_thread != NULL) { + JavaThreadState state; + { + // A JVMCI compiler thread should not disappear at this point + // but let's be extra safe. + MutexLocker mu(Threads_lock, thread); + state = jvmci_compiler_thread->thread_state(); + } + if (state == _thread_blocked) { + if (++consecutively_blocked == BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS) { + if (_compilation_log != NULL) { + _compilation_log->log_failure(thread, task, "compilation timed out", NULL); + } + if (PrintCompilation) { + task->print_compilation(tty, "compilation timed out"); + } + break; + } + } else { + consecutively_blocked = 0; + } + } else { + // Still waiting on JVMCI compiler queue + } + } + task->clear_waiter(); + return task->is_complete(); +} +#endif /** * Wait for the compilation task to complete. @@ -1737,18 +1783,7 @@ bool free_task = true; #ifdef COMPILERJVMCI if (compiler(task->comp_level())->is_jvmci()) { - { - MutexLocker waiter(task->lock(), thread); - // No need to check if compilation has completed - just - // rely on the time out. The JVMCI compiler thread will - // recycle the CompileTask. - task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_TIMEOUT); - // If the compilation completes while has_waiter is true then - // this thread is responsible for freeing the task. Otherwise - // the compiler thread will free the task. - task->clear_waiter(); - free_task = task->is_complete(); - } + free_task = wait_for_jvmci_completion(task, thread); } else #endif {
--- a/src/share/vm/compiler/compileBroker.hpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Fri Jan 08 17:30:33 2016 +0100 @@ -56,6 +56,8 @@ bool _is_blocking; #ifdef COMPILERJVMCI bool _has_waiter; + // Compiler thread for a blocking JVMCI compilation + CompilerThread* _jvmci_compiler_thread; #endif int _comp_level; int _num_inlined_bytecodes; @@ -91,6 +93,12 @@ #ifdef COMPILERJVMCI bool has_waiter() const { return _has_waiter; } void clear_waiter() { _has_waiter = false; } + CompilerThread* jvmci_compiler_thread() const { return _jvmci_compiler_thread; } + void set_jvmci_compiler_thread(CompilerThread* t) { + assert(is_blocking(), "must be"); + assert((t == NULL) != (_jvmci_compiler_thread == NULL), "must be"); + _jvmci_compiler_thread = t; + } #endif nmethodLocker* code_handle() const { return _code_handle; } @@ -363,6 +371,9 @@ const char* comment, bool blocking); static void wait_for_completion(CompileTask* task); +#ifdef COMPILERJVMCI + static bool wait_for_jvmci_completion(CompileTask* task, JavaThread* thread); +#endif static void invoke_compiler_on_method(CompileTask* task); static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
--- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Fri Jan 08 17:30:33 2016 +0100 @@ -161,6 +161,9 @@ // Called with the queue locked and with at least one element CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { +#ifdef COMPILERJVMCI + CompileTask *max_blocking_task = NULL; +#endif CompileTask *max_task = NULL; Method* max_method = NULL; jlong t = os::javaTimeMillis(); @@ -191,9 +194,28 @@ max_method = method; } } +#ifdef COMPILERJVMCI + if (task->is_blocking()) { + if (max_blocking_task == NULL || compare_methods(method, max_blocking_task->method())) { + max_blocking_task = task; + } + } +#endif task = next_task; } +#ifdef COMPILERJVMCI + if (max_blocking_task != NULL) { + // In blocking compilation mode, the CompileBroker will make + // compilations submitted by a JVMCI compiler thread non-blocking. These + // compilations should be scheduled after all blocking compilations + // to service non-compiler related compilations sooner and reduce the + // chance of such compilations timing out. + max_task = max_blocking_task; + max_method = max_task->method(); + } +#endif + if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile);
--- a/src/share/vm/runtime/compilationPolicy.cpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/runtime/compilationPolicy.cpp Fri Jan 08 17:30:33 2016 +0100 @@ -160,6 +160,19 @@ return !delay_compilation_during_startup() && CompileBroker::should_compile_new_jobs(); } +#ifdef COMPILERJVMCI +CompileTask* CompilationPolicy::select_task_blocking_aware(CompileQueue* compile_queue) { + if (!BackgroundCompilation) { + for (CompileTask* task = compile_queue->first(); task != NULL; task = task->next()) { + if (task->is_blocking()) { + return task; + } + } + } + return compile_queue->first(); +} +#endif + #ifndef PRODUCT void CompilationPolicy::print_time() { tty->print_cr ("Accumulated compilationPolicy times:"); @@ -340,6 +353,7 @@ } CompileTask* NonTieredCompPolicy::select_task(CompileQueue* compile_queue) { + COMPILERJVMCI_PRESENT(return select_task_blocking_aware(compile_queue);) return compile_queue->first(); }
--- a/src/share/vm/runtime/compilationPolicy.hpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/runtime/compilationPolicy.hpp Fri Jan 08 17:30:33 2016 +0100 @@ -58,6 +58,22 @@ static void set_policy(CompilationPolicy* policy) { _policy = policy; } static CompilationPolicy* policy() { return _policy; } +#ifdef COMPILERJVMCI + /** + * If in blocking compilation mode and the JVMCI compiler is in use, + * this method selects a blocking task (if any) before a non-blocking + * task. In blocking compilation mode, the CompileBroker will make + * compilations submitted by a JVMCI compiler thread non-blocking. These + * compilations should be scheduled after all blocking compilations + * to service non-compiler related compilations sooner and reduce the + * chance of such compilations timing out. + * + * @return the first non-blocking task in compile_queue if there is one otherwise + * the first task in compile_queue + */ + static CompileTask* select_task_blocking_aware(CompileQueue* compile_queue); +#endif + // Profiling elapsedTimer* accumulated_time() { return &_accumulated_time; } void print_time() PRODUCT_RETURN;
--- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Dec 30 17:55:07 2015 +0100 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Fri Jan 08 17:30:33 2016 +0100 @@ -168,6 +168,7 @@ // Called with the queue locked and with at least one element CompileTask* SimpleThresholdPolicy::select_task(CompileQueue* compile_queue) { + COMPILERJVMCI_PRESENT(return select_task_blocking_aware(compile_queue);) return compile_queue->first(); }