Index: chrome/browser/metrics/thread_watcher.h |
=================================================================== |
--- chrome/browser/metrics/thread_watcher.h (revision 89361) |
+++ chrome/browser/metrics/thread_watcher.h (working copy) |
@@ -18,24 +18,37 @@ |
// |
// Example Usage: |
// |
-// The following is an example for watching responsiveness of IO thread. |
-// sleep_time specifies how often ping messages have to be sent to IO thread. |
-// unresponsive_time is the wait time after ping message is sent, to check if |
-// we have received pong message or not. |
+// The following is an example for watching responsiveness of watched (IO) |
+// thread. |sleep_time| specifies how often ping messages have to be sent to |
+// watched (IO) thread. |unresponsive_time| is the wait time after ping |
+// message is sent, to check if we have received pong message or not. |
+// |unresponsive_threshold| specifies the number of unanswered ping messages |
+// after which watched (IO) thread is considered as not responsive. |
+// |crash_on_hang| specifies if we want to crash the browser when the watched |
+// (IO) thread has become sufficiently unresponsive, while other threads are |
+// sufficiently responsive. |live_threads_threshold| specifies the number of |
+// browser threads that are to be responsive when we want to crash the browser |
+// because of hung watched (IO) thread. |
// |
// base::TimeDelta sleep_time = base::TimeDelta::FromSeconds(5); |
// base::TimeDelta unresponsive_time = base::TimeDelta::FromSeconds(10); |
-// ThreadWatcher::StartWatching(BrowserThread::IO, "IO", sleep_time, |
-// unresponsive_time); |
+// uint32 unresponsive_threshold = ThreadWatcherList::kUnresponsiveCount; |
+// bool crash_on_hang = false; |
+// uint32 live_threads_threshold = ThreadWatcherList::kLiveThreadsThreshold; |
+// ThreadWatcher::StartWatching( |
+// BrowserThread::IO, "IO", sleep_time, unresponsive_time, |
+// unresponsive_threshold, crash_on_hang, live_threads_threshold); |
#ifndef CHROME_BROWSER_METRICS_THREAD_WATCHER_H_ |
#define CHROME_BROWSER_METRICS_THREAD_WATCHER_H_ |
#include <map> |
+#include <set> |
#include <string> |
#include <vector> |
#include "base/basictypes.h" |
+#include "base/command_line.h" |
#include "base/gtest_prod_util.h" |
#include "base/memory/ref_counted.h" |
#include "base/memory/scoped_ptr.h" |
@@ -51,23 +64,33 @@ |
class CustomThreadWatcher; |
class ThreadWatcherList; |
+class ThreadWatcherObserver; |
// This class performs health check on threads that would like to be watched. |
class ThreadWatcher { |
public: |
- // This method starts performing health check on the given thread_id. It will |
- // create ThreadWatcher object for the given thread_id, thread_name, |
- // sleep_time and unresponsive_time. sleep_time_ is the wait time between ping |
- // messages. unresponsive_time_ is the wait time after ping message is sent, |
- // to check if we have received pong message or not. It will register that |
- // ThreadWatcher object and activate the thread watching of the given |
- // thread_id. |
+ // This method starts performing health check on the given |thread_id|. It |
+ // will create ThreadWatcher object for the given |thread_id|, |thread_name|. |
+ // |sleep_time| is the wait time between ping messages. |unresponsive_time| is |
+ // the wait time after ping message is sent, to check if we have received pong |
+ // message or not. |unresponsive_threshold| is used to determine if the thread |
+ // is responsive or not. The watched thread is considered unresponsive if it |
+ // hasn't responded with a pong message for |unresponsive_threshold| number of |
+ // ping messages. |crash_on_hang| specifies if browser should be crashed when |
+ // the watched thread is unresponsive. |live_threads_threshold| specifies the |
+ // number of browser threads that are to be responsive when we want to crash |
+ // the browser and watched thread has become sufficiently unresponsive. It |
+ // will register that ThreadWatcher object and activate the thread watching of |
+ // the given thread_id. |
static void StartWatching(const BrowserThread::ID& thread_id, |
const std::string& thread_name, |
const base::TimeDelta& sleep_time, |
- const base::TimeDelta& unresponsive_time); |
+ const base::TimeDelta& unresponsive_time, |
+ uint32 unresponsive_threshold, |
+ bool crash_on_hang, |
+ uint32 live_threads_threshold); |
- // Return the thread_id of the thread being watched. |
+ // Return the |thread_id_| of the thread being watched. |
BrowserThread::ID thread_id() const { return thread_id_; } |
// Return the name of the thread being watched. |
@@ -82,20 +105,23 @@ |
// Returns true if we are montioring the thread. |
bool active() const { return active_; } |
- // Returns ping_time_ (used by unit tests). |
+ // Returns |ping_time_| (used by unit tests). |
base::TimeTicks ping_time() const { return ping_time_; } |
- // Returns ping_sequence_number_ (used by unit tests). |
+ // Returns |ping_sequence_number_| (used by unit tests). |
uint64 ping_sequence_number() const { return ping_sequence_number_; } |
protected: |
- // Construct a ThreadWatcher for the given thread_id. sleep_time_ is the |
- // wait time between ping messages. unresponsive_time_ is the wait time after |
+ // Construct a ThreadWatcher for the given |thread_id|. |sleep_time| is the |
+ // wait time between ping messages. |unresponsive_time| is the wait time after |
// ping message is sent, to check if we have received pong message or not. |
ThreadWatcher(const BrowserThread::ID& thread_id, |
const std::string& thread_name, |
const base::TimeDelta& sleep_time, |
- const base::TimeDelta& unresponsive_time); |
+ const base::TimeDelta& unresponsive_time, |
+ uint32 unresponsive_threshold, |
+ bool crash_on_hang, |
+ uint32 live_threads_threshold); |
virtual ~ThreadWatcher(); |
// This method activates the thread watching which starts ping/pong messaging. |
@@ -105,29 +131,29 @@ |
virtual void DeActivateThreadWatching(); |
// This will ensure that the watching is actively taking place, and awaken |
- // (i.e., post a PostPingMessage) if the watcher has stopped pinging due to |
- // lack of user activity. It will also reset ping_count_ to kPingCount. |
+ // (i.e., post a PostPingMessage()) if the watcher has stopped pinging due to |
+ // lack of user activity. It will also reset |ping_count_| to |kPingCount|. |
virtual void WakeUp(); |
// This method records when ping message was sent and it will Post a task |
- // (OnPingMessage) to the watched thread that does nothing but respond with |
- // OnPongMessage. It also posts a task (OnCheckResponsiveness) to check |
+ // (OnPingMessage()) to the watched thread that does nothing but respond with |
+ // OnPongMessage(). It also posts a task (OnCheckResponsiveness()) to check |
// responsiveness of monitored thread that would be called after waiting |
- // unresponsive_time_. |
+ // |unresponsive_time_|. |
// This method is accessible on WatchDogThread. |
virtual void PostPingMessage(); |
// This method handles a Pong Message from watched thread. It will track the |
// response time (pong time minus ping time) via histograms. It posts a |
- // PostPingMessage task that would be called after waiting sleep_time_. It |
- // increments ping_sequence_number_ by 1. |
+ // PostPingMessage() task that would be called after waiting |sleep_time_|. It |
+ // increments |ping_sequence_number_| by 1. |
// This method is accessible on WatchDogThread. |
virtual void OnPongMessage(uint64 ping_sequence_number); |
// This method will determine if the watched thread is responsive or not. If |
- // the latest ping_sequence_number_ is not same as the ping_sequence_number |
- // that is passed in, then we can assume that watched thread has responded |
- // with a pong message. |
+ // the latest |ping_sequence_number_| is not same as the |
+ // |ping_sequence_number| that is passed in, then we can assume that watched |
+ // thread has responded with a pong message. |
// This method is accessible on WatchDogThread. |
virtual bool OnCheckResponsiveness(uint64 ping_sequence_number); |
@@ -150,33 +176,31 @@ |
static void OnPingMessage(const BrowserThread::ID& thread_id, |
Task* callback_task); |
- // This method resets unresponsive_count_ to zero because watched thread is |
+ // This method resets |unresponsive_count_| to zero because watched thread is |
// responding to the ping message with a pong message. |
void ResetHangCounters(); |
// This method records watched thread is not responding to the ping message. |
- // It increments unresponsive_count_ by 1. |
+ // It increments |unresponsive_count_| by 1. |
void GotNoResponse(); |
+ // This method returns true if the watched thread has not responded with a |
+ // pong message for |unresponsive_threshold_| number of ping messages. |
+ bool IsVeryUnresponsive(); |
+ |
// 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; |
- // This value is used to determine if the watched thread is responsive or not. |
- // If unresponsive_count_ is less than kUnresponsiveCount then watched thread |
- // is considered as responsive (in responsive_count_histogram_) otherwise it |
- // is considered as unresponsive (in unresponsive_count_histogram_). |
- static const int kUnresponsiveCount; |
- |
- // The thread_id of the thread being watched. Only one instance can exist for |
- // the given thread_id of the thread being watched. |
+ // The |thread_id_| of the thread being watched. Only one instance can exist |
+ // for the given |thread_id_| of the thread being watched. |
const BrowserThread::ID thread_id_; |
// The name of the thread being watched. |
const std::string thread_name_; |
- // It is the sleep time between between the receipt of a pong message back, |
- // and the sending of another ping message. |
+ // It is the sleep time between the receipt of a pong message back, and the |
+ // sending of another ping message. |
const base::TimeDelta sleep_time_; |
// It is the duration from sending a ping message, until we check status to be |
@@ -207,29 +231,44 @@ |
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. |
+ // when we got no response (GotNoResponse()) from the watched thread. |
base::Histogram* unresponsive_time_histogram_; |
// Histogram that keeps track of how many threads are responding when we got |
- // no response (GotNoResponse) from the watched thread. |
+ // no response (GotNoResponse()) from the watched thread. |
base::Histogram* responsive_count_histogram_; |
// Histogram that keeps track of how many threads are not responding when we |
- // got no response (GotNoResponse) from the watched thread. Count includes the |
- // thread that got no response. |
+ // got no response (GotNoResponse()) from the watched thread. Count includes |
+ // the thread that got no response. |
base::Histogram* unresponsive_count_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 |
+ // incremented by 1 when we got no response (GotNoResponse()) from the watched |
// thread. |
- int unresponsive_count_; |
+ uint32 unresponsive_count_; |
// This is set to true when we would have crashed the browser because the |
// watched thread hasn't responded atleast 6 times. It is reset to false when |
// watched thread responds with a pong message. |
bool hung_processing_complete_; |
+ // This is used to determine if the watched thread is responsive or not. If |
+ // watched thread's |unresponsive_count_| is greater than or equal to |
+ // |unresponsive_threshold_| then we would consider it as unresponsive. |
+ uint32 unresponsive_threshold_; |
+ |
+ // This is set to true if we want to crash the browser when the watched thread |
+ // has become sufficiently unresponsive, while other threads are sufficiently |
+ // responsive. |
+ bool crash_on_hang_; |
+ |
+ // This specifies the number of browser threads that are to be responsive when |
+ // we want to crash the browser because watched thread has become sufficiently |
+ // unresponsive. |
+ uint32 live_threads_threshold_; |
+ |
// We use this factory to create callback tasks for ThreadWatcher object. We |
// use this during ping-pong messaging between WatchDog thread and watched |
// thread. |
@@ -242,26 +281,15 @@ |
// if it has been registered, which includes determing the histogram name. This |
// class provides utility functions to start and stop watching all browser |
// threads. Only one instance of this class exists. |
-class ThreadWatcherList : public NotificationObserver { |
+class ThreadWatcherList { |
public: |
// A map from BrowserThread to the actual instances. |
typedef std::map<BrowserThread::ID, ThreadWatcher*> RegistrationList; |
- // This singleton holds the global list of registered ThreadWatchers. |
- ThreadWatcherList(); |
- // Destructor deletes all registered ThreadWatcher instances. |
- virtual ~ThreadWatcherList(); |
- |
- // Register() stores a pointer to the given ThreadWatcher in a global map. |
- static void Register(ThreadWatcher* watcher); |
- |
- // This method returns true if the ThreadWatcher object is registerd. |
- static bool IsRegistered(const BrowserThread::ID thread_id); |
- |
// This method posts a task on WatchDogThread to start watching all browser |
// threads. |
// This method is accessible on UI thread. |
- static void StartWatchingAll(); |
+ static void StartWatchingAll(const CommandLine& command_line); |
// This method posts a task on WatchDogThread to RevokeAll tasks and to |
// deactive thread watching of other threads and tell NotificationService to |
@@ -269,46 +297,74 @@ |
// This method is accessible on UI thread. |
static void StopWatchingAll(); |
- // RemoveAll NotificationTypes that are being observed. |
- // This method is accessible on UI thread. |
- static void RemoveNotifications(); |
+ // Register() stores a pointer to the given ThreadWatcher in a global map. |
+ static void Register(ThreadWatcher* watcher); |
- // This method returns number of watched threads that have responded and |
- // threads that have not responded with a pong message. |
- static void GetStatusOfThreads(int* no_of_responding_threads, |
- int* no_of_unresponding_threads); |
+ // This method returns true if the ThreadWatcher object is registerd. |
+ static bool IsRegistered(const BrowserThread::ID thread_id); |
+ // This method returns number of responsive and unresponsive watched threads. |
+ static void GetStatusOfThreads(uint32* responding_thread_count, |
+ uint32* unresponding_thread_count); |
+ |
+ // This will ensure that the watching is actively taking place, and awaken |
+ // all thread watchers that are registered. |
+ static void WakeUpAll(); |
+ |
private: |
// Allow tests to access our innards for testing purposes. |
- FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, Registration); |
+ friend class CustomThreadWatcher; |
+ friend class ThreadWatcherTest; |
+ FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, CommandLineArgs); |
- // Delete all thread watcher objects and remove them from global map. |
- // This method is accessible on WatchDogThread. |
- void DeleteAll(); |
+ // This singleton holds the global list of registered ThreadWatchers. |
+ ThreadWatcherList(); |
- // This will ensure that the watching is actively taking place. It will wakeup |
- // all thread watchers every 2 seconds. This is the implementation of |
- // NotificationObserver. When a matching notification is posted to the |
- // notification service, this method is called. |
- // This method is accessible on UI thread. |
- virtual void Observe(NotificationType type, |
- const NotificationSource& source, |
- const NotificationDetails& details); |
+ // Destructor deletes all registered ThreadWatcher instances. |
+ virtual ~ThreadWatcherList(); |
- // This will ensure that the watching is actively taking place, and awaken |
- // all thread watchers that are registered. |
- // This method is accessible on WatchDogThread. |
- virtual void WakeUpAll(); |
+ // Parses the command line to get |unresponsive_threshold| from |
+ // switches::kCrashOnHangSeconds, |crash_on_hang_thread_names| from |
+ // switches::kCrashOnHangThreads and |live_threads_threshold| from |
+ // switches::kCrashOnLive. |crash_on_hang_thread_names| is the set of watched |
+ // thread's names that are to be crashed if they are not responding. |
+ static void ParseCommandLine( |
+ const CommandLine& command_line, |
+ uint32* unresponsive_threshold, |
+ std::set<std::string>* crash_on_hang_thread_names, |
+ uint32* live_threads_threshold); |
+ // This constructs the |ThreadWatcherList| singleton and starts watching |
+ // browser threads by calling StartWatching() on each browser thread that is |
+ // watched. |
+ static void InitializeAndStartWatching( |
+ uint32 unresponsive_threshold, |
+ const std::set<std::string>& crash_on_hang_thread_names, |
+ uint32 live_threads_threshold); |
+ |
+ // This method calls ThreadWatcher::StartWatching() to perform health check on |
+ // the given |thread_id|. |
+ static void StartWatching( |
+ const BrowserThread::ID& thread_id, |
+ const std::string& thread_name, |
+ const base::TimeDelta& sleep_time, |
+ const base::TimeDelta& unresponsive_time, |
+ uint32 unresponsive_threshold, |
+ const std::set<std::string>& crash_on_hang_thread_names, |
+ uint32 live_threads_threshold); |
+ |
+ // Delete all thread watcher objects and remove them from global map. It also |
+ // deletes |g_thread_watcher_list_|. |
+ static void DeleteAll(); |
+ |
// The Find() method can be used to test to see if a given ThreadWatcher was |
// already registered, or to retrieve a pointer to it from the global map. |
static ThreadWatcher* Find(const BrowserThread::ID& thread_id); |
- // Helper function should be called only while holding lock_. |
- ThreadWatcher* PreLockedFind(const BrowserThread::ID& thread_id); |
+ // The singleton of this class and is used to keep track of information about |
+ // threads that are being watched. |
+ static ThreadWatcherList* g_thread_watcher_list_; |
- static ThreadWatcherList* global_; // The singleton of this class. |
- |
// This is the wait time between ping messages. |
static const int kSleepSeconds; |
@@ -316,19 +372,60 @@ |
// received pong message or not. |
static const int kUnresponsiveSeconds; |
- // Lock for access to registered_. |
- base::Lock lock_; |
+ // Default values for |unresponsive_threshold|. |
+ static const int kUnresponsiveCount; |
+ // Default values for |live_threads_threshold|. |
+ static const int kLiveThreadsThreshold; |
+ |
// Map of all registered watched threads, from thread_id to ThreadWatcher. |
RegistrationList registered_; |
+ DISALLOW_COPY_AND_ASSIGN(ThreadWatcherList); |
+}; |
+ |
+// This class ensures that the thread watching is actively taking place. Only |
+// one instance of this class exists. |
+class ThreadWatcherObserver : public NotificationObserver { |
+ public: |
+ // Registers |g_thread_watcher_observer_| as the Notifications observer. |
+ // |wakeup_interval| specifies how often to wake up thread watchers. This |
+ // method is accessible on UI thread. |
+ static void SetupNotifications(const base::TimeDelta& wakeup_interval); |
+ |
+ // Removes all NotificationTypes from |registrar_| and deletes |
+ // |g_thread_watcher_observer_|. This method is accessible on UI thread. |
+ static void RemoveNotifications(); |
+ |
+ private: |
+ // Constructor of |g_thread_watcher_observer_| singleton. |
+ explicit ThreadWatcherObserver(const base::TimeDelta& wakeup_interval); |
+ |
+ // Destructor of |g_thread_watcher_observer_| singleton. |
+ virtual ~ThreadWatcherObserver(); |
+ |
+ // This ensures all thread watchers are active because there is some user |
+ // activity. It will wake up all thread watchers every |wakeup_interval_| |
+ // seconds. This is the implementation of NotificationObserver. When a |
+ // matching notification is posted to the notification service, this method is |
+ // called. |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details); |
+ |
+ // The singleton of this class. |
+ static ThreadWatcherObserver* g_thread_watcher_observer_; |
+ |
// The registrar that holds NotificationTypes to be observed. |
NotificationRegistrar registrar_; |
// This is the last time when woke all thread watchers up. |
base::TimeTicks last_wakeup_time_; |
- DISALLOW_COPY_AND_ASSIGN(ThreadWatcherList); |
+ // It is the time interval between wake up calls to thread watchers. |
+ const base::TimeDelta wakeup_interval_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ThreadWatcherObserver); |
}; |
// Class for WatchDogThread and in its Init method, we start watching UI, IO, |