Mercurial > hg > graal-jvmci-8
diff src/share/vm/compiler/compileBroker.cpp @ 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 | 24fd08e99b35 |
children | 94b7354ef0e0 |
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 {