Polish the lock contention logging.
- Make the code compilable.
- Surround the code with kLogLockContentions instead of #ifdef CONTENTION_LOGGING.
- Dump contended locks before never-contended locks for better log readability.
- Change the wait time unit from ms to us for better precision.
Bug: 9986464
Change-Id: I121c6ccf4424d3e0339b0dcd25e18976b41fe4f3
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 2f41bcd..0e5445f 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -23,6 +23,7 @@
#include <iosfwd>
#include <string>
+#include "atomic_integer.h"
#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
@@ -41,13 +42,6 @@
#define HAVE_TIMED_RWLOCK 0
#endif
-// Record Log contention information, dumpable via SIGQUIT.
-#define CONTENTION_LOGGING (0 && ART_USE_FUTEXES)
-const size_t kContentionLogSize = 64;
-#if CONTENTION_LOGGING
-#include "atomic_integer.h"
-#endif
-
namespace art {
class ScopedContentionRecorder;
@@ -55,6 +49,19 @@
const bool kDebugLocking = true || kIsDebugBuild;
+// Record Log contention information, dumpable via SIGQUIT.
+#ifdef ART_USE_FUTEXES
+// To enable lock contention logging, flip this to true.
+const bool kLogLockContentions = false;
+#else
+// Keep this false as lock contention logging is supported only with
+// futex.
+const bool kLogLockContentions = false;
+#endif
+const size_t kContentionLogSize = 64;
+const size_t kContentionLogDataSize = kLogLockContentions ? 1 : 0;
+const size_t kAllMutexDataSize = kLogLockContentions ? 1 : 0;
+
// Base class for all Mutex implementations
class BaseMutex {
public:
@@ -80,12 +87,12 @@
friend class ScopedContentionRecorder;
- void RecordContention(uint64_t blocked_tid, uint64_t owner_tid, uint64_t milli_time_blocked);
+ void RecordContention(uint64_t blocked_tid, uint64_t owner_tid, uint64_t nano_time_blocked);
void DumpContention(std::ostream& os) const;
const LockLevel level_; // Support for lock hierarchy.
const char* const name_;
-#if CONTENTION_LOGGING
+
// A log entry that records contention but makes no guarantee that either tid will be held live.
struct ContentionLogEntry {
ContentionLogEntry() : blocked_tid(0), owner_tid(0) {}
@@ -93,15 +100,27 @@
uint64_t owner_tid;
AtomicInteger count;
};
- ContentionLogEntry contention_log_[kContentionLogSize];
- // The next entry in the contention log to be updated. Value ranges from 0 to
- // kContentionLogSize - 1.
- AtomicInteger cur_content_log_entry_;
- // Number of times the Mutex has been contended.
- AtomicInteger contention_count_;
- // Sum of time waited by all contenders in ms.
- AtomicInteger wait_time_;
-#endif
+ struct ContentionLogData {
+ ContentionLogEntry contention_log[kContentionLogSize];
+ // The next entry in the contention log to be updated. Value ranges from 0 to
+ // kContentionLogSize - 1.
+ AtomicInteger cur_content_log_entry;
+ // Number of times the Mutex has been contended.
+ AtomicInteger contention_count;
+ // Sum of time waited by all contenders in ns.
+ volatile uint64_t wait_time;
+ void AddToWaitTime(uint64_t value);
+ ContentionLogData() : wait_time(0) {}
+ };
+ ContentionLogData contetion_log_data_[kContentionLogDataSize];
+
+ public:
+ bool HasEverContended() const {
+ if (kLogLockContentions) {
+ return contetion_log_data_->contention_count > 0;
+ }
+ return false;
+ }
};
// A Mutex is used to achieve mutual exclusion between threads. A Mutex can be used to gain