Index: chrome/browser/jankometer.cc |
diff --git a/chrome/browser/jankometer.cc b/chrome/browser/jankometer.cc |
index e8256f6969957e9b18dc8e2058bcf7e160d64d79..0db9b95bdf7c1350026422affca2255268ac6f02 100644 |
--- a/chrome/browser/jankometer.cc |
+++ b/chrome/browser/jankometer.cc |
@@ -81,80 +81,187 @@ class JankWatchdog : public Watchdog { |
DISALLOW_COPY_AND_ASSIGN(JankWatchdog); |
}; |
+class JankObserverHelper { |
+ public: |
+ JankObserverHelper(const std::string& thread_name, |
+ const TimeDelta& excessive_duration, |
+ bool watchdog_enable); |
+ ~JankObserverHelper(); |
+ |
+ void StartProcessingTimers(const TimeDelta& queueing_time); |
+ void EndProcessingTimers(); |
+ |
+ private: |
+ const TimeDelta max_message_delay_; |
+ |
+ // Time at which the current message processing began. |
+ TimeTicks begin_process_message_; |
+ |
+ // Time the current message spent in the queue -- delta between message |
+ // construction time and message processing time. |
+ TimeDelta queueing_time_; |
+ |
+ // Counters for the two types of jank we measure. |
+ StatsCounter slow_processing_counter_; // Messages with long processing time. |
+ StatsCounter queueing_delay_counter_; // Messages with long queueing delay. |
+ scoped_refptr<Histogram> process_times_; // Time spent processing task. |
+ scoped_refptr<Histogram> total_times_; // Total queueing plus processing. |
+ JankWatchdog total_time_watchdog_; // Watching for excessive total_time. |
+ |
+ DISALLOW_COPY_AND_ASSIGN(JankObserverHelper); |
+}; |
+ |
+JankObserverHelper::JankObserverHelper( |
+ const std::string& thread_name, |
+ const TimeDelta& excessive_duration, |
+ bool watchdog_enable) |
+ : max_message_delay_(excessive_duration), |
+ slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name), |
+ queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name), |
+ total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) { |
+ process_times_ = Histogram::FactoryGet( |
+ std::string("Chrome.ProcMsgL ") + thread_name, |
+ 1, 3600000, 50, Histogram::kUmaTargetedHistogramFlag); |
+ total_times_ = Histogram::FactoryGet( |
+ std::string("Chrome.TotalMsgL ") + thread_name, |
+ 1, 3600000, 50, Histogram::kUmaTargetedHistogramFlag); |
+} |
+ |
+JankObserverHelper::~JankObserverHelper() {} |
+ |
+// Called when a message has just begun processing, initializes |
+// per-message variables and timers. |
+void JankObserverHelper::StartProcessingTimers(const TimeDelta& queueing_time) { |
+ begin_process_message_ = TimeTicks::Now(); |
+ queueing_time_ = queueing_time; |
+ |
+ // Simulate arming when the message entered the queue. |
+ total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_); |
+ if (queueing_time_ > max_message_delay_) { |
+ // Message is too delayed. |
+ queueing_delay_counter_.Increment(); |
+#if defined(OS_WIN) |
+ if (kPlaySounds) |
+ MessageBeep(MB_ICONASTERISK); |
+#endif |
+ } |
+} |
+ |
+// Called when a message has just finished processing, finalizes |
+// per-message variables and timers. |
+void JankObserverHelper::EndProcessingTimers() { |
+ total_time_watchdog_.Disarm(); |
+ TimeTicks now = TimeTicks::Now(); |
+ if (begin_process_message_ != TimeTicks()) { |
+ TimeDelta processing_time = now - begin_process_message_; |
+ process_times_->AddTime(processing_time); |
+ total_times_->AddTime(queueing_time_ + processing_time); |
+ } |
+ if (now - begin_process_message_ > |
+ TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) { |
+ // Message took too long to process. |
+ slow_processing_counter_.Increment(); |
+#if defined(OS_WIN) |
+ if (kPlaySounds) |
+ MessageBeep(MB_ICONHAND); |
+#endif |
+ } |
+ |
+ // Reset message specific times. |
+ begin_process_message_ = base::TimeTicks(); |
+ queueing_time_ = base::TimeDelta(); |
+} |
+ |
//------------------------------------------------------------------------------ |
-class JankObserver : public base::RefCountedThreadSafe<JankObserver>, |
- public MessageLoopForUI::Observer { |
+class IOJankObserver : public base::RefCountedThreadSafe<IOJankObserver>, |
+ public MessageLoopForIO::IOObserver, |
+ public MessageLoop::TaskObserver { |
public: |
- JankObserver(const char* thread_name, |
- const TimeDelta& excessive_duration, |
- bool watchdog_enable) |
- : MaxMessageDelay_(excessive_duration), |
- slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name), |
- queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name), |
- total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) { |
- process_times_ = Histogram::FactoryGet( |
- std::string("Chrome.ProcMsgL ") + thread_name, |
- 1, 3600000, 50, Histogram::kUmaTargetedHistogramFlag); |
- total_times_ = Histogram::FactoryGet( |
- std::string("Chrome.TotalMsgL ") + thread_name, |
- 1, 3600000, 50, Histogram::kUmaTargetedHistogramFlag); |
+ IOJankObserver(const char* thread_name, |
+ TimeDelta excessive_duration, |
+ bool watchdog_enable) |
+ : helper_(thread_name, excessive_duration, watchdog_enable) {} |
+ |
+ ~IOJankObserver() {} |
+ |
+ // Attaches the observer to the current thread's message loop. You can only |
+ // attach to the current thread, so this function can be invoked on another |
+ // thread to attach it. |
+ void AttachToCurrentThread() { |
+ MessageLoop::current()->AddTaskObserver(this); |
+ MessageLoopForIO::current()->AddIOObserver(this); |
+ } |
+ |
+ // Detaches the observer to the current thread's message loop. |
+ void DetachFromCurrentThread() { |
+ MessageLoopForIO::current()->RemoveIOObserver(this); |
+ MessageLoop::current()->RemoveTaskObserver(this); |
} |
+ virtual void WillProcessIOEvent() { |
+ helper_.StartProcessingTimers(base::TimeDelta()); |
+ } |
+ |
+ virtual void DidProcessIOEvent() { |
+ helper_.EndProcessingTimers(); |
+ } |
+ |
+ virtual void WillProcessTask(base::TimeTicks birth_time) { |
+ base::TimeTicks now = base::TimeTicks::Now(); |
+ const base::TimeDelta queueing_time = now - birth_time; |
+ helper_.StartProcessingTimers(queueing_time); |
+ } |
+ |
+ virtual void DidProcessTask() { |
+ helper_.EndProcessingTimers(); |
+ } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<IOJankObserver>; |
+ |
+ JankObserverHelper helper_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(IOJankObserver); |
+}; |
+ |
+//------------------------------------------------------------------------------ |
+class UIJankObserver : public base::RefCountedThreadSafe<UIJankObserver>, |
+ public MessageLoop::TaskObserver, |
+ public MessageLoopForUI::Observer { |
+ public: |
+ UIJankObserver(const char* thread_name, |
+ TimeDelta excessive_duration, |
+ bool watchdog_enable) |
+ : helper_(thread_name, excessive_duration, watchdog_enable) {} |
+ |
// Attaches the observer to the current thread's message loop. You can only |
// attach to the current thread, so this function can be invoked on another |
// thread to attach it. |
void AttachToCurrentThread() { |
- // TODO(darin): support monitoring jankiness on non-UI threads! |
- if (MessageLoop::current()->type() == MessageLoop::TYPE_UI) |
- MessageLoopForUI::current()->AddObserver(this); |
+ DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
+ MessageLoopForUI::current()->AddObserver(this); |
+ MessageLoop::current()->AddTaskObserver(this); |
} |
// Detaches the observer to the current thread's message loop. |
void DetachFromCurrentThread() { |
- if (MessageLoop::current()->type() == MessageLoop::TYPE_UI) |
- MessageLoopForUI::current()->RemoveObserver(this); |
+ DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); |
+ MessageLoop::current()->RemoveTaskObserver(this); |
+ MessageLoopForUI::current()->RemoveObserver(this); |
} |
- // Called when a message has just begun processing, initializes |
- // per-message variables and timers. |
- void StartProcessingTimers() { |
- // Simulate arming when the message entered the queue. |
- total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_); |
- if (queueing_time_ > MaxMessageDelay_) { |
- // Message is too delayed. |
- queueing_delay_counter_.Increment(); |
-#if defined(OS_WIN) |
- if (kPlaySounds) |
- MessageBeep(MB_ICONASTERISK); |
-#endif |
- } |
+ virtual void WillProcessTask(base::TimeTicks birth_time) { |
+ base::TimeTicks now = base::TimeTicks::Now(); |
+ const base::TimeDelta queueing_time = now - birth_time; |
+ helper_.StartProcessingTimers(queueing_time); |
} |
- // Called when a message has just finished processing, finalizes |
- // per-message variables and timers. |
- void EndProcessingTimers() { |
- total_time_watchdog_.Disarm(); |
- TimeTicks now = TimeTicks::Now(); |
- if (begin_process_message_ != TimeTicks()) { |
- TimeDelta processing_time = now - begin_process_message_; |
- process_times_->AddTime(processing_time); |
- total_times_->AddTime(queueing_time_ + processing_time); |
- } |
- if (now - begin_process_message_ > |
- TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) { |
- // Message took too long to process. |
- slow_processing_counter_.Increment(); |
-#if defined(OS_WIN) |
- if (kPlaySounds) |
- MessageBeep(MB_ICONHAND); |
-#endif |
- } |
+ virtual void DidProcessTask() { |
+ helper_.EndProcessingTimers(); |
} |
#if defined(OS_WIN) |
virtual void WillProcessMessage(const MSG& msg) { |
- begin_process_message_ = TimeTicks::Now(); |
- |
// GetMessageTime returns a LONG (signed 32-bit) and GetTickCount returns |
// a DWORD (unsigned 32-bit). They both wrap around when the time is longer |
// than they can hold. I'm not sure if GetMessageTime wraps around to 0, |
@@ -166,58 +273,43 @@ class JankObserver : public base::RefCountedThreadSafe<JankObserver>, |
// to straddle the wraparound point, it will still be OK. |
DWORD cur_message_issue_time = static_cast<DWORD>(msg.time); |
DWORD cur_time = GetTickCount(); |
- queueing_time_ = |
+ base::TimeDelta queueing_time = |
base::TimeDelta::FromMilliseconds(cur_time - cur_message_issue_time); |
- StartProcessingTimers(); |
+ helper_.StartProcessingTimers(queueing_time); |
} |
virtual void DidProcessMessage(const MSG& msg) { |
- EndProcessingTimers(); |
+ helper_.EndProcessingTimers(); |
} |
#elif defined(TOOLKIT_USES_GTK) |
virtual void WillProcessEvent(GdkEvent* event) { |
- begin_process_message_ = TimeTicks::Now(); |
// TODO(evanm): we want to set queueing_time_ using |
// gdk_event_get_time, but how do you convert that info |
// into a delta? |
// guint event_time = gdk_event_get_time(event); |
- queueing_time_ = base::TimeDelta::FromMilliseconds(0); |
- StartProcessingTimers(); |
+ base::TimeDelta queueing_time = base::TimeDelta::FromMilliseconds(0); |
+ helper_.StartProcessingTimers(queueing_time); |
} |
virtual void DidProcessEvent(GdkEvent* event) { |
- EndProcessingTimers(); |
+ helper_.EndProcessingTimers(); |
} |
#endif |
private: |
- friend class base::RefCountedThreadSafe<JankObserver>; |
- |
- ~JankObserver() {} |
- |
- const TimeDelta MaxMessageDelay_; |
- |
- // Time at which the current message processing began. |
- TimeTicks begin_process_message_; |
+ friend class base::RefCountedThreadSafe<UIJankObserver>; |
- // Time the current message spent in the queue -- delta between message |
- // construction time and message processing time. |
- TimeDelta queueing_time_; |
+ ~UIJankObserver() {} |
- // Counters for the two types of jank we measure. |
- StatsCounter slow_processing_counter_; // Messages with long processing time. |
- StatsCounter queueing_delay_counter_; // Messages with long queueing delay. |
- scoped_refptr<Histogram> process_times_; // Time spent processing task. |
- scoped_refptr<Histogram> total_times_; // Total queueing plus processing. |
- JankWatchdog total_time_watchdog_; // Watching for excessive total_time. |
+ JankObserverHelper helper_; |
- DISALLOW_EVIL_CONSTRUCTORS(JankObserver); |
+ DISALLOW_COPY_AND_ASSIGN(UIJankObserver); |
}; |
// These objects are created by InstallJankometer and leaked. |
-JankObserver* ui_observer = NULL; |
-JankObserver* io_observer = NULL; |
+const scoped_refptr<UIJankObserver>* ui_observer = NULL; |
+const scoped_refptr<IOJankObserver>* io_observer = NULL; |
} // namespace |
@@ -239,36 +331,37 @@ void InstallJankometer(const CommandLine& parsed_command_line) { |
} |
// Install on the UI thread. |
- ui_observer = new JankObserver( |
- "UI", |
- TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs), |
- ui_watchdog_enabled); |
- ui_observer->AddRef(); |
- ui_observer->AttachToCurrentThread(); |
+ ui_observer = new scoped_refptr<UIJankObserver>( |
+ new UIJankObserver( |
+ "UI", |
+ TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs), |
+ ui_watchdog_enabled)); |
+ (*ui_observer)->AttachToCurrentThread(); |
// Now install on the I/O thread. Hiccups on that thread will block |
// interaction with web pages. We must proxy to that thread before we can |
// add our observer. |
- io_observer = new JankObserver( |
- "IO", |
- TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs), |
- io_watchdog_enabled); |
- io_observer->AddRef(); |
+ io_observer = new scoped_refptr<IOJankObserver>( |
+ new IOJankObserver( |
+ "IO", |
+ TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs), |
+ io_watchdog_enabled)); |
ChromeThread::PostTask( |
ChromeThread::IO, FROM_HERE, |
- NewRunnableMethod(io_observer, &JankObserver::AttachToCurrentThread)); |
+ NewRunnableMethod(io_observer->get(), |
+ &IOJankObserver::AttachToCurrentThread)); |
} |
void UninstallJankometer() { |
if (ui_observer) { |
- ui_observer->DetachFromCurrentThread(); |
- ui_observer->Release(); |
+ (*ui_observer)->DetachFromCurrentThread(); |
+ delete ui_observer; |
ui_observer = NULL; |
} |
if (io_observer) { |
// IO thread can't be running when we remove observers. |
DCHECK((!g_browser_process) || !(g_browser_process->io_thread())); |
- io_observer->Release(); |
+ delete io_observer; |
io_observer = NULL; |
} |
} |