diff options
| author | 2011-11-09 17:54:24 -0800 | |
|---|---|---|
| committer | 2011-11-11 10:51:43 -0800 | |
| commit | 33dc7717cd16592bcc825350bea6305be9eb2ea1 (patch) | |
| tree | da0643d598a30d0fb3e63ba036f53cbda1e011fd | |
| parent | 72db0d77d6c476c71c5bbaa14a80ca77f23a47f3 (diff) | |
Changed monitor to contain method and return pc values for logging.
The monitor saves method and return pc for logging, instead of the
source filename and line number. This saves it from having to do a
lookup every time a fat lock is acquired.
Change-Id: I88871abc90626b9e4dffc9677c093fd24937385c
| -rw-r--r-- | src/monitor.cc | 57 | ||||
| -rw-r--r-- | src/monitor.h | 14 | ||||
| -rw-r--r-- | src/monitor_android.cc | 2 | ||||
| -rw-r--r-- | src/thread.cc | 38 | ||||
| -rw-r--r-- | src/thread.h | 5 |
5 files changed, 62 insertions, 54 deletions
diff --git a/src/monitor.cc b/src/monitor.cc index 16298aed86..b9a94590f3 100644 --- a/src/monitor.cc +++ b/src/monitor.cc @@ -24,6 +24,7 @@ #include <time.h> #include <unistd.h> +#include "class_linker.h" #include "mutex.h" #include "object.h" #include "stl_util.h" @@ -120,8 +121,8 @@ Monitor::Monitor(Object* obj) obj_(obj), wait_set_(NULL), lock_("a monitor lock"), - owner_filename_(NULL), - owner_line_number_(0) { + locking_method_(NULL), + locking_pc_(0) { } Monitor::~Monitor() { @@ -197,15 +198,15 @@ void Monitor::Lock(Thread* self) { uint64_t waitStart, waitEnd; if (!lock_.TryLock()) { uint32_t wait_threshold = lock_profiling_threshold_; - const char* current_owner_filename = NULL; - uint32_t current_owner_line_number = -1; + const Method* current_locking_method = NULL; + uint32_t current_locking_pc = 0; { ScopedThreadStateChange tsc(self, Thread::kBlocked); if (wait_threshold != 0) { waitStart = NanoTime() / 1000; } - current_owner_filename = owner_filename_; - current_owner_line_number = owner_line_number_; + current_locking_method = locking_method_; + current_locking_pc = locking_pc_; lock_.Lock(); if (wait_threshold != 0) { @@ -222,7 +223,11 @@ void Monitor::Lock(Thread* self) { sample_percent = 100 * wait_ms / wait_threshold; } if (sample_percent != 0 && (static_cast<uint32_t>(rand() % 100) < sample_percent)) { - LogContentionEvent(self, wait_ms, sample_percent, current_owner_filename, current_owner_line_number); + const char* current_locking_filename; + uint32_t current_locking_line_number; + TranslateLocation(current_locking_method, current_locking_pc, + current_locking_filename, current_locking_line_number); + LogContentionEvent(self, wait_ms, sample_percent, current_locking_filename, current_locking_line_number); } } } @@ -232,7 +237,8 @@ void Monitor::Lock(Thread* self) { // When debugging, save the current monitor holder for future // acquisition failures to use in sampled logging. if (lock_profiling_threshold_ != 0) { - self->GetCurrentLocation(owner_filename_, owner_line_number_); + locking_method_ = self->GetCurrentMethod(); + locking_pc_ = self->GetCurrentReturnPc(); } } @@ -246,8 +252,8 @@ bool Monitor::Unlock(Thread* self) { // We own the monitor, so nobody else can be in here. if (lock_count_ == 0) { owner_ = NULL; - owner_filename_ = "unlocked"; - owner_line_number_ = 0; + locking_method_ = NULL; + locking_pc_ = 0; lock_.Unlock(); } else { --lock_count_; @@ -366,10 +372,10 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, bool interruptShouldThr int prevLockCount = lock_count_; lock_count_ = 0; owner_ = NULL; - const char* savedFileName = owner_filename_; - owner_filename_ = NULL; - uint32_t savedLineNumber = owner_line_number_; - owner_line_number_ = 0; + const Method* savedMethod = locking_method_; + locking_method_ = NULL; + uint32_t savedPc = locking_pc_; + locking_pc_ = 0; /* * Update thread status. If the GC wakes up, it'll ignore us, knowing @@ -435,8 +441,8 @@ done: */ owner_ = self; lock_count_ = prevLockCount; - owner_filename_ = savedFileName; - owner_line_number_ = savedLineNumber; + locking_method_ = savedMethod; + locking_pc_ = savedPc; RemoveFromWaitSet(self); /* set self->status back to Thread::kRunnable, and self-suspend if needed */ @@ -810,6 +816,25 @@ void Monitor::DescribeWait(std::ostream& os, const Thread* thread) { os << "\n"; } +void Monitor::TranslateLocation(const Method* method, uint32_t pc, + const char*& source_file, uint32_t& line_number) const { + // If method is null, location is unknown + if (method == NULL) { + source_file = "unknown"; + line_number = 0; + return; + } + + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Class* c = method->GetDeclaringClass(); + DexCache* dex_cache = c->GetDexCache(); + const DexFile& dex_file = class_linker->FindDexFile(dex_cache); + const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8()); + + source_file = dex_file.dexGetSourceFile(*class_def); + line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(pc)); +} + MonitorList::MonitorList() : lock_("MonitorList lock") { } diff --git a/src/monitor.h b/src/monitor.h index be704bab54..9b79f8ec27 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -55,6 +55,7 @@ namespace art { #define LW_LOCK_OWNER_SHIFT 3 #define LW_LOCK_OWNER(x) (((x) >> LW_LOCK_OWNER_SHIFT) & LW_LOCK_OWNER_MASK) +class Method; class Object; class Thread; @@ -97,6 +98,10 @@ class Monitor { void Wait(Thread* self, int64_t msec, int32_t nsec, bool interruptShouldThrow); + // Translates the provided method and pc into its declaring class' source file and line number. + void TranslateLocation(const Method* method, uint32_t pc, + const char*& source_file, uint32_t& line_number) const; + static bool (*is_sensitive_thread_hook_)(); static bool is_verbose_; static uint32_t lock_profiling_threshold_; @@ -115,10 +120,11 @@ class Monitor { Mutex lock_; - // Who last acquired this monitor, when lock sampling is enabled. - // Even when enabled, owner_filename_ may be NULL. - const char* owner_filename_; - uint32_t owner_line_number_; + // Method and pc where the lock owner acquired the lock, used when lock + // sampling is enabled. locking_method_ may be null if the lock is currently + // unlocked, or if the lock is acquired by the system when the stack is empty. + const Method* locking_method_; + uint32_t locking_pc_; friend class MonitorList; friend class Object; diff --git a/src/monitor_android.cc b/src/monitor_android.cc index 95dd397042..39dc5244d1 100644 --- a/src/monitor_android.cc +++ b/src/monitor_android.cc @@ -78,7 +78,7 @@ void Monitor::LogContentionEvent(Thread* self, uint32_t wait_ms, uint32_t sample // Emit the source code file name, <= 37 bytes. const char* filename; uint32_t line_number; - self->GetCurrentLocation(filename, line_number); + TranslateLocation(self->GetCurrentMethod(), self->GetCurrentReturnPc(), filename, line_number); cp = EventLogWriteString(cp, filename, strlen(filename)); // Emit the source code line number, 5 bytes. diff --git a/src/thread.cc b/src/thread.cc index 2bdfb3c73d..5dd0f2dca2 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -1191,35 +1191,6 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job return result; } -void Thread::GetCurrentLocation(const char*& source_file, uint32_t& line_number) const { - Frame f = top_of_managed_stack_; - Method* m = f.GetMethod(); - - // Check if the stack is empty - if (m == NULL) { - source_file = "UNKNOWN"; - line_number = 0; - return; - } - - // TODO: can this ever happen? - if (m->IsCalleeSaveMethod()) { - f.Next(); - m = f.GetMethod(); - } - - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Class* c = m->GetDeclaringClass(); - DexCache* dex_cache = c->GetDexCache(); - const DexFile& dex_file = class_linker->FindDexFile(dex_cache); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8()); - - source_file = dex_file.dexGetSourceFile(*class_def); - - uint32_t pc = ManglePc(f.GetReturnPC()); - line_number = dex_file.GetLineNumFromPC(m, m->ToDexPC(pc)); -} - void Thread::ThrowNewExceptionF(const char* exception_class_descriptor, const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -1399,7 +1370,7 @@ const Method* Thread::GetCurrentMethod() const { // here via a "FromCode" function, in which case there's a synthetic // callee-save method at the top of the stack. These shouldn't be user-visible, // so if we find one, skip it and return the compiled method underneath. - if (m->IsCalleeSaveMethod()) { + if (m != NULL && m->IsCalleeSaveMethod()) { Frame f = top_of_managed_stack_; f.Next(); m = f.GetMethod(); @@ -1407,6 +1378,13 @@ const Method* Thread::GetCurrentMethod() const { return m; } +uint32_t Thread::GetCurrentReturnPc() const { + if (top_of_managed_stack_.GetMethod() == NULL) { + return 0; + } + return ManglePc(top_of_managed_stack_.GetReturnPC()); +} + bool Thread::HoldsLock(Object* object) { if (object == NULL) { return false; diff --git a/src/thread.h b/src/thread.h index 15ded2490c..7b8c8b9524 100644 --- a/src/thread.h +++ b/src/thread.h @@ -229,9 +229,6 @@ class PACKED Thread { // Returns the java.lang.Thread's name, or NULL. String* GetName() const; - // Returns the current method's declaring class' source file and the current line number. - void GetCurrentLocation(const char*& source_file, uint32_t& line_number) const; - Object* GetPeer() const { return peer_; } @@ -244,6 +241,8 @@ class PACKED Thread { // This is used by the JNI implementation for logging and diagnostic purposes. const Method* GetCurrentMethod() const; + uint32_t GetCurrentReturnPc() const; + bool IsExceptionPending() const { return exception_ != NULL; } |