changeset 23302:90f7b4c21cfb

thread waiting for blocking JVMCI compilation should not wait on compiler queue forever (JDK-8148507)
author Doug Simon <doug.simon@oracle.com>
date Thu, 04 Feb 2016 15:21:43 +0100
parents 93caf66f5604
children 633cf7bea01d
files src/share/vm/compiler/compileBroker.cpp src/share/vm/compiler/compileBroker.hpp src/share/vm/jvmci/jvmciCompiler.hpp
diffstat 3 files changed, 47 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/compiler/compileBroker.cpp	Thu Feb 04 14:59:52 2016 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Thu Feb 04 15:21:43 2016 +0100
@@ -1724,50 +1724,57 @@
 }
 
 #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 milliseconds to wait before checking if
+// JVMCI compilation has made progress.
+static const long JVMCI_COMPILATION_PROGRESS_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;
+// The number of JVMCI compilation progress checks that must fail
+// before unblocking a thread waiting for a blocking compilation.
+static const int JVMCI_COMPILATION_PROGRESS_WAIT_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.
+ * waits until either the task completes or it sees no JVMCI compilation
+ * progress for N consecutive milliseconds where N is
+ * JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE *
+ * JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS.
  *
  * @return true if this thread needs to free/recycle the task
  */
-bool CompileBroker::wait_for_jvmci_completion(CompileTask* task, JavaThread* thread) {
+bool CompileBroker::wait_for_jvmci_completion(AbstractCompiler* comp, CompileTask* task, JavaThread* thread) {
   MutexLocker waiter(task->lock(), thread);
-  int consecutively_blocked = 0;
+  assert(comp->is_jvmci(), "must be");
+  JVMCICompiler* jvmci = (JVMCICompiler*) comp;
+  int progress_wait_attempts = 0;
+  int methods_compiled = jvmci->approx_num_methods_compiled();
   while (!task->is_complete() && !is_compilation_disabled_forever() &&
-         task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE)) {
+         task->lock()->wait(!Mutex::_no_safepoint_check_flag, JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE)) {
     CompilerThread* jvmci_compiler_thread = task->jvmci_compiler_thread();
+
+    bool progress;
     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 (PrintCompilation) {
-            task->print_compilation(tty, "wait for blocking compilation timed out");
-          }
-          break;
+      // If the JVMCI compiler thread is not blocked, we deem it to be making progress.
+      progress = jvmci_compiler_thread->thread_state() != _thread_blocked;
+    } else {
+      // Still waiting on JVMCI compiler queue. This thread may be holding a lock
+      // that all JVMCI compiler threads are blocked on. We use the counter for
+      // successful JVMCI compilations to determine whether JVMCI compilation
+      // is still making progress through the JVMCI compiler queue.
+      progress = jvmci->approx_num_methods_compiled() != methods_compiled;
+    }
+
+    if (!progress) {
+      if (++progress_wait_attempts == JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS) {
+        if (PrintCompilation) {
+          task->print_compilation(tty, "wait for blocking compilation timed out");
         }
-      } else {
-        consecutively_blocked = 0;
+        break;
       }
     } else {
-      // Still waiting on JVMCI compiler queue
+      progress_wait_attempts = 0;
+      if (jvmci_compiler_thread == NULL) {
+        methods_compiled = jvmci->approx_num_methods_compiled();
+      }
     }
   }
   task->clear_waiter();
@@ -1792,8 +1799,9 @@
   methodHandle method(thread, task->method());
   bool free_task = true;
 #ifdef COMPILERJVMCI
-  if (compiler(task->comp_level())->is_jvmci()) {
-    free_task = wait_for_jvmci_completion(task, thread);
+  AbstractCompiler* comp = compiler(task->comp_level());
+  if (comp->is_jvmci()) {
+    free_task = wait_for_jvmci_completion(comp, task, thread);
   } else
 #endif
   {
--- a/src/share/vm/compiler/compileBroker.hpp	Thu Feb 04 14:59:52 2016 +0100
+++ b/src/share/vm/compiler/compileBroker.hpp	Thu Feb 04 15:21:43 2016 +0100
@@ -372,7 +372,7 @@
                                           bool          blocking);
   static void wait_for_completion(CompileTask* task);
 #ifdef COMPILERJVMCI
-  static bool wait_for_jvmci_completion(CompileTask* task, JavaThread* thread);
+  static bool wait_for_jvmci_completion(AbstractCompiler* comp, CompileTask* task, JavaThread* thread);
 #endif
 
   static void invoke_compiler_on_method(CompileTask* task);
--- a/src/share/vm/jvmci/jvmciCompiler.hpp	Thu Feb 04 14:59:52 2016 +0100
+++ b/src/share/vm/jvmci/jvmciCompiler.hpp	Thu Feb 04 15:21:43 2016 +0100
@@ -80,8 +80,12 @@
   // Print compilation timers and statistics
   virtual void print_timers();
 
-  // Print compilation statistics
-  void reset_compilation_stats();
+  /**
+   * Get the number of methods that have been successfully compiled.
+   * This is an approximation as updating the counter is not atomic.
+   */
+  int approx_num_methods_compiled() { return _methodsCompiled; }
+
 #endif // COMPILERJVMCI
 
   // Print compilation timers and statistics