--- old/src/hotspot/share/prims/jvm.cpp 2019-05-25 10:47:48.238887544 -0400 +++ new/src/hotspot/share/prims/jvm.cpp 2019-05-25 10:47:47.654887513 -0400 @@ -487,8 +487,8 @@ if (!DisableExplicitGC) { if (AsyncDeflateIdleMonitors) { // AsyncDeflateIdleMonitors needs to know when System.gc() is - // called so any special clean up can be done at a safepoint. - ObjectSynchronizer::set_is_cleanup_requested(true); + // 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); } --- old/src/hotspot/share/runtime/globals.hpp 2019-05-25 10:47:49.934887632 -0400 +++ new/src/hotspot/share/runtime/globals.hpp 2019-05-25 10:47:49.210887594 -0400 @@ -729,11 +729,18 @@ diagnostic(bool, AsyncDeflateIdleMonitors, true, \ "Deflate idle monitors using JavaThreads and 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 AsyncDeflateInterval.") \ + range(0, 100) \ \ experimental(intx, hashCode, 5, \ "(Unstable) select hashCode generation algorithm") \ --- old/src/hotspot/share/runtime/safepoint.cpp 2019-05-25 10:47:51.694887724 -0400 +++ new/src/hotspot/share/runtime/safepoint.cpp 2019-05-25 10:47:50.982887687 -0400 @@ -510,8 +510,9 @@ } bool SafepointSynchronize::is_cleanup_needed() { - // Need a safepoint if there are many monitors to deflate. - if (ObjectSynchronizer::is_cleanup_needed()) return true; + // Need a cleanup safepoint if there are too many monitors in use + // and the monitor deflation needs to be done at a safepoint. + if (ObjectSynchronizer::is_safepoint_deflation_needed()) return true; // Need a safepoint if some inline cache buffers is non-empty if (!InlineCacheBuffer::is_empty()) return true; if (StringTable::needs_rehashing()) return true; --- old/src/hotspot/share/runtime/serviceThread.cpp 2019-05-25 10:47:53.734887830 -0400 +++ new/src/hotspot/share/runtime/serviceThread.cpp 2019-05-25 10:47:52.750887779 -0400 @@ -156,10 +156,13 @@ (oopstorage_work = needs_oopstorage_cleanup(oopstorages, oopstorages_cleanup, oopstorage_count)) | - (deflate_idle_monitors = ObjectSynchronizer::gOmShouldDeflateIdleMonitors()) + (deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed()) ) == 0) { // Wait until notified that there is some work to do. - ml.wait(); + // If AsyncDeflateIdleMonitors, then we wait for + // GuaranteedSafepointInterval so that is_async_deflation_needed() + // is checked at the same interval. + ml.wait(AsyncDeflateIdleMonitors ? GuaranteedSafepointInterval : 0); } if (has_jvmti_events) { @@ -205,9 +208,22 @@ if (deflate_idle_monitors) { // Deflate any global idle monitors. + ObjectSynchronizer::deflate_global_idle_monitors_using_JT(); + // deflate_per_thread_idle_monitors_using_JT() is called by // each JavaThread from ObjectSynchronizer::omAlloc() as needed. - ObjectSynchronizer::deflate_global_idle_monitors_using_JT(); + int count = 0; + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + if (jt->omInUseCount > 0) { + // This JavaThread is using monitors so mark it. + jt->omShouldDeflateIdleMonitors = true; + count++; + } + } + if (count > 0) { + log_debug(monitorinflation)("requesting async deflation of idle monitors for %d thread(s).", count); + } + ObjectSynchronizer::set_is_async_deflation_requested(false); // async deflation has been requested } } } --- old/src/hotspot/share/runtime/synchronizer.cpp 2019-05-25 10:47:55.414887918 -0400 +++ new/src/hotspot/share/runtime/synchronizer.cpp 2019-05-25 10:47:54.654887878 -0400 @@ -125,8 +125,9 @@ ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL; // count of entries in gOmInUseList int ObjectSynchronizer::gOmInUseCount = 0; -bool ObjectSynchronizer::_gOmShouldDeflateIdleMonitors = false; -bool volatile ObjectSynchronizer::_is_cleanup_requested = false; +bool volatile ObjectSynchronizer::_is_async_deflation_requested = false; +bool volatile ObjectSynchronizer::_is_special_deflation_requested = false; +jlong ObjectSynchronizer::_last_async_deflation_time_ns = 0; static volatile intptr_t gListLock = 0; // protects global monitor lists static volatile int gMonitorFreeCount = 0; // # on gFreeList @@ -1013,18 +1014,55 @@ if (gMonitorPopulation == 0) { return false; } - int monitors_used = gMonitorPopulation - gMonitorFreeCount; - int monitor_usage = (monitors_used * 100LL) / gMonitorPopulation; - return monitor_usage > MonitorUsedDeflationThreshold; + if (MonitorUsedDeflationThreshold > 0) { + int monitors_used = gMonitorPopulation - gMonitorFreeCount; + int monitor_usage = (monitors_used * 100LL) / gMonitorPopulation; + return monitor_usage > MonitorUsedDeflationThreshold; + } + return false; } -bool ObjectSynchronizer::is_cleanup_needed() { - if (MonitorUsedDeflationThreshold > 0) { - return monitors_used_above_threshold(); +bool ObjectSynchronizer::is_async_deflation_needed() { + if (!AsyncDeflateIdleMonitors) { + return false; + } + if (is_async_deflation_requested()) { + // Async deflation request. + return true; + } + if (AsyncDeflationInterval > 0 && + time_since_last_async_deflation_ms() > AsyncDeflationInterval && + monitors_used_above_threshold()) { + // It's been longer than our specified deflate interval and there + // 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 false; + } + if (is_special_deflation_requested()) { + // For AsyncDeflateIdleMonitors only do a safepoint deflation + // if there is a special deflation request. + return true; } return false; } +jlong ObjectSynchronizer::time_since_last_async_deflation_ms() { + return (os::javaTimeNanos() - _last_async_deflation_time_ns) / (NANOUNITS / MILLIUNITS); +} + void ObjectSynchronizer::oops_do(OopClosure* f) { // We only scan the global used list here (for moribund threads), and // the thread-local monitors in Thread::oops_do(). @@ -1118,9 +1156,11 @@ if (jt->omShouldDeflateIdleMonitors && jt->omInUseCount > 0 && cause != inflate_cause_vm_internal) { // Deflate any per-thread idle monitors for this JavaThread if - // this is not an internal inflation. Clean up your own mess. - // (Gibbs Rule 45) Otherwise, skip this cleanup. - // deflate_global_idle_monitors_using_JT() is called by the ServiceThread. + // this is not an internal inflation; internal inflations can + // occur in places where it is not safe to pause for a safepoint. + // Clean up your own mess. (Gibbs Rule 45) Otherwise, skip this + // deflation. deflate_global_idle_monitors_using_JT() is called + // by the ServiceThread. debug_only(jt->check_for_valid_safepoint_state(false);) ObjectSynchronizer::deflate_per_thread_idle_monitors_using_JT(); } @@ -1703,16 +1743,16 @@ // The per-thread in-use lists are handled in // ParallelSPCleanupThreadClosure::do_thread(). - if (!AsyncDeflateIdleMonitors || is_cleanup_requested()) { - // Use the older mechanism for the global in-use list or - // if a special cleanup has been requested. + 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. ObjectSynchronizer::deflate_idle_monitors(_counters); return; } - log_debug(monitorinflation)("requesting deflation of idle monitors."); - // Request deflation of global idle monitors by the ServiceThread: - _gOmShouldDeflateIdleMonitors = true; + log_debug(monitorinflation)("requesting async deflation of idle monitors."); + // Request deflation of idle monitors by the ServiceThread: + set_is_async_deflation_requested(true); MonitorLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); ml.notify_all(); } @@ -2041,8 +2081,8 @@ if (AsyncDeflateIdleMonitors) { // Nothing to do when global idle ObjectMonitors are deflated using - // a JavaThread unless a special cleanup has been requested. - if (!is_cleanup_requested()) { + // a JavaThread unless a special deflation has been requested. + if (!is_special_deflation_requested()) { return; } } @@ -2106,8 +2146,6 @@ assert(Thread::current()->is_Java_thread(), "precondition"); JavaThread * self = JavaThread::current(); - _gOmShouldDeflateIdleMonitors = false; - deflate_common_idle_monitors_using_JT(true /* is_global */, self); } @@ -2227,13 +2265,13 @@ // worker thread, then the reported time will likely be more // than a beginning to end measurement of the phase. // Note: AsyncDeflateIdleMonitors only deflates per-thread idle - // monitors at a safepoint when a special cleanup has been requested. + // monitors at a safepoint when a special deflation has been requested. log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs, monitors=%d", counters->perThreadTimes, counters->perThreadScavenged); - bool needs_special_cleanup = is_cleanup_requested(); - if (!AsyncDeflateIdleMonitors || needs_special_cleanup) { + bool needs_special_deflation = is_special_deflation_requested(); + if (!AsyncDeflateIdleMonitors || needs_special_deflation) { // AsyncDeflateIdleMonitors does not use these counters unless - // there is a special cleanup request. + // there is a special deflation request. gMonitorFreeCount += counters->nScavenged; @@ -2256,8 +2294,8 @@ ForceMonitorScavenge = 0; // Reset GVars.stwRandom = os::random(); GVars.stwCycle++; - if (needs_special_cleanup) { - set_is_cleanup_requested(false); // special clean up is done + if (needs_special_deflation) { + set_is_special_deflation_requested(false); // special deflation is done } } @@ -2265,9 +2303,9 @@ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (AsyncDeflateIdleMonitors) { - if (!is_cleanup_requested()) { - // Mark the JavaThread for idle monitor cleanup if a special - // cleanup has NOT been requested. + if (!is_special_deflation_requested()) { + // Mark the JavaThread for idle monitor deflation if a special + // deflation has NOT been requested. if (thread->omInUseCount > 0) { // This JavaThread is using monitors so mark it. thread->omShouldDeflateIdleMonitors = true; --- old/src/hotspot/share/runtime/synchronizer.hpp 2019-05-25 10:47:57.134888008 -0400 +++ new/src/hotspot/share/runtime/synchronizer.hpp 2019-05-25 10:47:56.418887971 -0400 @@ -162,9 +162,13 @@ static bool deflate_monitor_using_JT(ObjectMonitor* mid, ObjectMonitor** freeHeadp, ObjectMonitor** freeTailp); - static bool is_cleanup_needed(); - static bool is_cleanup_requested() { return _is_cleanup_requested; } - static void set_is_cleanup_requested(bool new_value) { _is_cleanup_requested = new_value; } + 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 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 static void thread_local_used_oops_do(Thread* thread, OopClosure* f); @@ -189,7 +193,6 @@ static int log_monitor_list_counts(outputStream * out); static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0; - static bool gOmShouldDeflateIdleMonitors() { return _gOmShouldDeflateIdleMonitors; } static void do_safepoint_work(DeflateMonitorCounters* _counters); private: @@ -205,8 +208,9 @@ static ObjectMonitor * volatile gOmInUseList; // count of entries in gOmInUseList static int gOmInUseCount; - static bool _gOmShouldDeflateIdleMonitors; - static volatile bool _is_cleanup_requested; + static volatile bool _is_async_deflation_requested; + static volatile bool _is_special_deflation_requested; + static jlong _last_async_deflation_time_ns; // Process oops in all global used monitors (i.e. moribund thread's monitors) static void global_used_oops_do(OopClosure* f); --- old/src/hotspot/share/runtime/vmOperations.cpp 2019-05-25 10:47:58.826888096 -0400 +++ new/src/hotspot/share/runtime/vmOperations.cpp 2019-05-25 10:47:58.234888065 -0400 @@ -41,6 +41,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/sweeper.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vmOperations.hpp" @@ -471,6 +472,17 @@ } } +bool VM_Exit::doit_prologue() { + if (AsyncDeflateIdleMonitors) { + // AsyncDeflateIdleMonitors does a special deflation at the VM_Exit + // safepoint in order to reduce the in-use monitor population that + // is reported ObjectSynchronizer::log_in_use_monitor_details() at + // VM exit. + ObjectSynchronizer::set_is_special_deflation_requested(true); + } + return true; +} + void VM_Exit::doit() { if (VerifyBeforeExit) { --- old/src/hotspot/share/runtime/vmOperations.hpp 2019-05-25 10:48:00.578888188 -0400 +++ new/src/hotspot/share/runtime/vmOperations.hpp 2019-05-25 10:47:59.822888148 -0400 @@ -498,6 +498,7 @@ } } VMOp_Type type() const { return VMOp_Exit; } + bool doit_prologue(); void doit(); }; --- old/src/hotspot/share/runtime/vmThread.cpp 2019-05-25 10:48:02.142888269 -0400 +++ new/src/hotspot/share/runtime/vmThread.cpp 2019-05-25 10:48:01.490888235 -0400 @@ -40,6 +40,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/safepoint.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" @@ -316,6 +317,14 @@ assert(should_terminate(), "termination flag must be set"); } + if (AsyncDeflateIdleMonitors) { + // AsyncDeflateIdleMonitors does a special deflation at the final + // safepoint in order to reduce the in-use monitor population that + // is reported ObjectSynchronizer::log_in_use_monitor_details() at + // VM exit. + ObjectSynchronizer::set_is_special_deflation_requested(true); + } + // 4526887 let VM thread exit at Safepoint _cur_vm_operation = &halt_op; SafepointSynchronize::begin(); --- old/test/hotspot/gtest/oops/test_markOop.cpp 2019-05-25 10:48:04.078888370 -0400 +++ new/test/hotspot/gtest/oops/test_markOop.cpp 2019-05-25 10:48:03.282888329 -0400 @@ -117,6 +117,10 @@ // This is no longer biased, because ObjectLocker revokes the bias. assert_test_pattern(h_obj, "is_neutral no_hash"); + // Hash the object then print it. + intx hash = h_obj->identity_hash(); + assert_test_pattern(h_obj, "is_neutral hash=0x"); + // Wait gets the lock inflated. { ObjectLocker ol(h_obj, THREAD); @@ -131,14 +135,18 @@ done.wait_with_safepoint_check(THREAD); // wait till the thread is done. } - // Make the object older. Not all GCs use this field. - Universe::heap()->collect(GCCause::_java_lang_system_gc); - if (UseParallelGC) { - assert_test_pattern(h_obj, "is_neutral no_hash age 1"); - } + if (!AsyncDeflateIdleMonitors) { + // With AsyncDeflateIdleMonitors, the collect() call below + // does not guarantee monitor deflation. + // Make the object older. Not all GCs use this field. + Universe::heap()->collect(GCCause::_java_lang_system_gc); + if (UseParallelGC) { + assert_test_pattern(h_obj, "is_neutral no_hash age 1"); + } - // Hash the object then print it. - intx hash = h_obj->identity_hash(); - assert_test_pattern(h_obj, "is_neutral hash=0x"); + // Hash the object then print it. + intx hash = h_obj->identity_hash(); + assert_test_pattern(h_obj, "is_neutral hash=0x"); + } } #endif // PRODUCT