Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8153224: Monitor deflation prolong safepoints
Add support for AsyncDeflateIdleMonitors (default true); the async deflation work is performed by the ServiceThread.

Co-authored-by: Carsten Varming <varming@gmail.com>
Reviewed-by: dcubed, rehn, rkennke, cvarming, coleenp, acorn, dholmes, eosterlund
  • Loading branch information
Daniel D. Daugherty and varming committed Jun 2, 2020
1 parent 30aa1b0 commit 00f223e22fdd5d5708e7a3af5964293b3903d3e4
@@ -74,6 +74,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.inline.hpp"
@@ -490,6 +491,11 @@ 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
@@ -653,6 +653,9 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *java_thread, jobject *mo
current_jt == java_thread->active_handshaker(),
"call by myself or at direct handshake");
oop obj = NULL;
// The ObjectMonitor* can't be async deflated since we are either
// at a safepoint or the calling thread is operating on itself so
// it cannot leave the underlying wait()/enter() call.
ObjectMonitor *mon = java_thread->current_waiting_monitor();
if (mon == NULL) {
// thread is not doing an Object.wait() call
@@ -730,15 +733,21 @@ JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread
HandleMark hm;
oop wait_obj = NULL;
{
// save object of current wait() call (if any) for later comparison
// The ObjectMonitor* can't be async deflated since we are either
// at a safepoint or the calling thread is operating on itself so
// it cannot leave the underlying wait() call.
// Save object of current wait() call (if any) for later comparison.
ObjectMonitor *mon = java_thread->current_waiting_monitor();
if (mon != NULL) {
wait_obj = (oop)mon->object();
}
}
oop pending_obj = NULL;
{
// save object of current enter() call (if any) for later comparison
// The ObjectMonitor* can't be async deflated since we are either
// at a safepoint or the calling thread is operating on itself so
// it cannot leave the underlying enter() call.
// Save object of current enter() call (if any) for later comparison.
ObjectMonitor *mon = java_thread->current_pending_monitor();
if (mon != NULL) {
pending_obj = (oop)mon->object();
@@ -73,6 +73,7 @@
#include "runtime/jniHandles.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vm_version.hpp"
@@ -477,6 +478,12 @@ 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);
@@ -1448,6 +1455,12 @@ 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
@@ -1797,6 +1810,13 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
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
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -36,24 +36,24 @@ void BasicLock::print_on(outputStream* st) const {
void BasicLock::move_to(oop obj, BasicLock* dest) {
// Check to see if we need to inflate the lock. This is only needed
// if an object is locked using "this" lightweight monitor. In that
// case, the displaced_header() is unlocked, because the
// case, the displaced_header() is unlocked/is_neutral, because the
// displaced_header() contains the header for the originally unlocked
// object. However the object could have already been inflated. But it
// does not matter, the inflation will just a no-op. For other cases,
// object. However the lock could have already been inflated. But it
// does not matter, this inflation will just a no-op. For other cases,
// the displaced header will be either 0x0 or 0x3, which are location
// independent, therefore the BasicLock is free to move.
//
// During OSR we may need to relocate a BasicLock (which contains a
// displaced word) from a location in an interpreter frame to a
// new location in a compiled frame. "this" refers to the source
// basiclock in the interpreter frame. "dest" refers to the destination
// basiclock in the new compiled frame. We *always* inflate in move_to().
// The always-Inflate policy works properly, but in 1.5.0 it can sometimes
// cause performance problems in code that makes heavy use of a small # of
// uncontended locks. (We'd inflate during OSR, and then sync performance
// would subsequently plummet because the thread would be forced thru the slow-path).
// This problem has been made largely moot on IA32 by inlining the inflated fast-path
// operations in Fast_Lock and Fast_Unlock in i486.ad.
// BasicLock in the interpreter frame. "dest" refers to the destination
// BasicLock in the new compiled frame. We *always* inflate in move_to()
// when the object is locked using "this" lightweight monitor.
//
// The always-Inflate policy works properly, but it depends on the
// inflated fast-path operations in fast_lock and fast_unlock to avoid
// performance problems. See x86/macroAssembler_x86.cpp: fast_lock()
// and fast_unlock() for examples.
//
// Note that there is a way to safely swing the object's markword from
// one stack location to another. This avoids inflation. Obviously,
@@ -63,8 +63,10 @@ void BasicLock::move_to(oop obj, BasicLock* dest) {
// we'll leave that optimization for another time.

if (displaced_header().is_neutral()) {
// The object is locked and the resulting ObjectMonitor* will also be
// locked so it can't be async deflated until ownership is dropped.
ObjectSynchronizer::inflate_helper(obj);
// WARNING: We can not put check here, because the inflation
// WARNING: We cannot put a check here, because the inflation
// will not update the displaced header. Once BasicLock is inflated,
// no one should ever look at its content.
} else {
@@ -683,11 +683,21 @@ const size_t minimumSymbolTableSize = 1024;
"Disable the use of stack guard pages if the JVM is loaded " \
"on the primordial process thread") \
\
diagnostic(bool, AsyncDeflateIdleMonitors, true, \
"Deflate idle monitors using the ServiceThread.") \
\
/* notice: the max range value here is max_jint, not max_intx */ \
/* because of overflow issue */ \
diagnostic(intx, AsyncDeflationInterval, 250, \
"Async deflate idle monitors every so many milliseconds when " \
"MonitorUsedDeflationThreshold is exceeded (0 is off).") \
range(0, max_jint) \
\
experimental(intx, MonitorUsedDeflationThreshold, 90, \
"Percentage of used monitors before triggering cleanup " \
"safepoint which deflates monitors (0 is off). " \
"The check is performed on GuaranteedSafepointInterval.") \
range(0, 100) \
"Percentage of used monitors before triggering deflation (0 is " \
"off). The check is performed on GuaranteedSafepointInterval " \
"or AsyncDeflationInterval.") \
range(0, 100) \
\
experimental(intx, hashCode, 5, \
"(Unstable) select hashCode generation algorithm") \
@@ -172,8 +172,12 @@ void exit_globals() {
if (log_is_enabled(Info, monitorinflation)) {
// The ObjectMonitor subsystem uses perf counters so
// do this before perfMemory_exit().
// ObjectSynchronizer::finish_deflate_idle_monitors()'s call
// to audit_and_print_stats() is done at the Debug level.
// These other two audit_and_print_stats() calls are done at the
// Debug level at a safepoint:
// - for safepoint based deflation auditing:
// ObjectSynchronizer::finish_deflate_idle_monitors()
// - for async deflation auditing:
// ObjectSynchronizer::do_safepoint_work()
ObjectSynchronizer::audit_and_print_stats(true /* on_exit */);
}
perfMemory_exit();

0 comments on commit 00f223e

Please sign in to comment.