8225453: is_busy diagnostics and other baseline cleanups from Async Monitor Deflation project
Reviewed-by: dholmes, rehn, coleenp
This commit is contained in:
parent
f93ae041ad
commit
d02937254d
@ -245,9 +245,7 @@ void ObjectMonitor::enter(TRAPS) {
|
|||||||
|
|
||||||
void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
|
void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
|
||||||
if (cur == NULL) {
|
if (cur == NULL) {
|
||||||
// Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
|
|
||||||
assert(_recursions == 0, "invariant");
|
assert(_recursions == 0, "invariant");
|
||||||
assert(_owner == Self, "invariant");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,9 +403,7 @@ int ObjectMonitor::TryLock(Thread * Self) {
|
|||||||
void * own = _owner;
|
void * own = _owner;
|
||||||
if (own != NULL) return 0;
|
if (own != NULL) return 0;
|
||||||
if (Atomic::replace_if_null(Self, &_owner)) {
|
if (Atomic::replace_if_null(Self, &_owner)) {
|
||||||
// Either guarantee _recursions == 0 or set _recursions = 0.
|
|
||||||
assert(_recursions == 0, "invariant");
|
assert(_recursions == 0, "invariant");
|
||||||
assert(_owner == Self, "invariant");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// The lock had been free momentarily, but we lost the race to the lock.
|
// The lock had been free momentarily, but we lost the race to the lock.
|
||||||
@ -417,6 +413,15 @@ int ObjectMonitor::TryLock(Thread * Self) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the fields used by is_busy() to a string that can be
|
||||||
|
// used for diagnostic output.
|
||||||
|
const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
|
||||||
|
ss->print("is_busy: contentions=%d, waiters=%d, owner=" INTPTR_FORMAT
|
||||||
|
", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, _contentions,
|
||||||
|
_waiters, p2i(_owner), p2i(_cxq), p2i(_EntryList));
|
||||||
|
return ss->base();
|
||||||
|
}
|
||||||
|
|
||||||
#define MAX_RECHECK_INTERVAL 1000
|
#define MAX_RECHECK_INTERVAL 1000
|
||||||
|
|
||||||
void ObjectMonitor::EnterI(TRAPS) {
|
void ObjectMonitor::EnterI(TRAPS) {
|
||||||
|
@ -235,6 +235,7 @@ class ObjectMonitor {
|
|||||||
// TODO-FIXME: assert _owner == null implies _recursions = 0
|
// TODO-FIXME: assert _owner == null implies _recursions = 0
|
||||||
return _contentions|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList);
|
return _contentions|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList);
|
||||||
}
|
}
|
||||||
|
const char* is_busy_to_string(stringStream* ss);
|
||||||
|
|
||||||
intptr_t is_entered(Thread* current) const;
|
intptr_t is_entered(Thread* current) const;
|
||||||
|
|
||||||
@ -268,7 +269,9 @@ class ObjectMonitor {
|
|||||||
// _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
|
// _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
|
||||||
// _contentions == 0 EntryList == NULL
|
// _contentions == 0 EntryList == NULL
|
||||||
// _recursions == 0 _WaitSet == NULL
|
// _recursions == 0 _WaitSet == NULL
|
||||||
assert(((is_busy()|_recursions) == 0), "freeing inuse monitor");
|
DEBUG_ONLY(stringStream ss;)
|
||||||
|
assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
|
||||||
|
"recursions=" INTPTR_FORMAT, is_busy_to_string(&ss), _recursions);
|
||||||
_succ = NULL;
|
_succ = NULL;
|
||||||
_EntryList = NULL;
|
_EntryList = NULL;
|
||||||
_cxq = NULL;
|
_cxq = NULL;
|
||||||
|
@ -95,12 +95,8 @@ inline jint ObjectMonitor::contentions() const {
|
|||||||
return _contentions;
|
return _contentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do NOT set _contentions = 0. There is a race such that _contentions could
|
|
||||||
// be set while inflating prior to setting _owner
|
|
||||||
// Just use Atomic::inc/dec and assert 0 when monitor put on free list
|
|
||||||
inline void ObjectMonitor::set_owner(void* owner) {
|
inline void ObjectMonitor::set_owner(void* owner) {
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_recursions = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SHARE_RUNTIME_OBJECTMONITOR_INLINE_HPP
|
#endif // SHARE_RUNTIME_OBJECTMONITOR_INLINE_HPP
|
||||||
|
@ -242,7 +242,6 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread * Self,
|
|||||||
|
|
||||||
if (owner == NULL && Atomic::replace_if_null(Self, &(m->_owner))) {
|
if (owner == NULL && Atomic::replace_if_null(Self, &(m->_owner))) {
|
||||||
assert(m->_recursions == 0, "invariant");
|
assert(m->_recursions == 0, "invariant");
|
||||||
assert(m->_owner == Self, "invariant");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1030,6 +1029,7 @@ ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
|
|||||||
// 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;
|
||||||
|
stringStream ss;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ObjectMonitor * m;
|
ObjectMonitor * m;
|
||||||
|
|
||||||
@ -1065,7 +1065,6 @@ ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
|
|||||||
ObjectMonitor * take = gFreeList;
|
ObjectMonitor * take = gFreeList;
|
||||||
gFreeList = take->FreeNext;
|
gFreeList = take->FreeNext;
|
||||||
guarantee(take->object() == NULL, "invariant");
|
guarantee(take->object() == NULL, "invariant");
|
||||||
guarantee(!take->is_busy(), "invariant");
|
|
||||||
take->Recycle();
|
take->Recycle();
|
||||||
omRelease(Self, take, false);
|
omRelease(Self, take, false);
|
||||||
}
|
}
|
||||||
@ -1167,7 +1166,10 @@ void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m,
|
|||||||
bool fromPerThreadAlloc) {
|
bool fromPerThreadAlloc) {
|
||||||
guarantee(m->header() == NULL, "invariant");
|
guarantee(m->header() == NULL, "invariant");
|
||||||
guarantee(m->object() == NULL, "invariant");
|
guarantee(m->object() == NULL, "invariant");
|
||||||
guarantee(((m->is_busy()|m->_recursions) == 0), "freeing in-use monitor");
|
stringStream ss;
|
||||||
|
guarantee((m->is_busy() | m->_recursions) == 0, "freeing in-use monitor: "
|
||||||
|
"%s, recursions=" INTPTR_FORMAT, m->is_busy_to_string(&ss),
|
||||||
|
m->_recursions);
|
||||||
// Remove from omInUseList
|
// Remove from omInUseList
|
||||||
if (fromPerThreadAlloc) {
|
if (fromPerThreadAlloc) {
|
||||||
ObjectMonitor* cur_mid_in_use = NULL;
|
ObjectMonitor* cur_mid_in_use = NULL;
|
||||||
@ -1220,16 +1222,14 @@ void ObjectSynchronizer::omFlush(Thread * Self) {
|
|||||||
int tally = 0;
|
int tally = 0;
|
||||||
if (list != NULL) {
|
if (list != NULL) {
|
||||||
ObjectMonitor * s;
|
ObjectMonitor * s;
|
||||||
// The thread is going away, the per-thread free monitors
|
// The thread is going away. Set 'tail' to the last per-thread free
|
||||||
// are freed via set_owner(NULL)
|
// monitor which will be linked to gFreeList below under the gListLock.
|
||||||
// Link them to tail, which will be linked into the global free list
|
stringStream ss;
|
||||||
// gFreeList below, under the gListLock
|
|
||||||
for (s = list; s != NULL; s = s->FreeNext) {
|
for (s = list; s != NULL; s = s->FreeNext) {
|
||||||
tally++;
|
tally++;
|
||||||
tail = s;
|
tail = s;
|
||||||
guarantee(s->object() == NULL, "invariant");
|
guarantee(s->object() == NULL, "invariant");
|
||||||
guarantee(!s->is_busy(), "invariant");
|
guarantee(!s->is_busy(), "must be !is_busy: %s", s->is_busy_to_string(&ss));
|
||||||
s->set_owner(NULL); // redundant but good hygiene
|
|
||||||
}
|
}
|
||||||
guarantee(tail != NULL, "invariant");
|
guarantee(tail != NULL, "invariant");
|
||||||
assert(Self->omFreeCount == tally, "free-count off");
|
assert(Self->omFreeCount == tally, "free-count off");
|
||||||
@ -1379,7 +1379,6 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self,
|
|||||||
// in which INFLATING appears in the mark.
|
// in which INFLATING appears in the mark.
|
||||||
m->Recycle();
|
m->Recycle();
|
||||||
m->_Responsible = NULL;
|
m->_Responsible = NULL;
|
||||||
m->_recursions = 0;
|
|
||||||
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // Consider: maintain by type/class
|
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // Consider: maintain by type/class
|
||||||
|
|
||||||
markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
|
markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
|
||||||
@ -1472,9 +1471,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread * 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);
|
||||||
m->set_owner(NULL);
|
|
||||||
m->set_object(object);
|
m->set_object(object);
|
||||||
m->_recursions = 0;
|
|
||||||
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
|
||||||
|
|
||||||
@ -1925,14 +1922,15 @@ void ObjectSynchronizer::audit_and_print_stats(bool on_exit) {
|
|||||||
// Check a free monitor entry; log any errors.
|
// Check a free monitor entry; log any errors.
|
||||||
void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n,
|
void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n,
|
||||||
outputStream * out, int *error_cnt_p) {
|
outputStream * out, int *error_cnt_p) {
|
||||||
|
stringStream ss;
|
||||||
if (n->is_busy()) {
|
if (n->is_busy()) {
|
||||||
if (jt != NULL) {
|
if (jt != NULL) {
|
||||||
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
|
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
|
||||||
": free per-thread monitor must not be busy.", p2i(jt),
|
": free per-thread monitor must not be busy: %s", p2i(jt),
|
||||||
p2i(n));
|
p2i(n), n->is_busy_to_string(&ss));
|
||||||
} else {
|
} else {
|
||||||
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor "
|
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor "
|
||||||
"must not be busy.", p2i(n));
|
"must not be busy: %s", p2i(n), n->is_busy_to_string(&ss));
|
||||||
}
|
}
|
||||||
*error_cnt_p = *error_cnt_p + 1;
|
*error_cnt_p = *error_cnt_p + 1;
|
||||||
}
|
}
|
||||||
@ -2111,6 +2109,7 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out,
|
|||||||
Thread::muxAcquire(&gListLock, "log_in_use_monitor_details");
|
Thread::muxAcquire(&gListLock, "log_in_use_monitor_details");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stringStream ss;
|
||||||
if (gOmInUseCount > 0) {
|
if (gOmInUseCount > 0) {
|
||||||
out->print_cr("In-use global monitor info:");
|
out->print_cr("In-use global monitor info:");
|
||||||
out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)");
|
out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)");
|
||||||
@ -2121,9 +2120,14 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out,
|
|||||||
const oop obj = (oop) n->object();
|
const oop obj = (oop) n->object();
|
||||||
const markOop mark = n->header();
|
const markOop mark = n->header();
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
out->print_cr(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(n),
|
out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(n),
|
||||||
n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL,
|
n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL,
|
||||||
p2i(obj), obj->klass()->external_name());
|
p2i(obj), obj->klass()->external_name());
|
||||||
|
if (n->is_busy() != 0) {
|
||||||
|
out->print(" (%s)", n->is_busy_to_string(&ss));
|
||||||
|
ss.reset();
|
||||||
|
}
|
||||||
|
out->cr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2141,10 +2145,15 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out,
|
|||||||
const oop obj = (oop) n->object();
|
const oop obj = (oop) n->object();
|
||||||
const markOop mark = n->header();
|
const markOop mark = n->header();
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
out->print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT
|
out->print(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT
|
||||||
" %s", p2i(jt), p2i(n), n->is_busy() != 0,
|
" %s", p2i(jt), p2i(n), n->is_busy() != 0,
|
||||||
mark->hash() != 0, n->owner() != NULL, p2i(obj),
|
mark->hash() != 0, n->owner() != NULL, p2i(obj),
|
||||||
obj->klass()->external_name());
|
obj->klass()->external_name());
|
||||||
|
if (n->is_busy() != 0) {
|
||||||
|
out->print(" (%s)", n->is_busy_to_string(&ss));
|
||||||
|
ss.reset();
|
||||||
|
}
|
||||||
|
out->cr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user