diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-03-31 16:36:35 -0700 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2014-04-07 13:44:36 -0700 |
commit | 440e4ceb310349ee8eb569495bc04d3d7fbe71cb (patch) | |
tree | db278d463f0c2440e9c8e8cb80e53d2b2effe196 /runtime/monitor.cc | |
parent | 4d3dc8a04da8a80251b381cdb482190363171dc1 (diff) | |
download | art-440e4ceb310349ee8eb569495bc04d3d7fbe71cb.zip art-440e4ceb310349ee8eb569495bc04d3d7fbe71cb.tar.gz art-440e4ceb310349ee8eb569495bc04d3d7fbe71cb.tar.bz2 |
Add monitor deflation.
We now deflate the monitors when we perform a heap trim. This causes
a pause but it shouldn't matter since we should be in a state where
we don't care about pauses. Memory savings are hard to measure.
Fixed integer overflow bug in GetEstimatedLastIterationThroughput.
Bug: 13733906
Change-Id: I4e0e68add02e7f43370b3a5ea763d6fe8a5b212c
Diffstat (limited to 'runtime/monitor.cc')
-rw-r--r-- | runtime/monitor.cc | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/runtime/monitor.cc b/runtime/monitor.cc index bcaf8ec..bbc7dd0 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -205,7 +205,7 @@ void Monitor::SetObject(mirror::Object* object) { void Monitor::Lock(Thread* self) { MutexLock mu(self, monitor_lock_); while (true) { - if (owner_ == NULL) { // Unowned. + if (owner_ == nullptr) { // Unowned. owner_ = self; CHECK_EQ(lock_count_, 0); // When debugging, save the current monitor holder for future @@ -223,15 +223,15 @@ void Monitor::Lock(Thread* self) { uint64_t wait_start_ms = log_contention ? 0 : MilliTime(); mirror::ArtMethod* owners_method = locking_method_; uint32_t owners_dex_pc = locking_dex_pc_; + // Do this before releasing the lock so that we don't get deflated. + ++num_waiters_; monitor_lock_.Unlock(self); // Let go of locks in order. { ScopedThreadStateChange tsc(self, kBlocked); // Change to blocked and give up mutator_lock_. self->SetMonitorEnterObject(obj_); MutexLock mu2(self, monitor_lock_); // Reacquire monitor_lock_ without mutator_lock_ for Wait. if (owner_ != NULL) { // Did the owner_ give the lock up? - ++num_waiters_; monitor_contenders_.Wait(self); // Still contended so wait. - --num_waiters_; // Woken from contention. if (log_contention) { uint64_t wait_ms = MilliTime() - wait_start_ms; @@ -252,6 +252,7 @@ void Monitor::Lock(Thread* self) { self->SetMonitorEnterObject(nullptr); } monitor_lock_.Lock(self); // Reacquire locks in order. + --num_waiters_; } } @@ -431,6 +432,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, * not order sensitive as we hold the pthread mutex. */ AppendToWaitSet(self); + ++num_waiters_; int prev_lock_count = lock_count_; lock_count_ = 0; owner_ = NULL; @@ -507,6 +509,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, lock_count_ = prev_lock_count; locking_method_ = saved_method; locking_dex_pc_ = saved_dex_pc; + --num_waiters_; RemoveFromWaitSet(self); if (was_interrupted) { @@ -575,8 +578,12 @@ bool Monitor::Deflate(Thread* self, mirror::Object* obj) { // If the lock isn't an inflated monitor, then we don't need to deflate anything. if (lw.GetState() == LockWord::kFatLocked) { Monitor* monitor = lw.FatLockMonitor(); - CHECK(monitor != nullptr); + DCHECK(monitor != nullptr); MutexLock mu(self, monitor->monitor_lock_); + // Can't deflate if we have anybody waiting on the CV. + if (monitor->num_waiters_ > 0) { + return false; + } Thread* owner = monitor->owner_; if (owner != nullptr) { // Can't deflate if we are locked and have a hash code. @@ -587,17 +594,16 @@ bool Monitor::Deflate(Thread* self, mirror::Object* obj) { if (monitor->lock_count_ > LockWord::kThinLockMaxCount) { return false; } - // Can't deflate if we have anybody waiting on the CV. - if (monitor->num_waiters_ > 0) { - return false; - } // Deflate to a thin lock. - obj->SetLockWord(LockWord::FromThinLockId(owner->GetTid(), monitor->lock_count_)); + obj->SetLockWord(LockWord::FromThinLockId(owner->GetThreadId(), monitor->lock_count_)); + VLOG(monitor) << "Deflated " << obj << " to thin lock " << owner->GetTid() << " / " << monitor->lock_count_; } else if (monitor->HasHashCode()) { obj->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode())); + VLOG(monitor) << "Deflated " << obj << " to hash monitor " << monitor->GetHashCode(); } else { // No lock and no hash, just put an empty lock word inside the object. obj->SetLockWord(LockWord()); + VLOG(monitor) << "Deflated" << obj << " to empty lock word"; } // The monitor is deflated, mark the object as nullptr so that we know to delete it during the // next GC. @@ -1054,7 +1060,7 @@ uint32_t Monitor::GetOwnerThreadId() { } MonitorList::MonitorList() - : allow_new_monitors_(true), monitor_list_lock_("MonitorList lock"), + : allow_new_monitors_(true), monitor_list_lock_("MonitorList lock", kMonitorListLock), monitor_add_condition_("MonitorList disallow condition", monitor_list_lock_) { } @@ -1103,6 +1109,22 @@ void MonitorList::SweepMonitorList(IsMarkedCallback* callback, void* arg) { } } +static mirror::Object* MonitorDeflateCallback(mirror::Object* object, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (Monitor::Deflate(reinterpret_cast<Thread*>(arg), object)) { + DCHECK_NE(object->GetLockWord().GetState(), LockWord::kFatLocked); + // If we deflated, return nullptr so that the monitor gets removed from the array. + return nullptr; + } + return object; // Monitor was not deflated. +} + +void MonitorList::DeflateMonitors() { + Thread* self = Thread::Current(); + Locks::mutator_lock_->AssertExclusiveHeld(self); + SweepMonitorList(MonitorDeflateCallback, reinterpret_cast<Thread*>(self)); +} + MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(NULL), entry_count_(0) { DCHECK(obj != NULL); |