8320304: Refactor and simplify monitor deflation functions

Reviewed-by: dcubed, dholmes
This commit is contained in:
Stefan Karlsson 2023-11-30 12:40:23 +00:00
parent da7cf258bb
commit 03759e892d
2 changed files with 154 additions and 123 deletions

View File

@ -63,6 +63,8 @@
#include "utilities/linkedlist.hpp" #include "utilities/linkedlist.hpp"
#include "utilities/preserveException.hpp" #include "utilities/preserveException.hpp"
class ObjectMonitorDeflationLogging;
void MonitorList::add(ObjectMonitor* m) { void MonitorList::add(ObjectMonitor* m) {
ObjectMonitor* head; ObjectMonitor* head;
do { do {
@ -84,17 +86,26 @@ size_t MonitorList::max() const {
return Atomic::load(&_max); return Atomic::load(&_max);
} }
class ObjectMonitorDeflationSafepointer : public StackObj {
JavaThread* const _current;
ObjectMonitorDeflationLogging* const _log;
public:
ObjectMonitorDeflationSafepointer(JavaThread* current, ObjectMonitorDeflationLogging* log)
: _current(current), _log(log) {}
void block_for_safepoint(const char* op_name, const char* count_name, size_t counter);
};
// Walk the in-use list and unlink deflated ObjectMonitors. // Walk the in-use list and unlink deflated ObjectMonitors.
// Returns the number of unlinked ObjectMonitors. // Returns the number of unlinked ObjectMonitors.
size_t MonitorList::unlink_deflated(Thread* current, LogStream* ls, size_t MonitorList::unlink_deflated(size_t deflated_count,
elapsedTimer* timer_p, GrowableArray<ObjectMonitor*>* unlinked_list,
size_t deflated_count, ObjectMonitorDeflationSafepointer* safepointer) {
GrowableArray<ObjectMonitor*>* unlinked_list) {
size_t unlinked_count = 0; size_t unlinked_count = 0;
ObjectMonitor* prev = nullptr; ObjectMonitor* prev = nullptr;
ObjectMonitor* m = Atomic::load_acquire(&_head); ObjectMonitor* m = Atomic::load_acquire(&_head);
// The in-use list head can be null during the final audit.
while (m != nullptr) { while (m != nullptr) {
if (m->is_being_async_deflated()) { if (m->is_being_async_deflated()) {
// Find next live ObjectMonitor. Batch up the unlinkable monitors, so we can // Find next live ObjectMonitor. Batch up the unlinkable monitors, so we can
@ -154,12 +165,8 @@ size_t MonitorList::unlink_deflated(Thread* current, LogStream* ls,
m = m->next_om(); m = m->next_om();
} }
if (current->is_Java_thread()) { // Must check for a safepoint/handshake and honor it.
// A JavaThread must check for a safepoint/handshake and honor it. safepointer->block_for_safepoint("unlinking", "unlinked_count", unlinked_count);
ObjectSynchronizer::chk_for_block_req(JavaThread::cast(current), "unlinking",
"unlinked_count", unlinked_count,
ls, timer_p);
}
} }
#ifdef ASSERT #ifdef ASSERT
@ -1536,40 +1543,10 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop object,
} }
} }
void ObjectSynchronizer::chk_for_block_req(JavaThread* current, const char* op_name,
const char* cnt_name, size_t cnt,
LogStream* ls, elapsedTimer* timer_p) {
if (!SafepointMechanism::should_process(current)) {
return;
}
// A safepoint/handshake has started.
if (ls != nullptr) {
timer_p->stop();
ls->print_cr("pausing %s: %s=" SIZE_FORMAT ", in_use_list stats: ceiling="
SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
op_name, cnt_name, cnt, in_use_list_ceiling(),
_in_use_list.count(), _in_use_list.max());
}
{
// Honor block request.
ThreadBlockInVM tbivm(current);
}
if (ls != nullptr) {
ls->print_cr("resuming %s: in_use_list stats: ceiling=" SIZE_FORMAT
", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, op_name,
in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max());
timer_p->start();
}
}
// Walk the in-use list and deflate (at most MonitorDeflationMax) idle // Walk the in-use list and deflate (at most MonitorDeflationMax) idle
// ObjectMonitors. Returns the number of deflated ObjectMonitors. // ObjectMonitors. Returns the number of deflated ObjectMonitors.
// //
size_t ObjectSynchronizer::deflate_monitor_list(Thread* current, LogStream* ls, size_t ObjectSynchronizer::deflate_monitor_list(ObjectMonitorDeflationSafepointer* safepointer) {
elapsedTimer* timer_p) {
MonitorList::Iterator iter = _in_use_list.iterator(); MonitorList::Iterator iter = _in_use_list.iterator();
size_t deflated_count = 0; size_t deflated_count = 0;
@ -1582,11 +1559,8 @@ size_t ObjectSynchronizer::deflate_monitor_list(Thread* current, LogStream* ls,
deflated_count++; deflated_count++;
} }
if (current->is_Java_thread()) { // Must check for a safepoint/handshake and honor it.
// A JavaThread must check for a safepoint/handshake and honor it. safepointer->block_for_safepoint("deflation", "deflated_count", deflated_count);
chk_for_block_req(JavaThread::cast(current), "deflation", "deflated_count",
deflated_count, ls, timer_p);
}
} }
return deflated_count; return deflated_count;
@ -1612,104 +1586,162 @@ public:
}; };
}; };
static size_t delete_monitors(JavaThread* current, GrowableArray<ObjectMonitor*>* delete_list, static size_t delete_monitors(GrowableArray<ObjectMonitor*>* delete_list,
LogStream* ls, elapsedTimer* timer_p) { ObjectMonitorDeflationSafepointer* safepointer) {
NativeHeapTrimmer::SuspendMark sm("monitor deletion"); NativeHeapTrimmer::SuspendMark sm("monitor deletion");
size_t deleted_count = 0; size_t deleted_count = 0;
for (ObjectMonitor* monitor: *delete_list) { for (ObjectMonitor* monitor: *delete_list) {
delete monitor; delete monitor;
deleted_count++; deleted_count++;
// A JavaThread must check for a safepoint/handshake and honor it. // A JavaThread must check for a safepoint/handshake and honor it.
ObjectSynchronizer::chk_for_block_req(current, "deletion", "deleted_count", safepointer->block_for_safepoint("deletion", "deleted_count", deleted_count);
deleted_count, ls, timer_p);
} }
return deleted_count; return deleted_count;
} }
class ObjectMonitorDeflationLogging: public StackObj {
LogStreamHandle(Debug, monitorinflation) _debug;
LogStreamHandle(Info, monitorinflation) _info;
LogStream* _stream;
elapsedTimer _timer;
size_t ceiling() const { return ObjectSynchronizer::in_use_list_ceiling(); }
size_t count() const { return ObjectSynchronizer::_in_use_list.count(); }
size_t max() const { return ObjectSynchronizer::_in_use_list.max(); }
public:
ObjectMonitorDeflationLogging()
: _debug(), _info(), _stream(nullptr) {
if (_debug.is_enabled()) {
_stream = &_debug;
} else if (_info.is_enabled()) {
_stream = &_info;
}
}
void begin() {
if (_stream != nullptr) {
_stream->print_cr("begin deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
ceiling(), count(), max());
_timer.start();
}
}
void before_handshake(size_t unlinked_count) {
if (_stream != nullptr) {
_timer.stop();
_stream->print_cr("before handshaking: unlinked_count=" SIZE_FORMAT
", in_use_list stats: ceiling=" SIZE_FORMAT ", count="
SIZE_FORMAT ", max=" SIZE_FORMAT,
unlinked_count, ceiling(), count(), max());
}
}
void after_handshake() {
if (_stream != nullptr) {
_stream->print_cr("after handshaking: in_use_list stats: ceiling="
SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
ceiling(), count(), max());
_timer.start();
}
}
void end(size_t deflated_count, size_t unlinked_count) {
if (_stream != nullptr) {
_timer.stop();
if (deflated_count != 0 || unlinked_count != 0 || _debug.is_enabled()) {
_stream->print_cr("deflated_count=" SIZE_FORMAT ", {unlinked,deleted}_count=" SIZE_FORMAT " monitors in %3.7f secs",
deflated_count, unlinked_count, _timer.seconds());
}
_stream->print_cr("end deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
ceiling(), count(), max());
}
}
void before_block_for_safepoint(const char* op_name, const char* cnt_name, size_t cnt) {
if (_stream != nullptr) {
_timer.stop();
_stream->print_cr("pausing %s: %s=" SIZE_FORMAT ", in_use_list stats: ceiling="
SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
op_name, cnt_name, cnt, ceiling(), count(), max());
}
}
void after_block_for_safepoint(const char* op_name) {
if (_stream != nullptr) {
_stream->print_cr("resuming %s: in_use_list stats: ceiling=" SIZE_FORMAT
", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, op_name,
ceiling(), count(), max());
_timer.start();
}
}
};
void ObjectMonitorDeflationSafepointer::block_for_safepoint(const char* op_name, const char* count_name, size_t counter) {
if (!SafepointMechanism::should_process(_current)) {
return;
}
// A safepoint/handshake has started.
_log->before_block_for_safepoint(op_name, count_name, counter);
{
// Honor block request.
ThreadBlockInVM tbivm(_current);
}
_log->after_block_for_safepoint(op_name);
}
// This function is called by the MonitorDeflationThread to deflate // This function is called by the MonitorDeflationThread to deflate
// ObjectMonitors. // ObjectMonitors.
size_t ObjectSynchronizer::deflate_idle_monitors() { size_t ObjectSynchronizer::deflate_idle_monitors() {
Thread* current = Thread::current(); JavaThread* current = JavaThread::current();
if (current->is_Java_thread()) { assert(current->is_monitor_deflation_thread(), "The only monitor deflater");
// The async deflation request has been processed.
_last_async_deflation_time_ns = os::javaTimeNanos();
set_is_async_deflation_requested(false);
}
LogStreamHandle(Debug, monitorinflation) lsh_debug; // The async deflation request has been processed.
LogStreamHandle(Info, monitorinflation) lsh_info; _last_async_deflation_time_ns = os::javaTimeNanos();
LogStream* ls = nullptr; set_is_async_deflation_requested(false);
if (log_is_enabled(Debug, monitorinflation)) {
ls = &lsh_debug;
} else if (log_is_enabled(Info, monitorinflation)) {
ls = &lsh_info;
}
elapsedTimer timer; ObjectMonitorDeflationLogging log;
if (ls != nullptr) { ObjectMonitorDeflationSafepointer safepointer(current, &log);
ls->print_cr("begin deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); log.begin();
timer.start();
}
// Deflate some idle ObjectMonitors. // Deflate some idle ObjectMonitors.
size_t deflated_count = deflate_monitor_list(current, ls, &timer); size_t deflated_count = deflate_monitor_list(&safepointer);
// Unlink the deflated ObjectMonitors from the in-use list.
size_t unlinked_count = 0; size_t unlinked_count = 0;
size_t deleted_count = 0; size_t deleted_count = 0;
if (deflated_count > 0) { if (deflated_count > 0) {
// There are ObjectMonitors that have been deflated. ResourceMark rm(current);
// Unlink deflated ObjectMonitors from the in-use list.
ResourceMark rm;
GrowableArray<ObjectMonitor*> delete_list((int)deflated_count); GrowableArray<ObjectMonitor*> delete_list((int)deflated_count);
unlinked_count = _in_use_list.unlink_deflated(current, ls, &timer, deflated_count, &delete_list); unlinked_count = _in_use_list.unlink_deflated(deflated_count, &delete_list, &safepointer);
if (current->is_monitor_deflation_thread()) {
if (ls != nullptr) {
timer.stop();
ls->print_cr("before handshaking: unlinked_count=" SIZE_FORMAT
", in_use_list stats: ceiling=" SIZE_FORMAT ", count="
SIZE_FORMAT ", max=" SIZE_FORMAT,
unlinked_count, in_use_list_ceiling(),
_in_use_list.count(), _in_use_list.max());
}
// A JavaThread needs to handshake in order to safely free the log.before_handshake(unlinked_count);
// ObjectMonitors that were deflated in this cycle.
HandshakeForDeflation hfd_hc;
Handshake::execute(&hfd_hc);
// Also, we sync and desync GC threads around the handshake, so that they can
// safely read the mark-word and look-through to the object-monitor, without
// being afraid that the object-monitor is going away.
VM_RendezvousGCThreads sync_gc;
VMThread::execute(&sync_gc);
if (ls != nullptr) { // A JavaThread needs to handshake in order to safely free the
ls->print_cr("after handshaking: in_use_list stats: ceiling=" // ObjectMonitors that were deflated in this cycle.
SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, HandshakeForDeflation hfd_hc;
in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); Handshake::execute(&hfd_hc);
timer.start(); // Also, we sync and desync GC threads around the handshake, so that they can
} // safely read the mark-word and look-through to the object-monitor, without
} else { // being afraid that the object-monitor is going away.
// This is not a monitor deflation thread. VM_RendezvousGCThreads sync_gc;
// No handshake or rendezvous is needed when we are already at safepoint. VMThread::execute(&sync_gc);
assert_at_safepoint();
} log.after_handshake();
// After the handshake, safely free the ObjectMonitors that were // After the handshake, safely free the ObjectMonitors that were
// deflated and unlinked in this cycle. // deflated and unlinked in this cycle.
deleted_count = delete_monitors(JavaThread::cast(current), &delete_list, ls, &timer);
// Delete the unlinked ObjectMonitors.
deleted_count = delete_monitors(&delete_list, &safepointer);
assert(unlinked_count == deleted_count, "must be"); assert(unlinked_count == deleted_count, "must be");
} }
if (ls != nullptr) { log.end(deflated_count, unlinked_count);
timer.stop();
if (deflated_count != 0 || unlinked_count != 0 || log_is_enabled(Debug, monitorinflation)) {
ls->print_cr("deflated_count=" SIZE_FORMAT ", {unlinked,deleted}_count=" SIZE_FORMAT " monitors in %3.7f secs",
deflated_count, unlinked_count, timer.seconds());
}
ls->print_cr("end deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max());
}
OM_PERFDATA_OP(MonExtant, set_value(_in_use_list.count())); OM_PERFDATA_OP(MonExtant, set_value(_in_use_list.count()));
OM_PERFDATA_OP(Deflations, inc(deflated_count)); OM_PERFDATA_OP(Deflations, inc(deflated_count));

View File

@ -34,6 +34,7 @@
template <typename T> class GrowableArray; template <typename T> class GrowableArray;
class LogStream; class LogStream;
class ObjectMonitor; class ObjectMonitor;
class ObjectMonitorDeflationSafepointer;
class ThreadsList; class ThreadsList;
class MonitorList { class MonitorList {
@ -46,9 +47,9 @@ private:
public: public:
void add(ObjectMonitor* monitor); void add(ObjectMonitor* monitor);
size_t unlink_deflated(Thread* current, LogStream* ls, elapsedTimer* timer_p, size_t unlink_deflated(size_t deflated_count,
size_t deflated_count, GrowableArray<ObjectMonitor*>* unlinked_list,
GrowableArray<ObjectMonitor*>* unlinked_list); ObjectMonitorDeflationSafepointer* safepointer);
size_t count() const; size_t count() const;
size_t max() const; size_t max() const;
@ -67,6 +68,7 @@ public:
class ObjectSynchronizer : AllStatic { class ObjectSynchronizer : AllStatic {
friend class VMStructs; friend class VMStructs;
friend class ObjectMonitorDeflationLogging;
public: public:
typedef enum { typedef enum {
@ -148,10 +150,7 @@ class ObjectSynchronizer : AllStatic {
static size_t deflate_idle_monitors(); static size_t deflate_idle_monitors();
// Deflate idle monitors: // Deflate idle monitors:
static void chk_for_block_req(JavaThread* current, const char* op_name, static size_t deflate_monitor_list(ObjectMonitorDeflationSafepointer* safepointer);
const char* cnt_name, size_t cnt, LogStream* ls,
elapsedTimer* timer_p);
static size_t deflate_monitor_list(Thread* current, LogStream* ls, elapsedTimer* timer_p);
static size_t in_use_list_ceiling(); static size_t in_use_list_ceiling();
static void dec_in_use_list_ceiling(); static void dec_in_use_list_ceiling();
static void inc_in_use_list_ceiling(); static void inc_in_use_list_ceiling();