| 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;
|
| - }
|
| -}
|
|
|