Index: chrome/browser/jankometer_win.cc |
diff --git a/chrome/browser/jankometer_win.cc b/chrome/browser/jankometer_win.cc |
deleted file mode 100644 |
index f449ff39095d2711f2e042bafe993374bf93b69e..0000000000000000000000000000000000000000 |
--- a/chrome/browser/jankometer_win.cc |
+++ /dev/null |
@@ -1,394 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/jankometer.h" |
- |
-#include <limits> |
- |
-#include "base/basictypes.h" |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/metrics/histogram.h" |
-#include "base/metrics/stats_counters.h" |
-#include "base/pending_task.h" |
-#include "base/strings/string_util.h" |
-#include "base/threading/thread.h" |
-#include "base/threading/watchdog.h" |
-#include "base/time/time.h" |
-#include "build/build_config.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "content/public/browser/browser_thread.h" |
- |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using content::BrowserThread; |
- |
-namespace { |
- |
-// The maximum threshold of delay of the message before considering it a delay. |
-// For a debug build, you may want to set IO delay around 500ms. |
-// For a release build, setting it around 350ms is sensible. |
-// Visit about:histograms to see what the distribution is on your system, with |
-// your build. Be sure to do some work to get interesting stats. |
-// The numbers below came from a warm start (you'll get about 5-10 alarms with |
-// a cold start), and running the page-cycler for 5 rounds. |
-#ifdef NDEBUG |
-const int kMaxUIMessageDelayMs = 350; |
-const int kMaxIOMessageDelayMs = 200; |
-#else |
-const int kMaxUIMessageDelayMs = 500; |
-const int kMaxIOMessageDelayMs = 400; |
-#endif |
- |
-// Maximum processing time (excluding queueing delay) for a message before |
-// considering it delayed. |
-const int kMaxMessageProcessingMs = 100; |
- |
-// TODO(brettw) Consider making this a pref. |
-const bool kPlaySounds = false; |
- |
-//------------------------------------------------------------------------------ |
-// Provide a special watchdog to make it easy to set the breakpoint on this |
-// class only. |
-class JankWatchdog : public base::Watchdog { |
- public: |
- JankWatchdog(const TimeDelta& duration, |
- const std::string& thread_watched_name, |
- bool enabled) |
- : Watchdog(duration, thread_watched_name, enabled), |
- thread_name_watched_(thread_watched_name), |
- alarm_count_(0) { |
- } |
- |
- virtual ~JankWatchdog() {} |
- |
- virtual void Alarm() OVERRIDE { |
- // Put break point here if you want to stop threads and look at what caused |
- // the jankiness. |
- alarm_count_++; |
- Watchdog::Alarm(); |
- } |
- |
- private: |
- std::string thread_name_watched_; |
- int alarm_count_; |
- |
- 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(); |
- |
- // Indicate if we will bother to measuer this message. |
- bool MessageWillBeMeasured(); |
- |
- static void SetDefaultMessagesToSkip(int count) { discard_count_ = count; } |
- |
- private: |
- const TimeDelta max_message_delay_; |
- |
- // Indicate if we'll bother measuring this message. |
- bool measure_current_message_; |
- |
- // Down counter which will periodically hit 0, and only then bother to measure |
- // the corresponding message. |
- int events_till_measurement_; |
- |
- // The value to re-initialize events_till_measurement_ after it reaches 0. |
- static int discard_count_; |
- |
- // 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. |
- base::StatsCounter slow_processing_counter_; // Msgs w/ long proc time. |
- base::StatsCounter queueing_delay_counter_; // Msgs w/ long queueing delay. |
- base::HistogramBase* const process_times_; // Time spent proc. task. |
- base::HistogramBase* const total_times_; // Total queueing plus proc. |
- 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), |
- measure_current_message_(true), |
- events_till_measurement_(0), |
- slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name), |
- queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name), |
- process_times_(base::Histogram::FactoryGet( |
- std::string("Chrome.ProcMsgL ") + thread_name, |
- 1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag)), |
- total_times_(base::Histogram::FactoryGet( |
- std::string("Chrome.TotalMsgL ") + thread_name, |
- 1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag)), |
- total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) { |
- if (discard_count_ > 0) { |
- // Select a vaguely random sample-start-point. |
- events_till_measurement_ = static_cast<int>( |
- (TimeTicks::Now() - TimeTicks()).InSeconds() % (discard_count_ + 1)); |
- } |
-} |
- |
-JankObserverHelper::~JankObserverHelper() {} |
- |
-// Called when a message has just begun processing, initializes |
-// per-message variables and timers. |
-void JankObserverHelper::StartProcessingTimers(const TimeDelta& queueing_time) { |
- DCHECK(measure_current_message_); |
- 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 (kPlaySounds) |
- MessageBeep(MB_ICONASTERISK); |
- } |
-} |
- |
-// Called when a message has just finished processing, finalizes |
-// per-message variables and timers. |
-void JankObserverHelper::EndProcessingTimers() { |
- if (!measure_current_message_) |
- return; |
- 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 (kPlaySounds) |
- MessageBeep(MB_ICONHAND); |
- } |
- |
- // Reset message specific times. |
- begin_process_message_ = base::TimeTicks(); |
- queueing_time_ = base::TimeDelta(); |
-} |
- |
-bool JankObserverHelper::MessageWillBeMeasured() { |
- measure_current_message_ = events_till_measurement_ <= 0; |
- if (!measure_current_message_) |
- --events_till_measurement_; |
- else |
- events_till_measurement_ = discard_count_; |
- return measure_current_message_; |
-} |
- |
-// static |
-int JankObserverHelper::discard_count_ = 99; // Measure only 1 in 100. |
- |
-//------------------------------------------------------------------------------ |
-class IOJankObserver : public base::RefCountedThreadSafe<IOJankObserver>, |
- public base::MessageLoopForIO::IOObserver, |
- public base::MessageLoop::TaskObserver { |
- public: |
- IOJankObserver(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() { |
- base::MessageLoop::current()->AddTaskObserver(this); |
- base::MessageLoopForIO::current()->AddIOObserver(this); |
- } |
- |
- // Detaches the observer to the current thread's message loop. |
- void DetachFromCurrentThread() { |
- base::MessageLoopForIO::current()->RemoveIOObserver(this); |
- base::MessageLoop::current()->RemoveTaskObserver(this); |
- } |
- |
- virtual void WillProcessIOEvent() OVERRIDE { |
- if (!helper_.MessageWillBeMeasured()) |
- return; |
- helper_.StartProcessingTimers(base::TimeDelta()); |
- } |
- |
- virtual void DidProcessIOEvent() OVERRIDE { |
- helper_.EndProcessingTimers(); |
- } |
- |
- virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
- if (!helper_.MessageWillBeMeasured()) |
- return; |
- base::TimeTicks now = base::TimeTicks::Now(); |
- const base::TimeDelta queueing_time = now - pending_task.time_posted; |
- helper_.StartProcessingTimers(queueing_time); |
- } |
- |
- virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
- helper_.EndProcessingTimers(); |
- } |
- |
- private: |
- friend class base::RefCountedThreadSafe<IOJankObserver>; |
- |
- virtual ~IOJankObserver() {} |
- |
- JankObserverHelper helper_; |
- |
- DISALLOW_COPY_AND_ASSIGN(IOJankObserver); |
-}; |
- |
-//------------------------------------------------------------------------------ |
-class UIJankObserver : public base::RefCountedThreadSafe<UIJankObserver>, |
- public base::MessageLoop::TaskObserver, |
- public base::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() { |
- DCHECK(base::MessageLoopForUI::IsCurrent()); |
- base::MessageLoopForUI::current()->AddObserver(this); |
- base::MessageLoop::current()->AddTaskObserver(this); |
- } |
- |
- // Detaches the observer to the current thread's message loop. |
- void DetachFromCurrentThread() { |
- DCHECK(base::MessageLoopForUI::IsCurrent()); |
- base::MessageLoop::current()->RemoveTaskObserver(this); |
- base::MessageLoopForUI::current()->RemoveObserver(this); |
- } |
- |
- virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
- if (!helper_.MessageWillBeMeasured()) |
- return; |
- base::TimeTicks now = base::TimeTicks::Now(); |
- const base::TimeDelta queueing_time = now - pending_task.time_posted; |
- helper_.StartProcessingTimers(queueing_time); |
- } |
- |
- virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
- helper_.EndProcessingTimers(); |
- } |
- |
- virtual void WillProcessEvent(const base::NativeEvent& event) OVERRIDE { |
- if (!helper_.MessageWillBeMeasured()) |
- return; |
- // 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, |
- // or if the original time comes from GetTickCount, it might wrap around |
- // to -1. |
- // |
- // Therefore, I cast to DWORD so if it wraps to -1 we will correct it. If |
- // it doesn't, then our time delta will be negative if a message happens |
- // to straddle the wraparound point, it will still be OK. |
- DWORD cur_message_issue_time = static_cast<DWORD>(event.time); |
- DWORD cur_time = GetTickCount(); |
- base::TimeDelta queueing_time = |
- base::TimeDelta::FromMilliseconds(cur_time - cur_message_issue_time); |
- |
- helper_.StartProcessingTimers(queueing_time); |
- } |
- |
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { |
- helper_.EndProcessingTimers(); |
- } |
- |
- private: |
- friend class base::RefCountedThreadSafe<UIJankObserver>; |
- |
- virtual ~UIJankObserver() {} |
- |
- JankObserverHelper helper_; |
- |
- DISALLOW_COPY_AND_ASSIGN(UIJankObserver); |
-}; |
- |
-// These objects are created by InstallJankometer and leaked. |
-const scoped_refptr<UIJankObserver>* ui_observer = NULL; |
-const scoped_refptr<IOJankObserver>* io_observer = NULL; |
- |
-} // namespace |
- |
-void InstallJankometer(const CommandLine& parsed_command_line) { |
- if (ui_observer || io_observer) { |
- NOTREACHED() << "Initializing jank-o-meter twice"; |
- return; |
- } |
- |
- bool ui_watchdog_enabled = false; |
- bool io_watchdog_enabled = false; |
- if (parsed_command_line.HasSwitch(switches::kEnableWatchdog)) { |
- std::string list = |
- parsed_command_line.GetSwitchValueASCII(switches::kEnableWatchdog); |
- if (list.npos != list.find("ui")) |
- ui_watchdog_enabled = true; |
- if (list.npos != list.find("io")) |
- io_watchdog_enabled = true; |
- } |
- |
- if (ui_watchdog_enabled || io_watchdog_enabled) |
- JankObserverHelper::SetDefaultMessagesToSkip(0); // Watch everything. |
- |
- // Install on the UI thread. |
- 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 scoped_refptr<IOJankObserver>( |
- new IOJankObserver( |
- "IO", |
- TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs), |
- io_watchdog_enabled)); |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind(&IOJankObserver::AttachToCurrentThread, io_observer->get())); |
-} |
- |
-void UninstallJankometer() { |
- if (ui_observer) { |
- (*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())); |
- delete io_observer; |
- io_observer = NULL; |
- } |
-} |