summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/metrics/thread_watcher.cc91
-rw-r--r--chrome/browser/metrics/thread_watcher.h36
2 files changed, 116 insertions, 11 deletions
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 8318f8c..fcc518a 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -25,10 +25,13 @@ ThreadWatcher::ThreadWatcher(const BrowserThread::ID& thread_id,
sleep_time_(sleep_time),
unresponsive_time_(unresponsive_time),
ping_time_(base::TimeTicks::Now()),
+ pong_time_(ping_time_),
ping_sequence_number_(0),
active_(false),
ping_count_(kPingCount),
- histogram_(NULL),
+ response_time_histogram_(NULL),
+ unresponsive_time_histogram_(NULL),
+ unresponsive_count_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
Initialize();
}
@@ -131,9 +134,14 @@ void ThreadWatcher::PostPingMessage() {
void ThreadWatcher::OnPongMessage(uint64 ping_sequence_number) {
DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
+
// Record watched thread's response time.
- base::TimeDelta response_time = base::TimeTicks::Now() - ping_time_;
- histogram_->AddTime(response_time);
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta response_time = now - ping_time_;
+ response_time_histogram_->AddTime(response_time);
+
+ // Save the current time when we have got pong message.
+ pong_time_ = now;
// Check if there are any extra pings in flight.
DCHECK_EQ(ping_sequence_number_, ping_sequence_number);
@@ -163,15 +171,39 @@ bool ThreadWatcher::OnCheckResponsiveness(uint64 ping_sequence_number) {
// If the latest ping_sequence_number_ is not same as the ping_sequence_number
// that is passed in, then we can assume OnPongMessage was called.
// OnPongMessage increments ping_sequence_number_.
- return ping_sequence_number_ != ping_sequence_number;
+ if (ping_sequence_number_ != ping_sequence_number) {
+ // Reset unresponsive_count_ to zero because we got a response from the
+ // watched thread.
+ GotGoodResponse();
+ return true;
+ }
+ // Record that we got no response from watched thread.
+ GotNoResponse();
+
+ // Post a task to check the responsiveness of watched thread.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &ThreadWatcher::OnCheckResponsiveness, ping_sequence_number_),
+ unresponsive_time_.InMilliseconds());
+ return false;
}
void ThreadWatcher::Initialize() {
ThreadWatcherList::Register(this);
- const std::string histogram_name =
+
+ const std::string response_time_histogram_name =
"ThreadWatcher.ResponseTime." + thread_name_;
- histogram_ = base::Histogram::FactoryTimeGet(
- histogram_name,
+ response_time_histogram_ = base::Histogram::FactoryTimeGet(
+ response_time_histogram_name,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(100), 50,
+ base::Histogram::kUmaTargetedHistogramFlag);
+
+ const std::string unresponsive_time_histogram_name =
+ "ThreadWatcher.Unresponsive." + thread_name_;
+ unresponsive_time_histogram_ = base::Histogram::FactoryTimeGet(
+ unresponsive_time_histogram_name,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromSeconds(100), 50,
base::Histogram::kUmaTargetedHistogramFlag);
@@ -185,10 +217,30 @@ void ThreadWatcher::OnPingMessage(const BrowserThread::ID& thread_id,
WatchDogThread::PostTask(FROM_HERE, callback_task);
}
+void ThreadWatcher::GotGoodResponse() {
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
+ unresponsive_count_ = 0;
+}
+
+void ThreadWatcher::GotNoResponse() {
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
+ ++unresponsive_count_;
+ // If watched thread is the only unresponsive thread and all other threads are
+ // responding then record total unresponsive_time since last pong message.
+ if (ThreadWatcherList::GetNumberOfUnresponsiveThreads() == 1) {
+ base::TimeDelta unresponse_time = base::TimeTicks::Now() - pong_time_;
+ unresponsive_time_histogram_->AddTime(unresponse_time);
+ }
+}
+
// ThreadWatcherList methods and members.
//
// static
ThreadWatcherList* ThreadWatcherList::global_ = NULL;
+// static
+const int ThreadWatcherList::kSleepSeconds = 2;
+// static
+const int ThreadWatcherList::kUnresponsiveSeconds = 4;
ThreadWatcherList::ThreadWatcherList()
: last_wakeup_time_(base::TimeTicks::Now()) {
@@ -227,12 +279,14 @@ void ThreadWatcherList::StartWatchingAll() {
WatchDogThread::PostDelayedTask(
FROM_HERE,
NewRunnableFunction(&ThreadWatcherList::StartWatchingAll),
- base::TimeDelta::FromSeconds(5).InMilliseconds());
+ base::TimeDelta::FromSeconds(kSleepSeconds).InMilliseconds());
return;
}
DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
- const base::TimeDelta kSleepTime = base::TimeDelta::FromSeconds(5);
- const base::TimeDelta kUnresponsiveTime = base::TimeDelta::FromSeconds(10);
+ const base::TimeDelta kSleepTime =
+ base::TimeDelta::FromSeconds(kSleepSeconds);
+ const base::TimeDelta kUnresponsiveTime =
+ base::TimeDelta::FromSeconds(kUnresponsiveSeconds);
if (BrowserThread::IsMessageLoopValid(BrowserThread::UI)) {
ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime,
kUnresponsiveTime);
@@ -283,6 +337,23 @@ void ThreadWatcherList::RemoveNotifications() {
global_->registrar_.RemoveAll();
}
+// static
+int ThreadWatcherList::GetNumberOfUnresponsiveThreads() {
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
+ int no_of_unresponding_threads = 0;
+ if (!global_)
+ return no_of_unresponding_threads;
+
+ base::AutoLock auto_lock(global_->lock_);
+ for (RegistrationList::iterator it = global_->registered_.begin();
+ global_->registered_.end() != it;
+ ++it) {
+ if (it->second->unresponsive_count_ > 0)
+ ++no_of_unresponding_threads;
+ }
+ return no_of_unresponding_threads;
+}
+
void ThreadWatcherList::DeleteAll() {
DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
base::AutoLock auto_lock(lock_);
diff --git a/chrome/browser/metrics/thread_watcher.h b/chrome/browser/metrics/thread_watcher.h
index 53cdb8d..5402c5f 100644
--- a/chrome/browser/metrics/thread_watcher.h
+++ b/chrome/browser/metrics/thread_watcher.h
@@ -149,6 +149,14 @@ class ThreadWatcher {
static void OnPingMessage(const BrowserThread::ID& thread_id,
Task* callback_task);
+ // This method resets unresponsive_count_ to zero because watched thread is
+ // responding to the ping message with a pong message.
+ void GotGoodResponse();
+
+ // This method records watched thread is not responding to the ping message.
+ // It increments unresponsive_count_ by 1.
+ void GotNoResponse();
+
// This is the number of ping messages to be sent when the user is idle.
// ping_count_ will be initialized to kPingCount whenever user becomes active.
static const int kPingCount;
@@ -171,6 +179,9 @@ class ThreadWatcher {
// This is the last time when ping message was sent.
base::TimeTicks ping_time_;
+ // This is the last time when we got pong message.
+ base::TimeTicks pong_time_;
+
// This is the sequence number of the next ping for which there is no pong. If
// the instance is sleeping, then it will be the sequence number for the next
// ping.
@@ -186,7 +197,19 @@ class ThreadWatcher {
int ping_count_;
// Histogram that keeps track of response times for the watched thread.
- base::Histogram* histogram_;
+ base::Histogram* response_time_histogram_;
+
+ // Histogram that keeps track of unresponsive time since the last pong message
+ // when we got no response (GotNoResponse) from the watched thread. We record
+ // this when the watched thread is the only unresponsive thread and all other
+ // threads are responsive.
+ base::Histogram* unresponsive_time_histogram_;
+
+ // This counter tracks the unresponsiveness of watched thread. If this value
+ // is zero then watched thread has responded with a pong message. This is
+ // incremented by 1 when we got no response (GotNoResponse) from the watched
+ // thread.
+ int unresponsive_count_;
// We use this factory to create callback tasks for ThreadWatcher object. We
// use this during ping-pong messaging between WatchDog thread and watched
@@ -231,6 +254,10 @@ class ThreadWatcherList : public NotificationObserver {
// This method is accessible on UI thread.
static void RemoveNotifications();
+ // This method returns number of watched threads that haven't responded with a
+ // pong message (number of threads with unresponsive_count_ greater than 0).
+ static int GetNumberOfUnresponsiveThreads();
+
private:
// Allow tests to access our innards for testing purposes.
FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, Registration);
@@ -262,6 +289,13 @@ class ThreadWatcherList : public NotificationObserver {
static ThreadWatcherList* global_; // The singleton of this class.
+ // This is the wait time between ping messages.
+ static const int kSleepSeconds;
+
+ // This is the wait time after ping message is sent, to check if we have
+ // received pong message or not.
+ static const int kUnresponsiveSeconds;
+
// Lock for access to registered_.
base::Lock lock_;