mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8246476: remove AsyncDeflateIdleMonitors option and the safepoint based deflation mechanism
Reviewed-by: dholmes, pchilanomate, coleenp
This commit is contained in:
parent
231a8408b2
commit
7436ef236e
14 changed files with 144 additions and 630 deletions
|
@ -688,9 +688,6 @@ const size_t minimumSymbolTableSize = 1024;
|
||||||
"Disable the use of stack guard pages if the JVM is loaded " \
|
"Disable the use of stack guard pages if the JVM is loaded " \
|
||||||
"on the primordial process thread") \
|
"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 */ \
|
/* notice: the max range value here is max_jint, not max_intx */ \
|
||||||
/* because of overflow issue */ \
|
/* because of overflow issue */ \
|
||||||
diagnostic(intx, AsyncDeflationInterval, 250, \
|
diagnostic(intx, AsyncDeflationInterval, 250, \
|
||||||
|
|
|
@ -170,10 +170,8 @@ void exit_globals() {
|
||||||
if (log_is_enabled(Info, monitorinflation)) {
|
if (log_is_enabled(Info, monitorinflation)) {
|
||||||
// The ObjectMonitor subsystem uses perf counters so
|
// The ObjectMonitor subsystem uses perf counters so
|
||||||
// do this before perfMemory_exit().
|
// do this before perfMemory_exit().
|
||||||
// These other two audit_and_print_stats() calls are done at the
|
// This other audit_and_print_stats() call is done at the
|
||||||
// Debug level at a safepoint:
|
// Debug level at a safepoint:
|
||||||
// - for safepoint based deflation auditing:
|
|
||||||
// ObjectSynchronizer::finish_deflate_idle_monitors()
|
|
||||||
// - for async deflation auditing:
|
// - for async deflation auditing:
|
||||||
// ObjectSynchronizer::do_safepoint_work()
|
// ObjectSynchronizer::do_safepoint_work()
|
||||||
ObjectSynchronizer::audit_and_print_stats(true /* on_exit */);
|
ObjectSynchronizer::audit_and_print_stats(true /* on_exit */);
|
||||||
|
|
|
@ -290,8 +290,6 @@ bool ObjectMonitor::enter(TRAPS) {
|
||||||
JavaThread * jt = (JavaThread *) Self;
|
JavaThread * jt = (JavaThread *) Self;
|
||||||
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
|
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||||
assert(jt->thread_state() != _thread_blocked, "invariant");
|
assert(jt->thread_state() != _thread_blocked, "invariant");
|
||||||
assert(AsyncDeflateIdleMonitors || this->object() != NULL, "invariant");
|
|
||||||
assert(AsyncDeflateIdleMonitors || contentions() >= 0, "must not be negative: contentions=%d", contentions());
|
|
||||||
|
|
||||||
// Keep track of contention for JVM/TI and M&M queries.
|
// Keep track of contention for JVM/TI and M&M queries.
|
||||||
add_to_contentions(1);
|
add_to_contentions(1);
|
||||||
|
@ -455,12 +453,12 @@ void ObjectMonitor::install_displaced_markword_in_object(const oop obj) {
|
||||||
// deflation so we're done here.
|
// deflation so we're done here.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ADIM_guarantee(l_object == obj, "object=" INTPTR_FORMAT " must equal obj="
|
assert(l_object == obj, "object=" INTPTR_FORMAT " must equal obj="
|
||||||
INTPTR_FORMAT, p2i(l_object), p2i(obj));
|
INTPTR_FORMAT, p2i(l_object), p2i(obj));
|
||||||
|
|
||||||
markWord dmw = header();
|
markWord dmw = header();
|
||||||
// The dmw has to be neutral (not NULL, not locked and not marked).
|
// The dmw has to be neutral (not NULL, not locked and not marked).
|
||||||
ADIM_guarantee(dmw.is_neutral(), "must be neutral: dmw=" INTPTR_FORMAT, dmw.value());
|
assert(dmw.is_neutral(), "must be neutral: dmw=" INTPTR_FORMAT, dmw.value());
|
||||||
|
|
||||||
// Install displaced mark word if the object's header still points
|
// Install displaced mark word if the object's header still points
|
||||||
// to this ObjectMonitor. More than one racing caller to this function
|
// to this ObjectMonitor. More than one racing caller to this function
|
||||||
|
@ -487,10 +485,6 @@ void ObjectMonitor::install_displaced_markword_in_object(const oop obj) {
|
||||||
// used for diagnostic output.
|
// used for diagnostic output.
|
||||||
const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
|
const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
|
||||||
ss->print("is_busy: waiters=%d, ", _waiters);
|
ss->print("is_busy: waiters=%d, ", _waiters);
|
||||||
if (!AsyncDeflateIdleMonitors) {
|
|
||||||
ss->print("contentions=%d, ", contentions());
|
|
||||||
ss->print("owner=" INTPTR_FORMAT, p2i(_owner));
|
|
||||||
} else {
|
|
||||||
if (contentions() > 0) {
|
if (contentions() > 0) {
|
||||||
ss->print("contentions=%d, ", contentions());
|
ss->print("contentions=%d, ", contentions());
|
||||||
} else {
|
} else {
|
||||||
|
@ -503,7 +497,6 @@ const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
|
||||||
// ignores DEFLATER_MARKER values.
|
// ignores DEFLATER_MARKER values.
|
||||||
ss->print("owner=" INTPTR_FORMAT, NULL);
|
ss->print("owner=" INTPTR_FORMAT, NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ss->print(", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, p2i(_cxq),
|
ss->print(", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, p2i(_cxq),
|
||||||
p2i(_EntryList));
|
p2i(_EntryList));
|
||||||
return ss->base();
|
return ss->base();
|
||||||
|
@ -524,8 +517,7 @@ void ObjectMonitor::EnterI(TRAPS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors &&
|
if (try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
|
||||||
try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
|
|
||||||
// Cancelled the in-progress async deflation by changing owner from
|
// Cancelled the in-progress async deflation by changing owner from
|
||||||
// DEFLATER_MARKER to Self. As part of the contended enter protocol,
|
// DEFLATER_MARKER to Self. As part of the contended enter protocol,
|
||||||
// contentions was incremented to a positive value before EnterI()
|
// contentions was incremented to a positive value before EnterI()
|
||||||
|
@ -659,8 +651,7 @@ void ObjectMonitor::EnterI(TRAPS) {
|
||||||
|
|
||||||
if (TryLock(Self) > 0) break;
|
if (TryLock(Self) > 0) break;
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors &&
|
if (try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
|
||||||
try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
|
|
||||||
// Cancelled the in-progress async deflation by changing owner from
|
// Cancelled the in-progress async deflation by changing owner from
|
||||||
// DEFLATER_MARKER to Self. As part of the contended enter protocol,
|
// DEFLATER_MARKER to Self. As part of the contended enter protocol,
|
||||||
// contentions was incremented to a positive value before EnterI()
|
// contentions was incremented to a positive value before EnterI()
|
||||||
|
@ -1007,8 +998,8 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) {
|
||||||
" is exiting an ObjectMonitor it does not own.", p2i(THREAD));
|
" is exiting an ObjectMonitor it does not own.", p2i(THREAD));
|
||||||
lsh.print_cr("The imbalance is possibly caused by JNI locking.");
|
lsh.print_cr("The imbalance is possibly caused by JNI locking.");
|
||||||
print_debug_style_on(&lsh);
|
print_debug_style_on(&lsh);
|
||||||
#endif
|
|
||||||
assert(false, "Non-balanced monitor enter/exit!");
|
assert(false, "Non-balanced monitor enter/exit!");
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,7 @@ class ObjectMonitor {
|
||||||
jint _contentions; // Number of active contentions in enter(). It is used by is_busy()
|
jint _contentions; // Number of active contentions in enter(). It is used by is_busy()
|
||||||
// along with other fields to determine if an ObjectMonitor can be
|
// along with other fields to determine if an ObjectMonitor can be
|
||||||
// deflated. It is also used by the async deflation protocol. See
|
// deflated. It is also used by the async deflation protocol. See
|
||||||
// ObjectSynchronizer::deflate_monitor() and deflate_monitor_using_JT().
|
// ObjectSynchronizer::deflate_monitor_using_JT().
|
||||||
protected:
|
protected:
|
||||||
ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor
|
ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor
|
||||||
volatile jint _waiters; // number of waiting threads
|
volatile jint _waiters; // number of waiting threads
|
||||||
|
@ -243,16 +243,12 @@ class ObjectMonitor {
|
||||||
intptr_t is_busy() const {
|
intptr_t is_busy() const {
|
||||||
// TODO-FIXME: assert _owner == null implies _recursions = 0
|
// TODO-FIXME: assert _owner == null implies _recursions = 0
|
||||||
intptr_t ret_code = _waiters | intptr_t(_cxq) | intptr_t(_EntryList);
|
intptr_t ret_code = _waiters | intptr_t(_cxq) | intptr_t(_EntryList);
|
||||||
if (!AsyncDeflateIdleMonitors) {
|
|
||||||
ret_code |= contentions() | intptr_t(_owner);
|
|
||||||
} else {
|
|
||||||
if (contentions() > 0) {
|
if (contentions() > 0) {
|
||||||
ret_code |= contentions();
|
ret_code |= contentions();
|
||||||
}
|
}
|
||||||
if (_owner != DEFLATER_MARKER) {
|
if (_owner != DEFLATER_MARKER) {
|
||||||
ret_code |= intptr_t(_owner);
|
ret_code |= intptr_t(_owner);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
const char* is_busy_to_string(stringStream* ss);
|
const char* is_busy_to_string(stringStream* ss);
|
||||||
|
@ -315,9 +311,9 @@ class ObjectMonitor {
|
||||||
// _recursions == 0 _WaitSet == NULL
|
// _recursions == 0 _WaitSet == NULL
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
stringStream ss;
|
stringStream ss;
|
||||||
#endif
|
|
||||||
assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
|
assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
|
||||||
"recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions);
|
"recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions);
|
||||||
|
#endif
|
||||||
_succ = NULL;
|
_succ = NULL;
|
||||||
_EntryList = NULL;
|
_EntryList = NULL;
|
||||||
_cxq = NULL;
|
_cxq = NULL;
|
||||||
|
@ -374,15 +370,4 @@ class ObjectMonitor {
|
||||||
void install_displaced_markword_in_object(const oop obj);
|
void install_displaced_markword_in_object(const oop obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Macro to use guarantee() for more strict AsyncDeflateIdleMonitors
|
|
||||||
// checks and assert() otherwise.
|
|
||||||
#define ADIM_guarantee(p, ...) \
|
|
||||||
do { \
|
|
||||||
if (AsyncDeflateIdleMonitors) { \
|
|
||||||
guarantee(p, __VA_ARGS__); \
|
|
||||||
} else { \
|
|
||||||
assert(p, __VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif // SHARE_RUNTIME_OBJECTMONITOR_HPP
|
#endif // SHARE_RUNTIME_OBJECTMONITOR_HPP
|
||||||
|
|
|
@ -67,7 +67,7 @@ inline bool ObjectMonitor::owner_is_DEFLATER_MARKER() {
|
||||||
|
|
||||||
// Returns true if 'this' is being async deflated and false otherwise.
|
// Returns true if 'this' is being async deflated and false otherwise.
|
||||||
inline bool ObjectMonitor::is_being_async_deflated() {
|
inline bool ObjectMonitor::is_being_async_deflated() {
|
||||||
return AsyncDeflateIdleMonitors && contentions() < 0;
|
return contentions() < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ObjectMonitor::clear() {
|
inline void ObjectMonitor::clear() {
|
||||||
|
@ -80,7 +80,6 @@ inline void ObjectMonitor::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ObjectMonitor::clear_common() {
|
inline void ObjectMonitor::clear_common() {
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// Async deflation protocol uses the header, owner and contentions
|
// Async deflation protocol uses the header, owner and contentions
|
||||||
// fields. While the ObjectMonitor being deflated is on the global
|
// fields. While the ObjectMonitor being deflated is on the global
|
||||||
// free list, we leave those three fields alone; contentions < 0
|
// free list, we leave those three fields alone; contentions < 0
|
||||||
|
@ -90,7 +89,6 @@ inline void ObjectMonitor::clear_common() {
|
||||||
guarantee(_owner == NULL || _owner == DEFLATER_MARKER,
|
guarantee(_owner == NULL || _owner == DEFLATER_MARKER,
|
||||||
"must be NULL or DEFLATER_MARKER: owner=" INTPTR_FORMAT,
|
"must be NULL or DEFLATER_MARKER: owner=" INTPTR_FORMAT,
|
||||||
p2i(_owner));
|
p2i(_owner));
|
||||||
}
|
|
||||||
assert(contentions() <= 0, "must not be positive: contentions=%d", contentions());
|
assert(contentions() <= 0, "must not be positive: contentions=%d", contentions());
|
||||||
assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
|
assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
|
||||||
assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
|
assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
|
||||||
|
@ -124,9 +122,11 @@ inline void ObjectMonitor::add_to_contentions(jint value) {
|
||||||
|
|
||||||
// Clear _owner field; current value must match old_value.
|
// Clear _owner field; current value must match old_value.
|
||||||
inline void ObjectMonitor::release_clear_owner(void* old_value) {
|
inline void ObjectMonitor::release_clear_owner(void* old_value) {
|
||||||
|
#ifdef ASSERT
|
||||||
void* prev = Atomic::load(&_owner);
|
void* prev = Atomic::load(&_owner);
|
||||||
ADIM_guarantee(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
|
assert(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
|
||||||
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
|
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
|
||||||
|
#endif
|
||||||
Atomic::release_store(&_owner, (void*)NULL);
|
Atomic::release_store(&_owner, (void*)NULL);
|
||||||
log_trace(monitorinflation, owner)("release_clear_owner(): mid="
|
log_trace(monitorinflation, owner)("release_clear_owner(): mid="
|
||||||
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT,
|
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT,
|
||||||
|
@ -136,9 +136,11 @@ inline void ObjectMonitor::release_clear_owner(void* old_value) {
|
||||||
// Simply set _owner field to new_value; current value must match old_value.
|
// Simply set _owner field to new_value; current value must match old_value.
|
||||||
// (Simple means no memory sync needed.)
|
// (Simple means no memory sync needed.)
|
||||||
inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) {
|
inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) {
|
||||||
|
#ifdef ASSERT
|
||||||
void* prev = Atomic::load(&_owner);
|
void* prev = Atomic::load(&_owner);
|
||||||
ADIM_guarantee(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
|
assert(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
|
||||||
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
|
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
|
||||||
|
#endif
|
||||||
Atomic::store(&_owner, new_value);
|
Atomic::store(&_owner, new_value);
|
||||||
log_trace(monitorinflation, owner)("set_owner_from(): mid="
|
log_trace(monitorinflation, owner)("set_owner_from(): mid="
|
||||||
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT
|
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT
|
||||||
|
@ -150,7 +152,7 @@ inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) {
|
||||||
// (Simple means no memory sync needed.)
|
// (Simple means no memory sync needed.)
|
||||||
inline void ObjectMonitor::set_owner_from(void* old_value1, void* old_value2, void* new_value) {
|
inline void ObjectMonitor::set_owner_from(void* old_value1, void* old_value2, void* new_value) {
|
||||||
void* prev = Atomic::load(&_owner);
|
void* prev = Atomic::load(&_owner);
|
||||||
ADIM_guarantee(prev == old_value1 || prev == old_value2,
|
assert(prev == old_value1 || prev == old_value2,
|
||||||
"unexpected prev owner=" INTPTR_FORMAT ", expected1="
|
"unexpected prev owner=" INTPTR_FORMAT ", expected1="
|
||||||
INTPTR_FORMAT " or expected2=" INTPTR_FORMAT, p2i(prev),
|
INTPTR_FORMAT " or expected2=" INTPTR_FORMAT, p2i(prev),
|
||||||
p2i(old_value1), p2i(old_value2));
|
p2i(old_value1), p2i(old_value2));
|
||||||
|
@ -165,9 +167,11 @@ inline void ObjectMonitor::set_owner_from(void* old_value1, void* old_value2, vo
|
||||||
|
|
||||||
// Simply set _owner field to self; current value must match basic_lock_p.
|
// Simply set _owner field to self; current value must match basic_lock_p.
|
||||||
inline void ObjectMonitor::set_owner_from_BasicLock(void* basic_lock_p, Thread* self) {
|
inline void ObjectMonitor::set_owner_from_BasicLock(void* basic_lock_p, Thread* self) {
|
||||||
|
#ifdef ASSERT
|
||||||
void* prev = Atomic::load(&_owner);
|
void* prev = Atomic::load(&_owner);
|
||||||
ADIM_guarantee(prev == basic_lock_p, "unexpected prev owner=" INTPTR_FORMAT
|
assert(prev == basic_lock_p, "unexpected prev owner=" INTPTR_FORMAT
|
||||||
", expected=" INTPTR_FORMAT, p2i(prev), p2i(basic_lock_p));
|
", expected=" INTPTR_FORMAT, p2i(prev), p2i(basic_lock_p));
|
||||||
|
#endif
|
||||||
// Non-null owner field to non-null owner field is safe without
|
// Non-null owner field to non-null owner field is safe without
|
||||||
// cmpxchg() as long as all readers can tolerate either flavor.
|
// cmpxchg() as long as all readers can tolerate either flavor.
|
||||||
Atomic::store(&_owner, self);
|
Atomic::store(&_owner, self);
|
||||||
|
|
|
@ -490,9 +490,6 @@ void SafepointSynchronize::end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafepointSynchronize::is_cleanup_needed() {
|
bool SafepointSynchronize::is_cleanup_needed() {
|
||||||
// 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
|
// Need a safepoint if some inline cache buffers is non-empty
|
||||||
if (!InlineCacheBuffer::is_empty()) return true;
|
if (!InlineCacheBuffer::is_empty()) return true;
|
||||||
if (StringTable::needs_rehashing()) return true;
|
if (StringTable::needs_rehashing()) return true;
|
||||||
|
@ -500,51 +497,24 @@ bool SafepointSynchronize::is_cleanup_needed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParallelSPCleanupThreadClosure : public ThreadClosure {
|
|
||||||
private:
|
|
||||||
DeflateMonitorCounters* _counters;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ParallelSPCleanupThreadClosure(DeflateMonitorCounters* counters) :
|
|
||||||
_counters(counters) {}
|
|
||||||
|
|
||||||
void do_thread(Thread* thread) {
|
|
||||||
// deflate_thread_local_monitors() handles or requests deflation of
|
|
||||||
// this thread's idle monitors. If !AsyncDeflateIdleMonitors or if
|
|
||||||
// there is a special cleanup request, deflation is handled now.
|
|
||||||
// Otherwise, async deflation is requested via a flag.
|
|
||||||
ObjectSynchronizer::deflate_thread_local_monitors(thread, _counters);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ParallelSPCleanupTask : public AbstractGangTask {
|
class ParallelSPCleanupTask : public AbstractGangTask {
|
||||||
private:
|
private:
|
||||||
SubTasksDone _subtasks;
|
SubTasksDone _subtasks;
|
||||||
ParallelSPCleanupThreadClosure _cleanup_threads_cl;
|
|
||||||
uint _num_workers;
|
uint _num_workers;
|
||||||
DeflateMonitorCounters* _counters;
|
|
||||||
public:
|
public:
|
||||||
ParallelSPCleanupTask(uint num_workers, DeflateMonitorCounters* counters) :
|
ParallelSPCleanupTask(uint num_workers) :
|
||||||
AbstractGangTask("Parallel Safepoint Cleanup"),
|
AbstractGangTask("Parallel Safepoint Cleanup"),
|
||||||
_subtasks(SafepointSynchronize::SAFEPOINT_CLEANUP_NUM_TASKS),
|
_subtasks(SafepointSynchronize::SAFEPOINT_CLEANUP_NUM_TASKS),
|
||||||
_cleanup_threads_cl(ParallelSPCleanupThreadClosure(counters)),
|
_num_workers(num_workers) {}
|
||||||
_num_workers(num_workers),
|
|
||||||
_counters(counters) {}
|
|
||||||
|
|
||||||
void work(uint worker_id) {
|
void work(uint worker_id) {
|
||||||
uint64_t safepoint_id = SafepointSynchronize::safepoint_id();
|
uint64_t safepoint_id = SafepointSynchronize::safepoint_id();
|
||||||
// All threads deflate monitors and mark nmethods (if necessary).
|
|
||||||
Threads::possibly_parallel_threads_do(true, &_cleanup_threads_cl);
|
|
||||||
|
|
||||||
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_DEFLATE_MONITORS)) {
|
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_DEFLATE_MONITORS)) {
|
||||||
const char* name = "deflating global idle monitors";
|
const char* name = "deflating idle monitors";
|
||||||
EventSafepointCleanupTask event;
|
EventSafepointCleanupTask event;
|
||||||
TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
|
TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
|
||||||
// AsyncDeflateIdleMonitors only uses DeflateMonitorCounters
|
ObjectSynchronizer::do_safepoint_work();
|
||||||
// when a special cleanup has been requested.
|
|
||||||
// Note: This logging output will include global idle monitor
|
|
||||||
// elapsed times, but not global idle monitor deflation count.
|
|
||||||
ObjectSynchronizer::do_safepoint_work(_counters);
|
|
||||||
|
|
||||||
post_safepoint_cleanup_task_event(event, safepoint_id, name);
|
post_safepoint_cleanup_task_event(event, safepoint_id, name);
|
||||||
}
|
}
|
||||||
|
@ -615,23 +585,17 @@ void SafepointSynchronize::do_cleanup_tasks() {
|
||||||
|
|
||||||
TraceTime timer("safepoint cleanup tasks", TRACETIME_LOG(Info, safepoint, cleanup));
|
TraceTime timer("safepoint cleanup tasks", TRACETIME_LOG(Info, safepoint, cleanup));
|
||||||
|
|
||||||
// Prepare for monitor deflation.
|
|
||||||
DeflateMonitorCounters deflate_counters;
|
|
||||||
ObjectSynchronizer::prepare_deflate_idle_monitors(&deflate_counters);
|
|
||||||
|
|
||||||
CollectedHeap* heap = Universe::heap();
|
CollectedHeap* heap = Universe::heap();
|
||||||
assert(heap != NULL, "heap not initialized yet?");
|
assert(heap != NULL, "heap not initialized yet?");
|
||||||
WorkGang* cleanup_workers = heap->get_safepoint_workers();
|
WorkGang* cleanup_workers = heap->get_safepoint_workers();
|
||||||
if (cleanup_workers != NULL) {
|
if (cleanup_workers != NULL) {
|
||||||
// Parallel cleanup using GC provided thread pool.
|
// Parallel cleanup using GC provided thread pool.
|
||||||
uint num_cleanup_workers = cleanup_workers->active_workers();
|
uint num_cleanup_workers = cleanup_workers->active_workers();
|
||||||
ParallelSPCleanupTask cleanup(num_cleanup_workers, &deflate_counters);
|
ParallelSPCleanupTask cleanup(num_cleanup_workers);
|
||||||
StrongRootsScope srs(num_cleanup_workers);
|
|
||||||
cleanup_workers->run_task(&cleanup);
|
cleanup_workers->run_task(&cleanup);
|
||||||
} else {
|
} else {
|
||||||
// Serial cleanup using VMThread.
|
// Serial cleanup using VMThread.
|
||||||
ParallelSPCleanupTask cleanup(1, &deflate_counters);
|
ParallelSPCleanupTask cleanup(1);
|
||||||
StrongRootsScope srs(1);
|
|
||||||
cleanup.work(0);
|
cleanup.work(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,9 +608,6 @@ void SafepointSynchronize::do_cleanup_tasks() {
|
||||||
ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces();
|
ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish monitor deflation.
|
|
||||||
ObjectSynchronizer::finish_deflate_idle_monitors(&deflate_counters);
|
|
||||||
|
|
||||||
assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
|
assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,10 +142,9 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||||
(deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed())
|
(deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed())
|
||||||
) == 0) {
|
) == 0) {
|
||||||
// Wait until notified that there is some work to do.
|
// Wait until notified that there is some work to do.
|
||||||
// If AsyncDeflateIdleMonitors, then we wait for
|
// We wait for GuaranteedSafepointInterval so that
|
||||||
// GuaranteedSafepointInterval so that is_async_deflation_needed()
|
// is_async_deflation_needed() is checked at the same interval.
|
||||||
// is checked at the same interval.
|
ml.wait(GuaranteedSafepointInterval);
|
||||||
ml.wait(AsyncDeflateIdleMonitors ? GuaranteedSafepointInterval : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_jvmti_events) {
|
if (has_jvmti_events) {
|
||||||
|
|
|
@ -491,16 +491,12 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread* self,
|
||||||
|
|
||||||
if (mark.has_monitor()) {
|
if (mark.has_monitor()) {
|
||||||
ObjectMonitor* const m = mark.monitor();
|
ObjectMonitor* const m = mark.monitor();
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// An async deflation can race us before we manage to make the
|
// An async deflation can race us before we manage to make the
|
||||||
// ObjectMonitor busy by setting the owner below. If we detect
|
// ObjectMonitor busy by setting the owner below. If we detect
|
||||||
// that race we just bail out to the slow-path here.
|
// that race we just bail out to the slow-path here.
|
||||||
if (m->object() == NULL) {
|
if (m->object() == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
assert(m->object() == obj, "invariant");
|
|
||||||
}
|
|
||||||
Thread* const owner = (Thread *) m->_owner;
|
Thread* const owner = (Thread *) m->_owner;
|
||||||
|
|
||||||
// Lock contention and Transactional Lock Elision (TLE) diagnostics
|
// Lock contention and Transactional Lock Elision (TLE) diagnostics
|
||||||
|
@ -986,9 +982,8 @@ static inline intptr_t get_next_hash(Thread* self, oop obj) {
|
||||||
intptr_t ObjectSynchronizer::FastHashCode(Thread* self, oop obj) {
|
intptr_t ObjectSynchronizer::FastHashCode(Thread* self, oop obj) {
|
||||||
if (UseBiasedLocking) {
|
if (UseBiasedLocking) {
|
||||||
// NOTE: many places throughout the JVM do not expect a safepoint
|
// NOTE: many places throughout the JVM do not expect a safepoint
|
||||||
// to be taken here, in particular most operations on perm gen
|
// to be taken here. However, we only ever bias Java instances and all
|
||||||
// objects. However, we only ever bias Java instances and all of
|
// of the call sites of identity_hash that might revoke biases have
|
||||||
// the call sites of identity_hash that might revoke biases have
|
|
||||||
// been checked to make sure they can handle a safepoint. The
|
// been checked to make sure they can handle a safepoint. The
|
||||||
// added check of the bias pattern is to avoid useless calls to
|
// added check of the bias pattern is to avoid useless calls to
|
||||||
// thread-local storage.
|
// thread-local storage.
|
||||||
|
@ -1193,8 +1188,6 @@ ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership
|
||||||
}
|
}
|
||||||
|
|
||||||
// CASE: inflated. Mark (tagged pointer) points to an ObjectMonitor.
|
// CASE: inflated. Mark (tagged pointer) points to an ObjectMonitor.
|
||||||
// The Object:ObjectMonitor relationship is stable as long as we're
|
|
||||||
// not at a safepoint and AsyncDeflateIdleMonitors is false.
|
|
||||||
if (mark.has_monitor()) {
|
if (mark.has_monitor()) {
|
||||||
// The first stage of async deflation does not affect any field
|
// The first stage of async deflation does not affect any field
|
||||||
// used by this comparison so the ObjectMonitor* is usable here.
|
// used by this comparison so the ObjectMonitor* is usable here.
|
||||||
|
@ -1294,9 +1287,6 @@ static bool monitors_used_above_threshold() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectSynchronizer::is_async_deflation_needed() {
|
bool ObjectSynchronizer::is_async_deflation_needed() {
|
||||||
if (!AsyncDeflateIdleMonitors) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (is_async_deflation_requested()) {
|
if (is_async_deflation_requested()) {
|
||||||
// Async deflation request.
|
// Async deflation request.
|
||||||
return true;
|
return true;
|
||||||
|
@ -1313,16 +1303,10 @@ bool ObjectSynchronizer::is_async_deflation_needed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectSynchronizer::is_safepoint_deflation_needed() {
|
|
||||||
return !AsyncDeflateIdleMonitors &&
|
|
||||||
monitors_used_above_threshold(); // Too many monitors in use.
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectSynchronizer::request_deflate_idle_monitors() {
|
bool ObjectSynchronizer::request_deflate_idle_monitors() {
|
||||||
bool is_JavaThread = Thread::current()->is_Java_thread();
|
bool is_JavaThread = Thread::current()->is_Java_thread();
|
||||||
bool ret_code = false;
|
bool ret_code = false;
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
jlong last_time = last_async_deflation_time_ns();
|
jlong last_time = last_async_deflation_time_ns();
|
||||||
set_is_async_deflation_requested(true);
|
set_is_async_deflation_requested(true);
|
||||||
{
|
{
|
||||||
|
@ -1347,15 +1331,6 @@ bool ObjectSynchronizer::request_deflate_idle_monitors() {
|
||||||
if (!ret_code) {
|
if (!ret_code) {
|
||||||
log_info(monitorinflation)("Async Deflation DID NOT happen after %d checks.", N_CHECKS);
|
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 ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
@ -1396,9 +1371,9 @@ void ObjectSynchronizer::list_oops_do(ObjectMonitor* list, OopClosure* f) {
|
||||||
// ObjectMonitor Lifecycle
|
// ObjectMonitor Lifecycle
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// Inflation unlinks monitors from om_list_globals._free_list or a per-thread
|
// Inflation unlinks monitors from om_list_globals._free_list or a per-thread
|
||||||
// free list and associates them with objects. Deflation -- which occurs at
|
// free list and associates them with objects. Async deflation disassociates
|
||||||
// STW-time or asynchronously -- disassociates idle monitors from objects.
|
// idle monitors from objects. Such scavenged monitors are returned to the
|
||||||
// Such scavenged monitors are returned to the om_list_globals._free_list.
|
// om_list_globals._free_list.
|
||||||
//
|
//
|
||||||
// ObjectMonitors reside in type-stable memory (TSM) and are immortal.
|
// ObjectMonitors reside in type-stable memory (TSM) and are immortal.
|
||||||
//
|
//
|
||||||
|
@ -1411,7 +1386,7 @@ void ObjectSynchronizer::list_oops_do(ObjectMonitor* list, OopClosure* f) {
|
||||||
ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
|
ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
|
||||||
// A large MAXPRIVATE value reduces both list lock contention
|
// A large MAXPRIVATE value reduces both list lock contention
|
||||||
// and list coherency traffic, but also tends to increase the
|
// and list coherency traffic, but also tends to increase the
|
||||||
// number of ObjectMonitors in circulation as well as the STW
|
// number of ObjectMonitors in circulation as well as the
|
||||||
// scavenge costs. As usual, we lean toward time in space-time
|
// scavenge costs. As usual, we lean toward time in space-time
|
||||||
// tradeoffs.
|
// tradeoffs.
|
||||||
const int MAXPRIVATE = 1024;
|
const int MAXPRIVATE = 1024;
|
||||||
|
@ -1447,7 +1422,6 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
|
||||||
break; // No more are available.
|
break; // No more are available.
|
||||||
}
|
}
|
||||||
guarantee(take->object() == NULL, "invariant");
|
guarantee(take->object() == NULL, "invariant");
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// We allowed 3 field values to linger during async deflation.
|
// We allowed 3 field values to linger during async deflation.
|
||||||
// Clear or restore them as appropriate.
|
// Clear or restore them as appropriate.
|
||||||
take->set_header(markWord::zero());
|
take->set_header(markWord::zero());
|
||||||
|
@ -1460,10 +1434,9 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
jint l_contentions = take->contentions();
|
jint l_contentions = take->contentions();
|
||||||
#endif
|
|
||||||
assert(l_contentions >= 0, "must not be negative: l_contentions=%d, contentions=%d",
|
assert(l_contentions >= 0, "must not be negative: l_contentions=%d, contentions=%d",
|
||||||
l_contentions, take->contentions());
|
l_contentions, take->contentions());
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
take->Recycle();
|
take->Recycle();
|
||||||
// Since we're taking from the global free-list, take must be Free.
|
// Since we're taking from the global free-list, take must be Free.
|
||||||
|
@ -1529,8 +1502,8 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
|
||||||
//
|
//
|
||||||
// Key constraint: all ObjectMonitors on a thread's free list and the global
|
// Key constraint: all ObjectMonitors on a thread's free list and the global
|
||||||
// free list must have their object field set to null. This prevents the
|
// free list must have their object field set to null. This prevents the
|
||||||
// scavenger -- deflate_monitor_list() or deflate_monitor_list_using_JT()
|
// scavenger -- deflate_monitor_list_using_JT() -- from reclaiming them
|
||||||
// -- from reclaiming them while we are trying to release them.
|
// while we are trying to release them.
|
||||||
|
|
||||||
void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m,
|
void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m,
|
||||||
bool from_per_thread_alloc) {
|
bool from_per_thread_alloc) {
|
||||||
|
@ -1639,15 +1612,13 @@ void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m,
|
||||||
//
|
//
|
||||||
// We currently call om_flush() from Threads::remove() before the
|
// We currently call om_flush() from Threads::remove() before the
|
||||||
// thread has been excised from the thread list and is no longer a
|
// thread has been excised from the thread list and is no longer a
|
||||||
// mutator. This means that om_flush() cannot run concurrently with
|
// mutator. In particular, this ensures that the thread's in-use
|
||||||
// a safepoint and interleave with deflate_idle_monitors(). In
|
// monitors are scanned by a GC safepoint, either via Thread::oops_do()
|
||||||
// particular, this ensures that the thread's in-use monitors are
|
// (before om_flush() is called) or via ObjectSynchronizer::oops_do()
|
||||||
// scanned by a GC safepoint, either via Thread::oops_do() (before
|
// (after om_flush() is called).
|
||||||
// om_flush() is called) or via ObjectSynchronizer::oops_do() (after
|
|
||||||
// om_flush() is called).
|
|
||||||
//
|
//
|
||||||
// With AsyncDeflateIdleMonitors, deflate_global_idle_monitors_using_JT()
|
// deflate_global_idle_monitors_using_JT() and
|
||||||
// and deflate_per_thread_idle_monitors_using_JT() (in another thread) can
|
// deflate_per_thread_idle_monitors_using_JT() (in another thread) can
|
||||||
// run at the same time as om_flush() so we have to follow a careful
|
// run at the same time as om_flush() so we have to follow a careful
|
||||||
// protocol to prevent list corruption.
|
// protocol to prevent list corruption.
|
||||||
|
|
||||||
|
@ -1701,9 +1672,11 @@ void ObjectSynchronizer::om_flush(Thread* self) {
|
||||||
cur_om = unmarked_next(cur_om);
|
cur_om = unmarked_next(cur_om);
|
||||||
}
|
}
|
||||||
guarantee(in_use_tail != NULL, "invariant");
|
guarantee(in_use_tail != NULL, "invariant");
|
||||||
|
#ifdef ASSERT
|
||||||
int l_om_in_use_count = Atomic::load(&self->om_in_use_count);
|
int l_om_in_use_count = Atomic::load(&self->om_in_use_count);
|
||||||
ADIM_guarantee(l_om_in_use_count == in_use_count, "in-use counts don't match: "
|
assert(l_om_in_use_count == in_use_count, "in-use counts don't match: "
|
||||||
"l_om_in_use_count=%d, in_use_count=%d", l_om_in_use_count, in_use_count);
|
"l_om_in_use_count=%d, in_use_count=%d", l_om_in_use_count, in_use_count);
|
||||||
|
#endif
|
||||||
Atomic::store(&self->om_in_use_count, 0);
|
Atomic::store(&self->om_in_use_count, 0);
|
||||||
// Clear the in-use list head (which also unlocks it):
|
// Clear the in-use list head (which also unlocks it):
|
||||||
Atomic::store(&self->om_in_use_list, (ObjectMonitor*)NULL);
|
Atomic::store(&self->om_in_use_list, (ObjectMonitor*)NULL);
|
||||||
|
@ -1744,9 +1717,11 @@ void ObjectSynchronizer::om_flush(Thread* self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guarantee(free_tail != NULL, "invariant");
|
guarantee(free_tail != NULL, "invariant");
|
||||||
|
#ifdef ASSERT
|
||||||
int l_om_free_count = Atomic::load(&self->om_free_count);
|
int l_om_free_count = Atomic::load(&self->om_free_count);
|
||||||
ADIM_guarantee(l_om_free_count == free_count, "free counts don't match: "
|
assert(l_om_free_count == free_count, "free counts don't match: "
|
||||||
"l_om_free_count=%d, free_count=%d", l_om_free_count, free_count);
|
"l_om_free_count=%d, free_count=%d", l_om_free_count, free_count);
|
||||||
|
#endif
|
||||||
Atomic::store(&self->om_free_count, 0);
|
Atomic::store(&self->om_free_count, 0);
|
||||||
Atomic::store(&self->om_free_list, (ObjectMonitor*)NULL);
|
Atomic::store(&self->om_free_list, (ObjectMonitor*)NULL);
|
||||||
om_unlock(free_list);
|
om_unlock(free_list);
|
||||||
|
@ -1825,7 +1800,6 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,
|
||||||
ObjectMonitor* inf = mark.monitor();
|
ObjectMonitor* inf = mark.monitor();
|
||||||
markWord dmw = inf->header();
|
markWord dmw = inf->header();
|
||||||
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
|
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
|
||||||
assert(AsyncDeflateIdleMonitors || inf->object() == object, "invariant");
|
|
||||||
assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid");
|
assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid");
|
||||||
return inf;
|
return inf;
|
||||||
}
|
}
|
||||||
|
@ -1911,7 +1885,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,
|
||||||
markWord dmw = mark.displaced_mark_helper();
|
markWord dmw = mark.displaced_mark_helper();
|
||||||
// Catch if the object's header is not neutral (not locked and
|
// Catch if the object's header is not neutral (not locked and
|
||||||
// not marked is what we care about here).
|
// not marked is what we care about here).
|
||||||
ADIM_guarantee(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
|
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
|
||||||
|
|
||||||
// Setup monitor fields to proper values -- prepare the monitor
|
// Setup monitor fields to proper values -- prepare the monitor
|
||||||
m->set_header(dmw);
|
m->set_header(dmw);
|
||||||
|
@ -1921,11 +1895,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,
|
||||||
// Note that a thread can inflate an object
|
// Note that a thread can inflate an object
|
||||||
// that it has stack-locked -- as might happen in wait() -- directly
|
// that it has stack-locked -- as might happen in wait() -- directly
|
||||||
// with CAS. That is, we can avoid the xchg-NULL .... ST idiom.
|
// with CAS. That is, we can avoid the xchg-NULL .... ST idiom.
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
m->set_owner_from(NULL, DEFLATER_MARKER, mark.locker());
|
m->set_owner_from(NULL, DEFLATER_MARKER, mark.locker());
|
||||||
} else {
|
|
||||||
m->set_owner_from(NULL, mark.locker());
|
|
||||||
}
|
|
||||||
m->set_object(object);
|
m->set_object(object);
|
||||||
// TODO-FIXME: assert BasicLock->dhw != 0.
|
// TODO-FIXME: assert BasicLock->dhw != 0.
|
||||||
|
|
||||||
|
@ -1965,15 +1935,13 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,
|
||||||
|
|
||||||
// Catch if the object's header is not neutral (not locked and
|
// Catch if the object's header is not neutral (not locked and
|
||||||
// not marked is what we care about here).
|
// not marked is what we care about here).
|
||||||
ADIM_guarantee(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
|
assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
|
||||||
ObjectMonitor* m = om_alloc(self);
|
ObjectMonitor* m = om_alloc(self);
|
||||||
// prepare m for installation - set monitor to initial state
|
// prepare m for installation - set monitor to initial state
|
||||||
m->Recycle();
|
m->Recycle();
|
||||||
m->set_header(mark);
|
m->set_header(mark);
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// DEFLATER_MARKER is the only non-NULL value we should see here.
|
// DEFLATER_MARKER is the only non-NULL value we should see here.
|
||||||
m->try_set_owner_from(DEFLATER_MARKER, NULL);
|
m->try_set_owner_from(DEFLATER_MARKER, NULL);
|
||||||
}
|
|
||||||
m->set_object(object);
|
m->set_object(object);
|
||||||
m->_Responsible = NULL;
|
m->_Responsible = NULL;
|
||||||
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class
|
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class
|
||||||
|
@ -2013,45 +1981,11 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// We maintain a list of in-use monitors for each thread.
|
// An async deflation request is registered with the ServiceThread
|
||||||
//
|
// and it is notified.
|
||||||
// For safepoint based deflation:
|
void ObjectSynchronizer::do_safepoint_work() {
|
||||||
// deflate_thread_local_monitors() scans a single thread's in-use list, while
|
|
||||||
// deflate_idle_monitors() scans only a global list of in-use monitors which
|
|
||||||
// is populated only as a thread dies (see om_flush()).
|
|
||||||
//
|
|
||||||
// These operations are called at all safepoints, immediately after mutators
|
|
||||||
// are stopped, but before any objects have moved. Collectively they traverse
|
|
||||||
// the population of in-use monitors, deflating where possible. The scavenged
|
|
||||||
// monitors are returned to the global monitor free list.
|
|
||||||
//
|
|
||||||
// Beware that we scavenge at *every* stop-the-world point. Having a large
|
|
||||||
// number of monitors in-use could negatively impact performance. We also want
|
|
||||||
// to minimize the total # of monitors in circulation, as they incur a small
|
|
||||||
// footprint penalty.
|
|
||||||
//
|
|
||||||
// Perversely, the heap size -- and thus the STW safepoint rate --
|
|
||||||
// typically drives the scavenge rate. Large heaps can mean infrequent GC,
|
|
||||||
// which in turn can mean large(r) numbers of ObjectMonitors in circulation.
|
|
||||||
// This is an unfortunate aspect of this design.
|
|
||||||
//
|
|
||||||
// For async deflation:
|
|
||||||
// If a special deflation request is made, then the safepoint based
|
|
||||||
// deflation mechanism is used. Otherwise, an async deflation request
|
|
||||||
// is registered with the ServiceThread and it is notified.
|
|
||||||
|
|
||||||
void ObjectSynchronizer::do_safepoint_work(DeflateMonitorCounters* counters) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||||
|
|
||||||
// The per-thread in-use lists are handled in
|
|
||||||
// ParallelSPCleanupThreadClosure::do_thread().
|
|
||||||
|
|
||||||
if (!AsyncDeflateIdleMonitors) {
|
|
||||||
// Use the older mechanism for the global in-use list.
|
|
||||||
ObjectSynchronizer::deflate_idle_monitors(counters);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug(monitorinflation)("requesting async deflation of idle monitors.");
|
log_debug(monitorinflation)("requesting async deflation of idle monitors.");
|
||||||
// Request deflation of idle monitors by the ServiceThread:
|
// Request deflation of idle monitors by the ServiceThread:
|
||||||
set_is_async_deflation_requested(true);
|
set_is_async_deflation_requested(true);
|
||||||
|
@ -2061,85 +1995,10 @@ void ObjectSynchronizer::do_safepoint_work(DeflateMonitorCounters* counters) {
|
||||||
if (log_is_enabled(Debug, monitorinflation)) {
|
if (log_is_enabled(Debug, monitorinflation)) {
|
||||||
// exit_globals()'s call to audit_and_print_stats() is done
|
// exit_globals()'s call to audit_and_print_stats() is done
|
||||||
// at the Info level and not at a safepoint.
|
// at the Info level and not at a safepoint.
|
||||||
// For safepoint based deflation, audit_and_print_stats() is called
|
|
||||||
// in ObjectSynchronizer::finish_deflate_idle_monitors() at the
|
|
||||||
// Debug level at a safepoint.
|
|
||||||
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
|
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deflate a single monitor if not in-use
|
|
||||||
// Return true if deflated, false if in-use
|
|
||||||
bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj,
|
|
||||||
ObjectMonitor** free_head_p,
|
|
||||||
ObjectMonitor** free_tail_p) {
|
|
||||||
bool deflated;
|
|
||||||
// Normal case ... The monitor is associated with obj.
|
|
||||||
const markWord mark = obj->mark();
|
|
||||||
guarantee(mark == markWord::encode(mid), "should match: mark="
|
|
||||||
INTPTR_FORMAT ", encoded mid=" INTPTR_FORMAT, mark.value(),
|
|
||||||
markWord::encode(mid).value());
|
|
||||||
// Make sure that mark.monitor() and markWord::encode() agree:
|
|
||||||
guarantee(mark.monitor() == mid, "should match: monitor()=" INTPTR_FORMAT
|
|
||||||
", mid=" INTPTR_FORMAT, p2i(mark.monitor()), p2i(mid));
|
|
||||||
const markWord dmw = mid->header();
|
|
||||||
guarantee(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
|
|
||||||
|
|
||||||
if (mid->is_busy()) {
|
|
||||||
// Easy checks are first - the ObjectMonitor is busy so no deflation.
|
|
||||||
deflated = false;
|
|
||||||
} else {
|
|
||||||
// Deflate the monitor if it is no longer being used
|
|
||||||
// It's idle - scavenge and return to the global free list
|
|
||||||
// plain old deflation ...
|
|
||||||
if (log_is_enabled(Trace, monitorinflation)) {
|
|
||||||
ResourceMark rm;
|
|
||||||
log_trace(monitorinflation)("deflate_monitor: "
|
|
||||||
"object=" INTPTR_FORMAT ", mark="
|
|
||||||
INTPTR_FORMAT ", type='%s'", p2i(obj),
|
|
||||||
mark.value(), obj->klass()->external_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the header back to obj
|
|
||||||
obj->release_set_mark(dmw);
|
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// clear() expects the owner field to be NULL.
|
|
||||||
// DEFLATER_MARKER is the only non-NULL value we should see here.
|
|
||||||
mid->try_set_owner_from(DEFLATER_MARKER, NULL);
|
|
||||||
}
|
|
||||||
mid->clear();
|
|
||||||
|
|
||||||
assert(mid->object() == NULL, "invariant: object=" INTPTR_FORMAT,
|
|
||||||
p2i(mid->object()));
|
|
||||||
assert(mid->is_free(), "invariant");
|
|
||||||
|
|
||||||
// Move the deflated ObjectMonitor to the working free list
|
|
||||||
// defined by free_head_p and free_tail_p.
|
|
||||||
if (*free_head_p == NULL) *free_head_p = mid;
|
|
||||||
if (*free_tail_p != NULL) {
|
|
||||||
// We append to the list so the caller can use mid->_next_om
|
|
||||||
// to fix the linkages in its context.
|
|
||||||
ObjectMonitor* prevtail = *free_tail_p;
|
|
||||||
// Should have been cleaned up by the caller:
|
|
||||||
// Note: Should not have to lock prevtail here since we're at a
|
|
||||||
// safepoint and ObjectMonitors on the local free list should
|
|
||||||
// not be accessed in parallel.
|
|
||||||
#ifdef ASSERT
|
|
||||||
ObjectMonitor* l_next_om = prevtail->next_om();
|
|
||||||
#endif
|
|
||||||
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
|
||||||
prevtail->set_next_om(mid);
|
|
||||||
}
|
|
||||||
*free_tail_p = mid;
|
|
||||||
// At this point, mid->_next_om still refers to its current
|
|
||||||
// value and another ObjectMonitor's _next_om field still
|
|
||||||
// refers to this ObjectMonitor. Those linkages have to be
|
|
||||||
// cleaned up by the caller who has the complete context.
|
|
||||||
deflated = true;
|
|
||||||
}
|
|
||||||
return deflated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deflate the specified ObjectMonitor if not in-use using a JavaThread.
|
// Deflate the specified ObjectMonitor if not in-use using a JavaThread.
|
||||||
// Returns true if it was deflated and false otherwise.
|
// Returns true if it was deflated and false otherwise.
|
||||||
//
|
//
|
||||||
|
@ -2156,7 +2015,6 @@ bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj,
|
||||||
bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
|
bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
|
||||||
ObjectMonitor** free_head_p,
|
ObjectMonitor** free_head_p,
|
||||||
ObjectMonitor** free_tail_p) {
|
ObjectMonitor** free_tail_p) {
|
||||||
assert(AsyncDeflateIdleMonitors, "sanity check");
|
|
||||||
assert(Thread::current()->is_Java_thread(), "precondition");
|
assert(Thread::current()->is_Java_thread(), "precondition");
|
||||||
// A newly allocated ObjectMonitor should not be seen here so we
|
// A newly allocated ObjectMonitor should not be seen here so we
|
||||||
// avoid an endless inflate/deflate cycle.
|
// avoid an endless inflate/deflate cycle.
|
||||||
|
@ -2245,8 +2103,8 @@ bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
|
||||||
// prevtail should have been cleaned up by the caller:
|
// prevtail should have been cleaned up by the caller:
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
ObjectMonitor* l_next_om = unmarked_next(prevtail);
|
ObjectMonitor* l_next_om = unmarked_next(prevtail);
|
||||||
#endif
|
|
||||||
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
||||||
|
#endif
|
||||||
om_lock(prevtail);
|
om_lock(prevtail);
|
||||||
prevtail->set_next_om(mid); // prevtail now points to mid (and is unlocked)
|
prevtail->set_next_om(mid); // prevtail now points to mid (and is unlocked)
|
||||||
}
|
}
|
||||||
|
@ -2262,56 +2120,6 @@ bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
|
||||||
return true; // Success, ObjectMonitor has been deflated.
|
return true; // Success, ObjectMonitor has been deflated.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk a given monitor list, and deflate idle monitors.
|
|
||||||
// The given list could be a per-thread list or a global list.
|
|
||||||
//
|
|
||||||
// In the case of parallel processing of thread local monitor lists,
|
|
||||||
// work is done by Threads::parallel_threads_do() which ensures that
|
|
||||||
// each Java thread is processed by exactly one worker thread, and
|
|
||||||
// thus avoid conflicts that would arise when worker threads would
|
|
||||||
// process the same monitor lists concurrently.
|
|
||||||
//
|
|
||||||
// See also ParallelSPCleanupTask and
|
|
||||||
// SafepointSynchronize::do_cleanup_tasks() in safepoint.cpp and
|
|
||||||
// Threads::parallel_java_threads_do() in thread.cpp.
|
|
||||||
int ObjectSynchronizer::deflate_monitor_list(ObjectMonitor** list_p,
|
|
||||||
int* count_p,
|
|
||||||
ObjectMonitor** free_head_p,
|
|
||||||
ObjectMonitor** free_tail_p) {
|
|
||||||
ObjectMonitor* cur_mid_in_use = NULL;
|
|
||||||
ObjectMonitor* mid = NULL;
|
|
||||||
ObjectMonitor* next = NULL;
|
|
||||||
int deflated_count = 0;
|
|
||||||
|
|
||||||
// This list walk executes at a safepoint and does not race with any
|
|
||||||
// other list walkers.
|
|
||||||
|
|
||||||
for (mid = Atomic::load(list_p); mid != NULL; mid = next) {
|
|
||||||
next = unmarked_next(mid);
|
|
||||||
oop obj = (oop) mid->object();
|
|
||||||
if (obj != NULL && deflate_monitor(mid, obj, free_head_p, free_tail_p)) {
|
|
||||||
// Deflation succeeded and already updated free_head_p and
|
|
||||||
// free_tail_p as needed. Finish the move to the local free list
|
|
||||||
// by unlinking mid from the global or per-thread in-use list.
|
|
||||||
if (cur_mid_in_use == NULL) {
|
|
||||||
// mid is the list head so switch the list head to next:
|
|
||||||
Atomic::store(list_p, next);
|
|
||||||
} else {
|
|
||||||
// Switch cur_mid_in_use's next field to next:
|
|
||||||
cur_mid_in_use->set_next_om(next);
|
|
||||||
}
|
|
||||||
// At this point mid is disconnected from the in-use list.
|
|
||||||
deflated_count++;
|
|
||||||
Atomic::dec(count_p);
|
|
||||||
// mid is current tail in the free_head_p list so NULL terminate it:
|
|
||||||
mid->set_next_om(NULL);
|
|
||||||
} else {
|
|
||||||
cur_mid_in_use = mid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return deflated_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk a given ObjectMonitor list and deflate idle ObjectMonitors using
|
// Walk a given ObjectMonitor list and deflate idle ObjectMonitors using
|
||||||
// a JavaThread. Returns the number of deflated ObjectMonitors. The given
|
// a JavaThread. Returns the number of deflated ObjectMonitors. The given
|
||||||
// list could be a per-thread in-use list or the global in-use list.
|
// list could be a per-thread in-use list or the global in-use list.
|
||||||
|
@ -2323,7 +2131,6 @@ int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor** list_p,
|
||||||
ObjectMonitor** free_head_p,
|
ObjectMonitor** free_head_p,
|
||||||
ObjectMonitor** free_tail_p,
|
ObjectMonitor** free_tail_p,
|
||||||
ObjectMonitor** saved_mid_in_use_p) {
|
ObjectMonitor** saved_mid_in_use_p) {
|
||||||
assert(AsyncDeflateIdleMonitors, "sanity check");
|
|
||||||
JavaThread* self = JavaThread::current();
|
JavaThread* self = JavaThread::current();
|
||||||
|
|
||||||
ObjectMonitor* cur_mid_in_use = NULL;
|
ObjectMonitor* cur_mid_in_use = NULL;
|
||||||
|
@ -2453,75 +2260,6 @@ int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor** list_p,
|
||||||
return deflated_count;
|
return deflated_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectSynchronizer::prepare_deflate_idle_monitors(DeflateMonitorCounters* counters) {
|
|
||||||
counters->n_in_use = 0; // currently associated with objects
|
|
||||||
counters->n_in_circulation = 0; // extant
|
|
||||||
counters->n_scavenged = 0; // reclaimed (global and per-thread)
|
|
||||||
counters->per_thread_scavenged = 0; // per-thread scavenge total
|
|
||||||
counters->per_thread_times = 0.0; // per-thread scavenge times
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectSynchronizer::deflate_idle_monitors(DeflateMonitorCounters* counters) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// Nothing to do when global idle ObjectMonitors are deflated using
|
|
||||||
// a JavaThread.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool deflated = false;
|
|
||||||
|
|
||||||
ObjectMonitor* free_head_p = NULL; // Local SLL of scavenged monitors
|
|
||||||
ObjectMonitor* free_tail_p = NULL;
|
|
||||||
elapsedTimer timer;
|
|
||||||
|
|
||||||
if (log_is_enabled(Info, monitorinflation)) {
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: the thread-local monitors lists get deflated in
|
|
||||||
// a separate pass. See deflate_thread_local_monitors().
|
|
||||||
|
|
||||||
// For moribund threads, scan om_list_globals._in_use_list
|
|
||||||
int deflated_count = 0;
|
|
||||||
if (Atomic::load(&om_list_globals._in_use_list) != NULL) {
|
|
||||||
// Update n_in_circulation before om_list_globals._in_use_count is
|
|
||||||
// updated by deflation.
|
|
||||||
Atomic::add(&counters->n_in_circulation,
|
|
||||||
Atomic::load(&om_list_globals._in_use_count));
|
|
||||||
|
|
||||||
deflated_count = deflate_monitor_list(&om_list_globals._in_use_list,
|
|
||||||
&om_list_globals._in_use_count,
|
|
||||||
&free_head_p, &free_tail_p);
|
|
||||||
Atomic::add(&counters->n_in_use, Atomic::load(&om_list_globals._in_use_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (free_head_p != NULL) {
|
|
||||||
// Move the deflated ObjectMonitors back to the global free list.
|
|
||||||
guarantee(free_tail_p != NULL && deflated_count > 0, "invariant");
|
|
||||||
#ifdef ASSERT
|
|
||||||
ObjectMonitor* l_next_om = free_tail_p->next_om();
|
|
||||||
#endif
|
|
||||||
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
|
||||||
prepend_list_to_global_free_list(free_head_p, free_tail_p, deflated_count);
|
|
||||||
Atomic::add(&counters->n_scavenged, deflated_count);
|
|
||||||
}
|
|
||||||
timer.stop();
|
|
||||||
|
|
||||||
LogStreamHandle(Debug, monitorinflation) lsh_debug;
|
|
||||||
LogStreamHandle(Info, monitorinflation) lsh_info;
|
|
||||||
LogStream* ls = NULL;
|
|
||||||
if (log_is_enabled(Debug, monitorinflation)) {
|
|
||||||
ls = &lsh_debug;
|
|
||||||
} else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) {
|
|
||||||
ls = &lsh_info;
|
|
||||||
}
|
|
||||||
if (ls != NULL) {
|
|
||||||
ls->print_cr("deflating global idle monitors, %3.7f secs, %d monitors", timer.seconds(), deflated_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HandshakeForDeflation : public HandshakeClosure {
|
class HandshakeForDeflation : public HandshakeClosure {
|
||||||
public:
|
public:
|
||||||
HandshakeForDeflation() : HandshakeClosure("HandshakeForDeflation") {}
|
HandshakeForDeflation() : HandshakeClosure("HandshakeForDeflation") {}
|
||||||
|
@ -2533,8 +2271,6 @@ class HandshakeForDeflation : public HandshakeClosure {
|
||||||
};
|
};
|
||||||
|
|
||||||
void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
|
void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
|
||||||
assert(AsyncDeflateIdleMonitors, "sanity check");
|
|
||||||
|
|
||||||
// Deflate any global idle monitors.
|
// Deflate any global idle monitors.
|
||||||
deflate_global_idle_monitors_using_JT();
|
deflate_global_idle_monitors_using_JT();
|
||||||
|
|
||||||
|
@ -2568,7 +2304,7 @@ void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
|
||||||
// (or a safepoint) for safety.
|
// (or a safepoint) for safety.
|
||||||
|
|
||||||
ObjectMonitor* list = Atomic::load(&om_list_globals._wait_list);
|
ObjectMonitor* list = Atomic::load(&om_list_globals._wait_list);
|
||||||
ADIM_guarantee(list != NULL, "om_list_globals._wait_list must not be NULL");
|
assert(list != NULL, "om_list_globals._wait_list must not be NULL");
|
||||||
int count = Atomic::load(&om_list_globals._wait_count);
|
int count = Atomic::load(&om_list_globals._wait_count);
|
||||||
Atomic::store(&om_list_globals._wait_count, 0);
|
Atomic::store(&om_list_globals._wait_count, 0);
|
||||||
Atomic::store(&om_list_globals._wait_list, (ObjectMonitor*)NULL);
|
Atomic::store(&om_list_globals._wait_list, (ObjectMonitor*)NULL);
|
||||||
|
@ -2576,13 +2312,17 @@ void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
|
||||||
// Find the tail for prepend_list_to_common(). No need to mark
|
// Find the tail for prepend_list_to_common(). No need to mark
|
||||||
// ObjectMonitors for this list walk since only the deflater
|
// ObjectMonitors for this list walk since only the deflater
|
||||||
// thread manages the wait list.
|
// thread manages the wait list.
|
||||||
|
#ifdef ASSERT
|
||||||
int l_count = 0;
|
int l_count = 0;
|
||||||
|
#endif
|
||||||
ObjectMonitor* tail = NULL;
|
ObjectMonitor* tail = NULL;
|
||||||
for (ObjectMonitor* n = list; n != NULL; n = unmarked_next(n)) {
|
for (ObjectMonitor* n = list; n != NULL; n = unmarked_next(n)) {
|
||||||
tail = n;
|
tail = n;
|
||||||
|
#ifdef ASSERT
|
||||||
l_count++;
|
l_count++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
ADIM_guarantee(count == l_count, "count=%d != l_count=%d", count, l_count);
|
assert(count == l_count, "count=%d != l_count=%d", count, l_count);
|
||||||
|
|
||||||
// Will execute a safepoint if !ThreadLocalHandshakes:
|
// Will execute a safepoint if !ThreadLocalHandshakes:
|
||||||
HandshakeForDeflation hfd_hc;
|
HandshakeForDeflation hfd_hc;
|
||||||
|
@ -2598,7 +2338,6 @@ void ObjectSynchronizer::deflate_idle_monitors_using_JT() {
|
||||||
// Deflate global idle ObjectMonitors using a JavaThread.
|
// Deflate global idle ObjectMonitors using a JavaThread.
|
||||||
//
|
//
|
||||||
void ObjectSynchronizer::deflate_global_idle_monitors_using_JT() {
|
void ObjectSynchronizer::deflate_global_idle_monitors_using_JT() {
|
||||||
assert(AsyncDeflateIdleMonitors, "sanity check");
|
|
||||||
assert(Thread::current()->is_Java_thread(), "precondition");
|
assert(Thread::current()->is_Java_thread(), "precondition");
|
||||||
JavaThread* self = JavaThread::current();
|
JavaThread* self = JavaThread::current();
|
||||||
|
|
||||||
|
@ -2608,7 +2347,6 @@ void ObjectSynchronizer::deflate_global_idle_monitors_using_JT() {
|
||||||
// Deflate the specified JavaThread's idle ObjectMonitors using a JavaThread.
|
// Deflate the specified JavaThread's idle ObjectMonitors using a JavaThread.
|
||||||
//
|
//
|
||||||
void ObjectSynchronizer::deflate_per_thread_idle_monitors_using_JT(JavaThread* target) {
|
void ObjectSynchronizer::deflate_per_thread_idle_monitors_using_JT(JavaThread* target) {
|
||||||
assert(AsyncDeflateIdleMonitors, "sanity check");
|
|
||||||
assert(Thread::current()->is_Java_thread(), "precondition");
|
assert(Thread::current()->is_Java_thread(), "precondition");
|
||||||
|
|
||||||
deflate_common_idle_monitors_using_JT(false /* !is_global */, target);
|
deflate_common_idle_monitors_using_JT(false /* !is_global */, target);
|
||||||
|
@ -2664,8 +2402,8 @@ void ObjectSynchronizer::deflate_common_idle_monitors_using_JT(bool is_global, J
|
||||||
// all out.
|
// all out.
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
ObjectMonitor* l_next_om = unmarked_next(free_tail_p);
|
ObjectMonitor* l_next_om = unmarked_next(free_tail_p);
|
||||||
#endif
|
|
||||||
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
||||||
|
#endif
|
||||||
|
|
||||||
prepend_list_to_global_wait_list(free_head_p, free_tail_p, local_deflated_count);
|
prepend_list_to_global_wait_list(free_head_p, free_tail_p, local_deflated_count);
|
||||||
|
|
||||||
|
@ -2711,94 +2449,6 @@ void ObjectSynchronizer::deflate_common_idle_monitors_using_JT(bool is_global, J
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* counters) {
|
|
||||||
// Report the cumulative time for deflating each thread's idle
|
|
||||||
// monitors. Note: if the work is split among more than one
|
|
||||||
// worker thread, then the reported time will likely be more
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// Nothing to do when idle ObjectMonitors are deflated using
|
|
||||||
// a JavaThread.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_is_enabled(Debug, monitorinflation)) {
|
|
||||||
// exit_globals()'s call to audit_and_print_stats() is done
|
|
||||||
// at the Info level and not at a safepoint.
|
|
||||||
// For async deflation, audit_and_print_stats() is called in
|
|
||||||
// ObjectSynchronizer::do_safepoint_work() at the Debug level
|
|
||||||
// at a safepoint.
|
|
||||||
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
|
|
||||||
} else if (log_is_enabled(Info, monitorinflation)) {
|
|
||||||
log_info(monitorinflation)("global_population=%d, global_in_use_count=%d, "
|
|
||||||
"global_free_count=%d, global_wait_count=%d",
|
|
||||||
Atomic::load(&om_list_globals._population),
|
|
||||||
Atomic::load(&om_list_globals._in_use_count),
|
|
||||||
Atomic::load(&om_list_globals._free_count),
|
|
||||||
Atomic::load(&om_list_globals._wait_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
OM_PERFDATA_OP(Deflations, inc(counters->n_scavenged));
|
|
||||||
OM_PERFDATA_OP(MonExtant, set_value(counters->n_in_circulation));
|
|
||||||
|
|
||||||
GVars.stw_random = os::random();
|
|
||||||
GVars.stw_cycle++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors) {
|
|
||||||
// Nothing to do when per-thread idle ObjectMonitors are deflated
|
|
||||||
// using a JavaThread.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectMonitor* free_head_p = NULL; // Local SLL of scavenged monitors
|
|
||||||
ObjectMonitor* free_tail_p = NULL;
|
|
||||||
elapsedTimer timer;
|
|
||||||
|
|
||||||
if (log_is_enabled(Info, safepoint, cleanup) ||
|
|
||||||
log_is_enabled(Info, monitorinflation)) {
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update n_in_circulation before om_in_use_count is updated by deflation.
|
|
||||||
Atomic::add(&counters->n_in_circulation, Atomic::load(&thread->om_in_use_count));
|
|
||||||
|
|
||||||
int deflated_count = deflate_monitor_list(&thread->om_in_use_list, &thread->om_in_use_count, &free_head_p, &free_tail_p);
|
|
||||||
Atomic::add(&counters->n_in_use, Atomic::load(&thread->om_in_use_count));
|
|
||||||
|
|
||||||
if (free_head_p != NULL) {
|
|
||||||
// Move the deflated ObjectMonitors back to the global free list.
|
|
||||||
guarantee(free_tail_p != NULL && deflated_count > 0, "invariant");
|
|
||||||
#ifdef ASSERT
|
|
||||||
ObjectMonitor* l_next_om = free_tail_p->next_om();
|
|
||||||
#endif
|
|
||||||
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
|
|
||||||
prepend_list_to_global_free_list(free_head_p, free_tail_p, deflated_count);
|
|
||||||
Atomic::add(&counters->n_scavenged, deflated_count);
|
|
||||||
Atomic::add(&counters->per_thread_scavenged, deflated_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.stop();
|
|
||||||
counters->per_thread_times += timer.seconds();
|
|
||||||
|
|
||||||
LogStreamHandle(Debug, monitorinflation) lsh_debug;
|
|
||||||
LogStreamHandle(Info, monitorinflation) lsh_info;
|
|
||||||
LogStream* ls = NULL;
|
|
||||||
if (log_is_enabled(Debug, monitorinflation)) {
|
|
||||||
ls = &lsh_debug;
|
|
||||||
} else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) {
|
|
||||||
ls = &lsh_info;
|
|
||||||
}
|
|
||||||
if (ls != NULL) {
|
|
||||||
ls->print_cr("jt=" INTPTR_FORMAT ": deflating per-thread idle monitors, %3.7f secs, %d monitors", p2i(thread), timer.seconds(), deflated_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor cleanup on JavaThread::exit
|
// Monitor cleanup on JavaThread::exit
|
||||||
|
|
||||||
// Iterate through monitor cache and attempt to release thread's monitors
|
// Iterate through monitor cache and attempt to release thread's monitors
|
||||||
|
@ -2824,7 +2474,7 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure {
|
||||||
// A simple optimization is to add a per-thread flag that indicates a thread
|
// A simple optimization is to add a per-thread flag that indicates a thread
|
||||||
// called jni_monitorenter() during its lifetime.
|
// called jni_monitorenter() during its lifetime.
|
||||||
//
|
//
|
||||||
// Instead of No_Savepoint_Verifier it might be cheaper to
|
// Instead of NoSafepointVerifier it might be cheaper to
|
||||||
// use an idiom of the form:
|
// use an idiom of the form:
|
||||||
// auto int tmp = SafepointSynchronize::_safepoint_counter ;
|
// auto int tmp = SafepointSynchronize::_safepoint_counter ;
|
||||||
// <code that must not run at safepoint>
|
// <code that must not run at safepoint>
|
||||||
|
@ -2883,8 +2533,6 @@ u_char* ObjectSynchronizer::get_gvars_stw_random_addr() {
|
||||||
// aid; pass 'true' for the 'on_exit' parameter to have in-use monitor
|
// aid; pass 'true' for the 'on_exit' parameter to have in-use monitor
|
||||||
// details logged at the Info level and 'false' for the 'on_exit'
|
// details logged at the Info level and 'false' for the 'on_exit'
|
||||||
// parameter to have in-use monitor details logged at the Trace level.
|
// parameter to have in-use monitor details logged at the Trace level.
|
||||||
// deflate_monitor_list() no longer uses spin-locking so be careful
|
|
||||||
// when adding audit_and_print_stats() calls at a safepoint.
|
|
||||||
//
|
//
|
||||||
void ObjectSynchronizer::audit_and_print_stats(bool on_exit) {
|
void ObjectSynchronizer::audit_and_print_stats(bool on_exit) {
|
||||||
assert(on_exit || SafepointSynchronize::is_at_safepoint(), "invariant");
|
assert(on_exit || SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||||
|
@ -2983,11 +2631,6 @@ void ObjectSynchronizer::chk_free_entry(JavaThread* jt, ObjectMonitor* n,
|
||||||
"field: _header=" INTPTR_FORMAT, p2i(jt), p2i(n),
|
"field: _header=" INTPTR_FORMAT, p2i(jt), p2i(n),
|
||||||
n->header().value());
|
n->header().value());
|
||||||
*error_cnt_p = *error_cnt_p + 1;
|
*error_cnt_p = *error_cnt_p + 1;
|
||||||
} else if (!AsyncDeflateIdleMonitors) {
|
|
||||||
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor "
|
|
||||||
"must have NULL _header field: _header=" INTPTR_FORMAT,
|
|
||||||
p2i(n), n->header().value());
|
|
||||||
*error_cnt_p = *error_cnt_p + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n->object() != NULL) {
|
if (n->object() != NULL) {
|
||||||
|
|
|
@ -42,14 +42,6 @@ class ThreadsList;
|
||||||
|
|
||||||
typedef PaddedEnd<ObjectMonitor, OM_CACHE_LINE_SIZE> PaddedObjectMonitor;
|
typedef PaddedEnd<ObjectMonitor, OM_CACHE_LINE_SIZE> PaddedObjectMonitor;
|
||||||
|
|
||||||
struct DeflateMonitorCounters {
|
|
||||||
volatile int n_in_use; // currently associated with objects
|
|
||||||
volatile int n_in_circulation; // extant
|
|
||||||
volatile int n_scavenged; // reclaimed (global and per-thread)
|
|
||||||
volatile int per_thread_scavenged; // per-thread scavenge total
|
|
||||||
double per_thread_times; // per-thread scavenge times
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectSynchronizer : AllStatic {
|
class ObjectSynchronizer : AllStatic {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
public:
|
public:
|
||||||
|
@ -131,20 +123,11 @@ class ObjectSynchronizer : AllStatic {
|
||||||
// GC: we current use aggressive monitor deflation policy
|
// GC: we current use aggressive monitor deflation policy
|
||||||
// Basically we deflate all monitors that are not busy.
|
// Basically we deflate all monitors that are not busy.
|
||||||
// An adaptive profile-based deflation policy could be used if needed
|
// An adaptive profile-based deflation policy could be used if needed
|
||||||
static void deflate_idle_monitors(DeflateMonitorCounters* counters);
|
|
||||||
static void deflate_idle_monitors_using_JT();
|
static void deflate_idle_monitors_using_JT();
|
||||||
static void deflate_global_idle_monitors_using_JT();
|
static void deflate_global_idle_monitors_using_JT();
|
||||||
static void deflate_per_thread_idle_monitors_using_JT(JavaThread* target);
|
static void deflate_per_thread_idle_monitors_using_JT(JavaThread* target);
|
||||||
static void deflate_common_idle_monitors_using_JT(bool is_global, JavaThread* target);
|
static void deflate_common_idle_monitors_using_JT(bool is_global, JavaThread* target);
|
||||||
static void deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters);
|
|
||||||
static void prepare_deflate_idle_monitors(DeflateMonitorCounters* counters);
|
|
||||||
static void finish_deflate_idle_monitors(DeflateMonitorCounters* counters);
|
|
||||||
|
|
||||||
// For a given monitor list: global or per-thread, deflate idle monitors
|
|
||||||
static int deflate_monitor_list(ObjectMonitor** list_p,
|
|
||||||
int* count_p,
|
|
||||||
ObjectMonitor** free_head_p,
|
|
||||||
ObjectMonitor** free_tail_p);
|
|
||||||
// For a given in-use monitor list: global or per-thread, deflate idle
|
// For a given in-use monitor list: global or per-thread, deflate idle
|
||||||
// monitors using a JavaThread.
|
// monitors using a JavaThread.
|
||||||
static int deflate_monitor_list_using_JT(ObjectMonitor** list_p,
|
static int deflate_monitor_list_using_JT(ObjectMonitor** list_p,
|
||||||
|
@ -152,14 +135,10 @@ class ObjectSynchronizer : AllStatic {
|
||||||
ObjectMonitor** free_head_p,
|
ObjectMonitor** free_head_p,
|
||||||
ObjectMonitor** free_tail_p,
|
ObjectMonitor** free_tail_p,
|
||||||
ObjectMonitor** saved_mid_in_use_p);
|
ObjectMonitor** saved_mid_in_use_p);
|
||||||
static bool deflate_monitor(ObjectMonitor* mid, oop obj,
|
|
||||||
ObjectMonitor** free_head_p,
|
|
||||||
ObjectMonitor** free_tail_p);
|
|
||||||
static bool deflate_monitor_using_JT(ObjectMonitor* mid,
|
static bool deflate_monitor_using_JT(ObjectMonitor* mid,
|
||||||
ObjectMonitor** free_head_p,
|
ObjectMonitor** free_head_p,
|
||||||
ObjectMonitor** free_tail_p);
|
ObjectMonitor** free_tail_p);
|
||||||
static bool is_async_deflation_needed();
|
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_async_deflation_requested() { return _is_async_deflation_requested; }
|
||||||
static jlong last_async_deflation_time_ns() { return _last_async_deflation_time_ns; }
|
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 bool request_deflate_idle_monitors(); // for whitebox test support and VM exit logging
|
||||||
|
@ -191,7 +170,7 @@ class ObjectSynchronizer : AllStatic {
|
||||||
static int log_monitor_list_counts(outputStream * out);
|
static int log_monitor_list_counts(outputStream * out);
|
||||||
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
|
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
|
||||||
|
|
||||||
static void do_safepoint_work(DeflateMonitorCounters* counters);
|
static void do_safepoint_work();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SynchronizerTest;
|
friend class SynchronizerTest;
|
||||||
|
|
|
@ -431,10 +431,10 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VM_Exit::doit_prologue() {
|
bool VM_Exit::doit_prologue() {
|
||||||
if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
|
if (log_is_enabled(Info, monitorinflation)) {
|
||||||
// AsyncDeflateIdleMonitors does a special deflation in order
|
// Do a deflation in order to reduce the in-use monitor population
|
||||||
// to reduce the in-use monitor population that is reported by
|
// that is reported by ObjectSynchronizer::log_in_use_monitor_details()
|
||||||
// ObjectSynchronizer::log_in_use_monitor_details() at VM exit.
|
// at VM exit.
|
||||||
ObjectSynchronizer::request_deflate_idle_monitors();
|
ObjectSynchronizer::request_deflate_idle_monitors();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -260,10 +260,10 @@ void VMThread::run() {
|
||||||
assert(should_terminate(), "termination flag must be set");
|
assert(should_terminate(), "termination flag must be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
|
if (log_is_enabled(Info, monitorinflation)) {
|
||||||
// AsyncDeflateIdleMonitors does a special deflation in order
|
// Do a deflation in order to reduce the in-use monitor population
|
||||||
// to reduce the in-use monitor population that is reported by
|
// that is reported by ObjectSynchronizer::log_in_use_monitor_details()
|
||||||
// ObjectSynchronizer::log_in_use_monitor_details() at VM exit.
|
// at VM exit.
|
||||||
ObjectSynchronizer::request_deflate_idle_monitors();
|
ObjectSynchronizer::request_deflate_idle_monitors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,13 +222,11 @@ Handle ThreadService::get_current_contended_monitor(JavaThread* thread) {
|
||||||
if (wait_obj != NULL) {
|
if (wait_obj != NULL) {
|
||||||
// thread is doing an Object.wait() call
|
// thread is doing an Object.wait() call
|
||||||
obj = (oop) wait_obj->object();
|
obj = (oop) wait_obj->object();
|
||||||
assert(AsyncDeflateIdleMonitors || obj != NULL, "Object.wait() should have an object");
|
|
||||||
} else {
|
} else {
|
||||||
ObjectMonitor *enter_obj = thread->current_pending_monitor();
|
ObjectMonitor *enter_obj = thread->current_pending_monitor();
|
||||||
if (enter_obj != NULL) {
|
if (enter_obj != NULL) {
|
||||||
// thread is trying to enter() an ObjectMonitor.
|
// thread is trying to enter() an ObjectMonitor.
|
||||||
obj = (oop) enter_obj->object();
|
obj = (oop) enter_obj->object();
|
||||||
assert(AsyncDeflateIdleMonitors || obj != NULL, "ObjectMonitor should have an associated object!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,19 +138,5 @@ TEST_VM(markWord, printing) {
|
||||||
assert_test_pattern(h_obj, "monitor");
|
assert_test_pattern(h_obj, "monitor");
|
||||||
done.wait_with_safepoint_check(THREAD); // wait till the thread is done.
|
done.wait_with_safepoint_check(THREAD); // wait till the thread is done.
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
|
@ -29,23 +29,17 @@
|
||||||
* @modules java.base/jdk.internal.misc
|
* @modules java.base/jdk.internal.misc
|
||||||
* java.management
|
* java.management
|
||||||
* @run driver SafepointCleanupTest
|
* @run driver SafepointCleanupTest
|
||||||
* @run driver SafepointCleanupTest -XX:+AsyncDeflateIdleMonitors
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import jdk.test.lib.process.OutputAnalyzer;
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
import jdk.test.lib.process.ProcessTools;
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
|
||||||
public class SafepointCleanupTest {
|
public class SafepointCleanupTest {
|
||||||
static final String ASYNC_DISABLE_OPTION = "-XX:-AsyncDeflateIdleMonitors";
|
|
||||||
static final String ASYNC_ENABLE_OPTION = "-XX:+AsyncDeflateIdleMonitors";
|
|
||||||
static final String UNLOCK_DIAG_OPTION = "-XX:+UnlockDiagnosticVMOptions";
|
|
||||||
|
|
||||||
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
|
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
output.shouldContain("[safepoint,cleanup]");
|
output.shouldContain("[safepoint,cleanup]");
|
||||||
output.shouldContain("safepoint cleanup tasks");
|
output.shouldContain("safepoint cleanup tasks");
|
||||||
output.shouldContain("deflating global idle monitors");
|
output.shouldContain("deflating idle monitors");
|
||||||
output.shouldContain("deflating per-thread idle monitors");
|
|
||||||
output.shouldContain("updating inline caches");
|
output.shouldContain("updating inline caches");
|
||||||
output.shouldContain("compilation policy safepoint handler");
|
output.shouldContain("compilation policy safepoint handler");
|
||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
|
@ -58,40 +52,19 @@ public class SafepointCleanupTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
String async_option;
|
|
||||||
if (args.length == 0) {
|
|
||||||
// By default test deflating idle monitors at a safepoint.
|
|
||||||
async_option = ASYNC_DISABLE_OPTION;
|
|
||||||
} else {
|
|
||||||
async_option = args[0];
|
|
||||||
}
|
|
||||||
if (!async_option.equals(ASYNC_DISABLE_OPTION) &&
|
|
||||||
!async_option.equals(ASYNC_ENABLE_OPTION)) {
|
|
||||||
throw new RuntimeException("Unknown async_option value: '"
|
|
||||||
+ async_option + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=info",
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=info",
|
||||||
UNLOCK_DIAG_OPTION,
|
|
||||||
async_option,
|
|
||||||
InnerClass.class.getName());
|
InnerClass.class.getName());
|
||||||
analyzeOutputOn(pb);
|
analyzeOutputOn(pb);
|
||||||
|
|
||||||
pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceSafepointCleanupTime",
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceSafepointCleanupTime",
|
||||||
UNLOCK_DIAG_OPTION,
|
|
||||||
async_option,
|
|
||||||
InnerClass.class.getName());
|
InnerClass.class.getName());
|
||||||
analyzeOutputOn(pb);
|
analyzeOutputOn(pb);
|
||||||
|
|
||||||
pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=off",
|
pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=off",
|
||||||
UNLOCK_DIAG_OPTION,
|
|
||||||
async_option,
|
|
||||||
InnerClass.class.getName());
|
InnerClass.class.getName());
|
||||||
analyzeOutputOff(pb);
|
analyzeOutputOff(pb);
|
||||||
|
|
||||||
pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceSafepointCleanupTime",
|
pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceSafepointCleanupTime",
|
||||||
UNLOCK_DIAG_OPTION,
|
|
||||||
async_option,
|
|
||||||
InnerClass.class.getName());
|
InnerClass.class.getName());
|
||||||
analyzeOutputOff(pb);
|
analyzeOutputOff(pb);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue