diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5ed593b0d2f..c480f8a09ac 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1115,6 +1115,10 @@ bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThrea return false; } +size_t WhiteBox::get_in_use_monitor_count() { + return ObjectSynchronizer::_in_use_list.count(); +} + WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level, jint bci)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); @@ -1850,6 +1854,10 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj)) return (jboolean) obj_oop->mark().has_monitor(); WB_END +WB_ENTRY(jlong, WB_getInUseMonitorCount(JNIEnv* env, jobject wb)) + return (jlong) WhiteBox::get_in_use_monitor_count(); +WB_END + WB_ENTRY(jint, WB_getLockStackCapacity(JNIEnv* env)) return (jint) LockStack::CAPACITY; WB_END @@ -2844,6 +2852,7 @@ static JNINativeMethod methods[] = { (void*)&WB_AddModuleExportsToAll }, {CC"deflateIdleMonitors", CC"()Z", (void*)&WB_DeflateIdleMonitors }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"getInUseMonitorCount", CC"()J", (void*)&WB_getInUseMonitorCount }, {CC"getLockStackCapacity", CC"()I", (void*)&WB_getLockStackCapacity }, {CC"supportsRecursiveLightweightLocking", CC"()Z", (void*)&WB_supportsRecursiveLightweightLocking }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, diff --git a/src/hotspot/share/prims/whitebox.hpp b/src/hotspot/share/prims/whitebox.hpp index a88f8d21843..c5072b97d4f 100644 --- a/src/hotspot/share/prims/whitebox.hpp +++ b/src/hotspot/share/prims/whitebox.hpp @@ -68,6 +68,7 @@ class WhiteBox : public AllStatic { JNINativeMethod* method_array, int method_count); static void register_extended(JNIEnv* env, jclass wbclass, JavaThread* thread); static bool compile_method(Method* method, int comp_level, int bci, JavaThread* THREAD); + static size_t get_in_use_monitor_count(); #ifdef LINUX static bool validate_cgroup(const char* proc_cgroups, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* cg_flags); #endif diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 7406af678e0..493303df661 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -69,6 +69,7 @@ public: class ObjectSynchronizer : AllStatic { friend class VMStructs; friend class ObjectMonitorDeflationLogging; + friend class WhiteBox; public: typedef enum { diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index 47cb5613171..19dd90015bf 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -21,19 +21,21 @@ * questions. */ -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /* * @test * @summary Tests that recursive locking doesn't cause excessive native memory usage * @library /test/lib - * @run driver TestRecursiveMonitorChurn + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xmx100M -XX:AsyncDeflationInterval=0 -XX:GuaranteedAsyncDeflationInterval=0 + * -Xlog:monitorinflation=trace + * TestRecursiveMonitorChurn */ + +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + public class TestRecursiveMonitorChurn { static class Monitor { public static volatile int i, j; @@ -46,50 +48,32 @@ public class TestRecursiveMonitorChurn { } } + static final WhiteBox WB = WhiteBox.getWhiteBox(); + static final int LM_MONITOR = 0; + static final int COUNT = 100000; + public static volatile Monitor monitor; - public static void main(String[] args) throws IOException { - if (args.length == 1 && args[0].equals("test")) { - // The actual test, in a forked JVM. - for (int i = 0; i < 100000; i++) { - monitor = new Monitor(); - monitor.doSomething(); + public static void main(String[] args) { + if (WB.getIntVMFlag("LockingMode") == LM_MONITOR) { + throw new SkippedException("LM_MONITOR always inflates. Invalid test."); + } + final long pre_monitor_count = WB.getInUseMonitorCount(); + System.out.println(" Precount = " + pre_monitor_count); + for (int i = 0; i < COUNT; i++) { + monitor = new Monitor(); + monitor.doSomething(); + } + System.out.println("i + j = " + (Monitor.i + Monitor.j)); + final long post_monitor_count = WB.getInUseMonitorCount(); + System.out.println("Postcount = " + post_monitor_count); + + if (pre_monitor_count != post_monitor_count) { + final long monitor_count_change = post_monitor_count - pre_monitor_count; + System.out.println("Unexpected change in monitor count: " + monitor_count_change); + if (monitor_count_change < 0) { + throw new RuntimeException("Unexpected Deflation"); } - System.out.println("i + j = " + (Monitor.i + Monitor.j)); - } else { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-Xmx100M", "-XX:AsyncDeflationInterval=0", "-XX:GuaranteedAsyncDeflationInterval=0", - "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics", - "TestRecursiveMonitorChurn", - "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.reportDiagnosticSummary(); - - output.shouldHaveExitValue(0); - - // We want to see, in the final NMT printout, a committed object monitor size that is reasonably low. - // Like this: - // - Object Monitors (reserved=208, committed=208) - // (malloc=208 #1) (at peak) - // - // Without recursive locking support, this would look more like this: - // - Object Monitors (reserved=20800624, committed=20800624) - // (malloc=20800624 #100003) (at peak) - - Pattern pat = Pattern.compile("- *Object Monitors.*reserved=(\\d+), committed=(\\d+).*"); - for (String line : output.asLines()) { - Matcher m = pat.matcher(line); - if (m.matches()) { - long reserved = Long.parseLong(m.group(1)); - long committed = Long.parseLong(m.group(2)); - System.out.println(">>>>> " + line + ": " + reserved + " - " + committed); - if (committed > 1000) { - throw new RuntimeException("Allocated too many monitors"); - } - return; - } - } - throw new RuntimeException("Did not find expected NMT output"); + throw new RuntimeException("Unexpected Inflation"); } } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 3b930aec16f..1bc309e2aec 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -119,6 +119,8 @@ public class WhiteBox { return isMonitorInflated0(obj); } + public native long getInUseMonitorCount(); + public native int getLockStackCapacity(); public native boolean supportsRecursiveLightweightLocking();