Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8246477: add whitebox support for deflating idle monitors
Reviewed-by: dholmes, eosterlund
  • Loading branch information
Daniel D. Daugherty committed Jun 24, 2020
1 parent 362f168 commit 3e4ad5d8d138a37eeaee01ab7b061c6299fb7e26
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 79 deletions.
@@ -493,11 +493,6 @@ JVM_END
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
@@ -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_END

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_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString
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 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
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 @@ static JNINativeMethod methods[] = {
(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 },
@@ -121,7 +121,6 @@ static volatile intptr_t gInflationLocks[NINFLATIONLOCKS];
// 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 @@ bool ObjectSynchronizer::is_async_deflation_needed() {
// 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();
}
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
}
}
return false;
}
if (is_special_deflation_requested()) {
// For AsyncDeflateIdleMonitors only do a safepoint deflation
// if there is a special deflation request.
return true;
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;
}
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 @@ void ObjectSynchronizer::do_safepoint_work(DeflateMonitorCounters* counters) {
// 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 @@ void ObjectSynchronizer::deflate_idle_monitors(DeflateMonitorCounters* counters)

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 @@ void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
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 @@ void ObjectSynchronizer::deflate_common_idle_monitors_using_JT(bool is_global, J
}

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 @@ void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* co
// 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 @@ void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* co

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;
}

@@ -161,9 +161,9 @@ class ObjectSynchronizer : AllStatic {
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 @@ class ObjectSynchronizer : AllStatic {
// 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:
@@ -432,11 +432,10 @@ int VM_Exit::wait_for_threads_in_native_to_block() {

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;
}
@@ -261,11 +261,10 @@ void VMThread::run() {
}

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
@@ -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 Object inflateMonitor(Object monitor) throws Exception {
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.");
@@ -203,6 +203,10 @@ public static void main(String[] args) throws ClassNotFoundException, Instantiat

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",
@@ -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.");
}
}
}

0 comments on commit 3e4ad5d

Please sign in to comment.