changeset 59914:6d462945718b

8246477: add whitebox support for deflating idle monitors Reviewed-by: dholmes, eosterlund
author dcubed
date Wed, 24 Jun 2020 17:48:53 -0400
parents 131e72eab59a
children 6652918413f5
files src/hotspot/share/prims/jvm.cpp src/hotspot/share/prims/whitebox.cpp src/hotspot/share/runtime/synchronizer.cpp src/hotspot/share/runtime/synchronizer.hpp src/hotspot/share/runtime/vmOperations.cpp src/hotspot/share/runtime/vmThread.cpp test/hotspot/jtreg/compiler/testlibrary/rtm/AbortProvoker.java test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java test/lib/sun/hotspot/WhiteBox.java
diffstat 10 files changed, 158 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/prims/jvm.cpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/prims/jvm.cpp	Wed Jun 24 17:48:53 2020 -0400
@@ -493,11 +493,6 @@
 JVM_ENTRY_NO_ENV(void, JVM_GC(void))
   JVMWrapper("JVM_GC");
   if (!DisableExplicitGC) {
-    if (AsyncDeflateIdleMonitors) {
-      // AsyncDeflateIdleMonitors needs to know when System.gc() is
-      // called so any special deflation can be done at a safepoint.
-      ObjectSynchronizer::set_is_special_deflation_requested(true);
-    }
     Universe::heap()->collect(GCCause::_java_lang_system_gc);
   }
 JVM_END
--- a/src/hotspot/share/prims/whitebox.cpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/prims/whitebox.cpp	Wed Jun 24 17:48:53 2020 -0400
@@ -41,6 +41,7 @@
 #include "gc/shared/genArguments.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
 #include "jvmtifiles/jvmtiEnv.hpp"
+#include "logging/log.hpp"
 #include "memory/filemap.hpp"
 #include "memory/heapShared.inline.hpp"
 #include "memory/metaspaceShared.hpp"
@@ -478,12 +479,6 @@
 
 WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o))
   if (UseG1GC) {
-    if (AsyncDeflateIdleMonitors) {
-      // AsyncDeflateIdleMonitors needs to know when System.gc() or
-      // the equivalent is called so any special clean up can be done
-      // at a safepoint, e.g., TestHumongousClassLoader.java.
-      ObjectSynchronizer::set_is_special_deflation_requested(true);
-    }
     G1CollectedHeap* g1h = G1CollectedHeap::heap();
     if (!g1h->concurrent_mark()->cm_thread()->during_cycle()) {
       g1h->collect(GCCause::_wb_conc_mark);
@@ -1455,12 +1450,6 @@
 WB_END
 
 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
-  if (AsyncDeflateIdleMonitors) {
-    // AsyncDeflateIdleMonitors needs to know when System.gc() or
-    // the equivalent is called so any special clean up can be done
-    // at a safepoint, e.g., TestHumongousClassLoader.java.
-    ObjectSynchronizer::set_is_special_deflation_requested(true);
-  }
   Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true);
   Universe::heap()->collect(GCCause::_wb_full_gc);
 #if INCLUDE_G1GC
@@ -1809,14 +1798,12 @@
   return (jboolean) obj_oop->mark().has_monitor();
 WB_END
 
+WB_ENTRY(jboolean, WB_DeflateIdleMonitors(JNIEnv* env, jobject wb))
+  log_info(monitorinflation)("WhiteBox initiated DeflateIdleMonitors");
+  return ObjectSynchronizer::request_deflate_idle_monitors();
+WB_END
+
 WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb))
-  if (AsyncDeflateIdleMonitors) {
-    // AsyncDeflateIdleMonitors needs to know when System.gc() or
-    // the equivalent is called so any special clean up can be done
-    // at a safepoint, e.g., TestRTMTotalCountIncrRate.java or
-    // TestUseRTMForStackLocks.java.
-    ObjectSynchronizer::set_is_special_deflation_requested(true);
-  }
   VM_ForceSafepoint force_safepoint_op;
   VMThread::execute(&force_safepoint_op);
 WB_END
@@ -2480,6 +2467,7 @@
                                                       (void*)&WB_AddModuleExportsToAll },
   {CC"assertMatchingSafepointCalls", CC"(ZZ)V",       (void*)&WB_AssertMatchingSafepointCalls },
   {CC"assertSpecialLock",  CC"(ZZ)V",                 (void*)&WB_AssertSpecialLock },
+  {CC"deflateIdleMonitors", CC"()Z",                  (void*)&WB_DeflateIdleMonitors },
   {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated  },
   {CC"forceSafepoint",     CC"()V",                   (void*)&WB_ForceSafepoint     },
   {CC"getConstantPool0",   CC"(Ljava/lang/Class;)J",  (void*)&WB_GetConstantPool    },
--- a/src/hotspot/share/runtime/synchronizer.cpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Wed Jun 24 17:48:53 2020 -0400
@@ -121,7 +121,6 @@
 // global list of blocks of monitors
 PaddedObjectMonitor* ObjectSynchronizer::g_block_list = NULL;
 bool volatile ObjectSynchronizer::_is_async_deflation_requested = false;
-bool volatile ObjectSynchronizer::_is_special_deflation_requested = false;
 jlong ObjectSynchronizer::_last_async_deflation_time_ns = 0;
 
 struct ObjectMonitorListGlobals {
@@ -1309,30 +1308,60 @@
     // are too many monitors in use. We don't deflate more frequently
     // than AsyncDeflationInterval (unless is_async_deflation_requested)
     // in order to not swamp the ServiceThread.
-    _last_async_deflation_time_ns = os::javaTimeNanos();
     return true;
   }
   return false;
 }
 
 bool ObjectSynchronizer::is_safepoint_deflation_needed() {
-  if (!AsyncDeflateIdleMonitors) {
-    if (monitors_used_above_threshold()) {
-      // Too many monitors in use.
-      return true;
+  return !AsyncDeflateIdleMonitors &&
+         monitors_used_above_threshold();  // Too many monitors in use.
+}
+
+bool ObjectSynchronizer::request_deflate_idle_monitors() {
+  bool is_JavaThread = Thread::current()->is_Java_thread();
+  bool ret_code = false;
+
+  if (AsyncDeflateIdleMonitors) {
+    jlong last_time = last_async_deflation_time_ns();
+    set_is_async_deflation_requested(true);
+    {
+      MonitorLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
+      ml.notify_all();
     }
-    return false;
+    const int N_CHECKS = 5;
+    for (int i = 0; i < N_CHECKS; i++) {  // sleep for at most 5 seconds
+      if (last_async_deflation_time_ns() > last_time) {
+        log_info(monitorinflation)("Async Deflation happened after %d check(s).", i);
+        ret_code = true;
+        break;
+      }
+      if (is_JavaThread) {
+        // JavaThread has to honor the blocking protocol.
+        ThreadBlockInVM tbivm(JavaThread::current());
+        os::naked_short_sleep(999);  // sleep for almost 1 second
+      } else {
+        os::naked_short_sleep(999);  // sleep for almost 1 second
+      }
+    }
+    if (!ret_code) {
+      log_info(monitorinflation)("Async Deflation DID NOT happen after %d checks.", N_CHECKS);
+    }
+  } else {
+    // Only need to force this safepoint if we are not using async
+    // deflation. The VMThread won't call this function before the
+    // final safepoint if we are not using async deflation so we
+    // don't have to reason about the VMThread executing a VM-op here.
+    VM_ForceSafepoint force_safepoint_op;
+    VMThread::execute(&force_safepoint_op);
+    ret_code = true;
   }
-  if (is_special_deflation_requested()) {
-    // For AsyncDeflateIdleMonitors only do a safepoint deflation
-    // if there is a special deflation request.
-    return true;
-  }
-  return false;
+
+  return ret_code;
 }
 
 jlong ObjectSynchronizer::time_since_last_async_deflation_ms() {
-  return (os::javaTimeNanos() - _last_async_deflation_time_ns) / (NANOUNITS / MILLIUNITS);
+  return (os::javaTimeNanos() - last_async_deflation_time_ns()) / (NANOUNITS / MILLIUNITS);
 }
 
 void ObjectSynchronizer::oops_do(OopClosure* f) {
@@ -2017,9 +2046,8 @@
   // The per-thread in-use lists are handled in
   // ParallelSPCleanupThreadClosure::do_thread().
 
-  if (!AsyncDeflateIdleMonitors || is_special_deflation_requested()) {
-    // Use the older mechanism for the global in-use list or if a
-    // special deflation has been requested before the safepoint.
+  if (!AsyncDeflateIdleMonitors) {
+    // Use the older mechanism for the global in-use list.
     ObjectSynchronizer::deflate_idle_monitors(counters);
     return;
   }
@@ -2438,10 +2466,8 @@
 
   if (AsyncDeflateIdleMonitors) {
     // Nothing to do when global idle ObjectMonitors are deflated using
-    // a JavaThread unless a special deflation has been requested.
-    if (!is_special_deflation_requested()) {
-      return;
-    }
+    // a JavaThread.
+    return;
   }
 
   bool deflated = false;
@@ -2534,6 +2560,7 @@
                              Atomic::load(&om_list_globals._wait_count));
 
   // The ServiceThread's async deflation request has been processed.
+  _last_async_deflation_time_ns = os::javaTimeNanos();
   set_is_async_deflation_requested(false);
 
   if (Atomic::load(&om_list_globals._wait_count) > 0) {
@@ -2609,16 +2636,6 @@
   }
 
   do {
-    if (saved_mid_in_use_p != NULL) {
-      // We looped around because deflate_monitor_list_using_JT()
-      // detected a pending safepoint. Honoring the safepoint is good,
-      // but as long as is_special_deflation_requested() is supported,
-      // we can't safely restart using saved_mid_in_use_p. That saved
-      // ObjectMonitor could have been deflated by safepoint based
-      // deflation and would no longer be on the in-use list where we
-      // originally found it.
-      saved_mid_in_use_p = NULL;
-    }
     int local_deflated_count;
     if (is_global) {
       local_deflated_count =
@@ -2701,10 +2718,9 @@
   // than a beginning to end measurement of the phase.
   log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs, monitors=%d", counters->per_thread_times, counters->per_thread_scavenged);
 
-  bool needs_special_deflation = is_special_deflation_requested();
-  if (AsyncDeflateIdleMonitors && !needs_special_deflation) {
+  if (AsyncDeflateIdleMonitors) {
     // Nothing to do when idle ObjectMonitors are deflated using
-    // a JavaThread unless a special deflation has been requested.
+    // a JavaThread.
     return;
   }
 
@@ -2729,17 +2745,14 @@
 
   GVars.stw_random = os::random();
   GVars.stw_cycle++;
-
-  if (needs_special_deflation) {
-    set_is_special_deflation_requested(false);  // special deflation is done
-  }
 }
 
 void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters) {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 
-  if (AsyncDeflateIdleMonitors && !is_special_deflation_requested()) {
-    // Nothing to do if a special deflation has NOT been requested.
+  if (AsyncDeflateIdleMonitors) {
+    // Nothing to do when per-thread idle ObjectMonitors are deflated
+    // using a JavaThread.
     return;
   }
 
--- a/src/hotspot/share/runtime/synchronizer.hpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/runtime/synchronizer.hpp	Wed Jun 24 17:48:53 2020 -0400
@@ -161,9 +161,9 @@
   static bool is_async_deflation_needed();
   static bool is_safepoint_deflation_needed();
   static bool is_async_deflation_requested() { return _is_async_deflation_requested; }
-  static bool is_special_deflation_requested() { return _is_special_deflation_requested; }
+  static jlong last_async_deflation_time_ns() { return _last_async_deflation_time_ns; }
+  static bool request_deflate_idle_monitors();  // for whitebox test support and VM exit logging
   static void set_is_async_deflation_requested(bool new_value) { _is_async_deflation_requested = new_value; }
-  static void set_is_special_deflation_requested(bool new_value) { _is_special_deflation_requested = new_value; }
   static jlong time_since_last_async_deflation_ms();
   static void oops_do(OopClosure* f);
   // Process oops in thread local used monitors
@@ -200,7 +200,6 @@
   // global list of blocks of monitors
   static PaddedObjectMonitor* g_block_list;
   static volatile bool _is_async_deflation_requested;
-  static volatile bool _is_special_deflation_requested;
   static jlong         _last_async_deflation_time_ns;
 
   // Function to prepend new blocks to the appropriate lists:
--- a/src/hotspot/share/runtime/vmOperations.cpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/runtime/vmOperations.cpp	Wed Jun 24 17:48:53 2020 -0400
@@ -432,11 +432,10 @@
 
 bool VM_Exit::doit_prologue() {
   if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
-    // AsyncDeflateIdleMonitors does a special deflation at the VM_Exit
-    // safepoint in order to reduce the in-use monitor population that
-    // is reported by ObjectSynchronizer::log_in_use_monitor_details()
-    // at VM exit.
-    ObjectSynchronizer::set_is_special_deflation_requested(true);
+    // AsyncDeflateIdleMonitors does a special deflation in order
+    // to reduce the in-use monitor population that is reported by
+    // ObjectSynchronizer::log_in_use_monitor_details() at VM exit.
+    ObjectSynchronizer::request_deflate_idle_monitors();
   }
   return true;
 }
--- a/src/hotspot/share/runtime/vmThread.cpp	Wed Jun 24 23:47:16 2020 +0200
+++ b/src/hotspot/share/runtime/vmThread.cpp	Wed Jun 24 17:48:53 2020 -0400
@@ -261,11 +261,10 @@
   }
 
   if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
-    // AsyncDeflateIdleMonitors does a special deflation at the final
-    // safepoint in order to reduce the in-use monitor population that
-    // is reported by ObjectSynchronizer::log_in_use_monitor_details()
-    // at VM exit.
-    ObjectSynchronizer::set_is_special_deflation_requested(true);
+    // AsyncDeflateIdleMonitors does a special deflation in order
+    // to reduce the in-use monitor population that is reported by
+    // ObjectSynchronizer::log_in_use_monitor_details() at VM exit.
+    ObjectSynchronizer::request_deflate_idle_monitors();
   }
 
   // 4526887 let VM thread exit at Safepoint
--- a/test/hotspot/jtreg/compiler/testlibrary/rtm/AbortProvoker.java	Wed Jun 24 23:47:16 2020 +0200
+++ b/test/hotspot/jtreg/compiler/testlibrary/rtm/AbortProvoker.java	Wed Jun 24 17:48:53 2020 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -98,7 +98,9 @@
     public static void verifyMonitorState(Object monitor,
             boolean shouldBeInflated) {
         if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) {
-            WHITE_BOX.forceSafepoint();
+            boolean did_deflation = WHITE_BOX.deflateIdleMonitors();
+            Asserts.assertEQ(did_deflation, true,
+                             "deflateIdleMonitors() should have worked.");
         }
         Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated,
                 "Monitor in a wrong state.");
--- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java	Wed Jun 24 23:47:16 2020 +0200
+++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java	Wed Jun 24 17:48:53 2020 -0400
@@ -203,6 +203,10 @@
 
         gc.provoke();
 
+        boolean did_deflation = WB.deflateIdleMonitors();
+        Asserts.assertEQ(did_deflation, true,
+                         "deflateIdleMonitors() should have worked.");
+
         // Test checks
         Asserts.assertEquals(WB.isClassAlive(HUMONGOUS_CLASSLOADER_NAME), false,
                 String.format("Classloader class %s is loaded after we forget all references to it",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java	Wed Jun 24 17:48:53 2020 -0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package runtime.whitebox;
+
+/*
+ * @test
+ * @bug 8246477
+ * @summary Test to verify that WB method deflateIdleMonitors works correctly.
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver runtime.whitebox.TestWBDeflateIdleMonitors
+ */
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class TestWBDeflateIdleMonitors {
+
+    public static void main(String args[]) throws Exception {
+        ProcessBuilder pb = ProcessTools.createTestJvm(
+                "-Xbootclasspath/a:.",
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:+WhiteBoxAPI",
+                "-Xlog:monitorinflation=info",
+                InflateMonitorsTest.class.getName());
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        System.out.println(output.getStdout());
+        output.shouldHaveExitValue(0);
+        output.shouldContain("WhiteBox initiated DeflateIdleMonitors");
+    }
+
+    public static class InflateMonitorsTest {
+        static WhiteBox wb = WhiteBox.getWhiteBox();
+        public static Object obj;
+
+        public static void main(String args[]) {
+            obj = new Object();
+            synchronized (obj) {
+                // HotSpot implementation detail: asking for the hash code
+                // when the object is locked causes monitor inflation.
+                if (obj.hashCode() == 0xBAD) System.out.println("!");
+                Asserts.assertEQ(wb.isMonitorInflated(obj), true,
+                                 "Monitor should be inflated.");
+            }
+            boolean did_deflation = wb.deflateIdleMonitors();
+            Asserts.assertEQ(did_deflation, true,
+                             "deflateIdleMonitors() should have worked.");
+            Asserts.assertEQ(wb.isMonitorInflated(obj), false,
+                             "Monitor should be deflated.");
+        }
+    }
+}
--- a/test/lib/sun/hotspot/WhiteBox.java	Wed Jun 24 23:47:16 2020 +0200
+++ b/test/lib/sun/hotspot/WhiteBox.java	Wed Jun 24 17:48:53 2020 -0400
@@ -110,6 +110,8 @@
 
   public  native int getSymbolRefcount(String name);
 
+  public native boolean deflateIdleMonitors();
+
   private native boolean isMonitorInflated0(Object obj);
   public         boolean isMonitorInflated(Object obj) {
     Objects.requireNonNull(obj);