8320304: Refactor and simplify monitor deflation functions
Reviewed-by: dcubed, dholmes
This commit is contained in:
parent
da7cf258bb
commit
03759e892d
@ -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));
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user