8148507: [JVMCI] mitigate deadlocks related to JVMCI compiler under -Xbatch
authordnsimon
Mon, 08 Feb 2016 18:52:03 +0100
changeset 35845 30025047885d
parent 35844 8a1952516600
child 35846 f5a8b47778ef
8148507: [JVMCI] mitigate deadlocks related to JVMCI compiler under -Xbatch Reviewed-by: twisti, dholmes
hotspot/src/share/vm/compiler/compileBroker.cpp
hotspot/src/share/vm/compiler/compileBroker.hpp
hotspot/src/share/vm/jvmci/jvmciCompiler.cpp
hotspot/src/share/vm/jvmci/jvmciCompiler.hpp
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp	Mon Feb 08 18:52:03 2016 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Mon Feb 08 18:52:03 2016 +0100
@@ -545,7 +545,7 @@
         c1_count = JVMCIHostThreads;
       }
 
-      if (!UseInterpreter) {
+      if (!UseInterpreter || !BackgroundCompilation) {
         // Force initialization of JVMCI compiler otherwise JVMCI
         // compilations will not block until JVMCI is initialized
         ResourceMark rm;
@@ -1346,49 +1346,55 @@
 }
 
 #if INCLUDE_JVMCI
-// The number of milliseconds to wait before checking if the
-// JVMCI compiler thread is blocked.
-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(JVMCICompiler* jvmci, 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)) {
+  int progress_wait_attempts = 0;
+  int methods_compiled = jvmci->methods_compiled();
+  while (!task->is_complete() && !is_compilation_disabled_forever() &&
+         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(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->methods_compiled() != methods_compiled;
+    }
+
+    if (!progress) {
+      if (++progress_wait_attempts == JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS) {
+        if (PrintCompilation) {
+          task->print(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->methods_compiled();
+      }
     }
   }
   task->clear_waiter();
@@ -1413,8 +1419,9 @@
   methodHandle method(thread, task->method());
   bool free_task;
 #if INCLUDE_JVMCI
-  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((JVMCICompiler*) comp, task, thread);
   } else
 #endif
   {
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp	Mon Feb 08 18:52:03 2016 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.hpp	Mon Feb 08 18:52:03 2016 +0100
@@ -32,6 +32,9 @@
 #include "runtime/perfData.hpp"
 #include "trace/tracing.hpp"
 #include "utilities/stack.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmciCompiler.hpp"
+#endif
 
 class nmethod;
 class nmethodLocker;
@@ -234,7 +237,7 @@
                                           bool                blocking);
   static void wait_for_completion(CompileTask* task);
 #if INCLUDE_JVMCI
-  static bool wait_for_jvmci_completion(CompileTask* task, JavaThread* thread);
+  static bool wait_for_jvmci_completion(JVMCICompiler* comp, CompileTask* task, JavaThread* thread);
 #endif
 
   static void invoke_compiler_on_method(CompileTask* task);
--- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp	Mon Feb 08 18:52:03 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp	Mon Feb 08 18:52:03 2016 +0100
@@ -38,7 +38,7 @@
 
 JVMCICompiler::JVMCICompiler() : AbstractCompiler(jvmci) {
   _bootstrapping = false;
-  _methodsCompiled = 0;
+  _methods_compiled = 0;
   assert(_instance == NULL, "only one instance allowed");
   _instance = this;
 }
@@ -99,7 +99,7 @@
     } while (first_round && qsize == 0);
     first_round = false;
     if (PrintBootstrap) {
-      while (z < (_methodsCompiled / 100)) {
+      while (z < (_methods_compiled / 100)) {
         ++z;
         tty->print_raw(".");
       }
@@ -107,7 +107,7 @@
   } while (qsize != 0);
 
   if (PrintBootstrap) {
-    tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled);
+    tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methods_compiled);
   }
   _bootstrapping = false;
 }
@@ -176,7 +176,7 @@
           env->set_failure("no nmethod produced", true);
         } else {
           env->task()->set_num_inlined_bytecodes(CompilationRequestResult::inlinedBytecodes(result_object));
-          _methodsCompiled++;
+          Atomic::inc(&_methods_compiled);
         }
       }
     } else {
--- a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp	Mon Feb 08 18:52:03 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp	Mon Feb 08 18:52:03 2016 +0100
@@ -33,10 +33,10 @@
   bool _bootstrapping;
 
   /**
-   * Number of methods compiled by JVMCI. This is not synchronized
-   * so may not be 100% accurate.
+   * Number of methods successfully compiled by a call to
+   * JVMCICompiler::compile_method().
    */
-  volatile int _methodsCompiled;
+  volatile int _methods_compiled;
 
   static JVMCICompiler* _instance;
 
@@ -80,8 +80,11 @@
   // Print compilation timers and statistics
   virtual void print_timers();
 
-  // Print compilation statistics
-  void reset_compilation_stats();
+  /**
+   * Gets the number of methods that have been successfully compiled by
+   * a call to JVMCICompiler::compile_method().
+   */
+  int methods_compiled() { return _methods_compiled; }
 
   // Print compilation timers and statistics
   static void print_compilation_timers();