1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/chromeos/swap_metrics.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <vector>
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ash/shell.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/file_util.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/files/file_path.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/metrics/histogram.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_number_conversions.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_util.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/stringprintf.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/synchronization/cancellation_flag.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/sys_info.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/threading/sequenced_worker_pool.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/browser.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/browser_list.h"
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/tabs/tab_strip_model.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/browser_thread.h"
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/base/events/event.h"
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::FilePath;
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace chromeos {
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace {
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Time delays for metrics collections, starting after an interesting UI event.
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Times are relative to the UI event. Start with zero to record the initial
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// state of the metrics immediately.
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kMetricsDelayMs[] = { 0, 100, 300, 1000, 3000 };
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch///////////////////////////////////////////////////////////////////////////////
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Runs in the blocking thread pool to load metrics and record them.
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Reads data about CPU utilization and swap activity from the /proc and /sys
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// file systems. Owned by SwapMetrics on the UI thread.
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass SwapMetrics::Backend : public base::RefCountedThreadSafe<Backend> {
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  explicit Backend(const std::string& reason);
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Records one set of statistics for |time_index| after the interesting
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // event. May trigger another delayed task to record more statistics.
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void RecordMetricsOnBlockingPool(size_t time_index);
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Sets the thread-safe cancellation flag.
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void CancelOnUIThread() { cancelled_.Set(); }
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  friend class base::RefCountedThreadSafe<Backend>;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual ~Backend();
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Extracts a field value from a list of name-value pairs
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // in a file (typically a /proc or /sys file). Returns false
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // if the field is not found, or for other errors.
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool GetFieldFromKernelOutput(const std::string& path,
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                const std::string& field,
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                int64* value);
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Reads a file whose content is a single line, and returns its content as a
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // list of tokens. |expected_tokens_count| is the expected number of tokens.
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |delimiters| is a string containing characters that may appear between
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // tokens. Returns true on success, false otherwise.
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool TokenizeOneLineFile(const std::string& path,
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           size_t expected_tokens_count,
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           const std::string& delimiters,
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                           std::vector<std::string>* tokens);
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Retrieve various system metrics. Return true on success.
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool GetMeminfoField(const std::string& field, int64* value);
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool GetUptime(double* uptime_secs, double* idle_time_secs);
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool GetPageFaults(int64* page_faults);
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Record histogram samples.
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void RecordFaultsHistogramSample(int faults,
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   const std::string& reason,
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   int swap_group,
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   int time_index);
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void RecordCpuHistogramSample(int cpu,
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                const std::string& reason,
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                int swap_group,
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                int time_index);
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Cancellation flag that can be written from the UI thread (which owns this
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // object) and read from any thread.
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::CancellationFlag cancelled_;
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Data initialized once and shared by all instances of this class.
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static bool first_time_;
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static int64 swap_total_kb_;
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static int number_of_cpus_;
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Values at the beginning of each sampling interval.
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  double last_uptime_secs_;
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  double last_idle_time_secs_;
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 last_page_faults_;
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Swap group for a set of samples, chosen at the beginning of the set.
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int swap_group_;
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Reason for sampling.
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const std::string reason_;
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(Backend);
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::first_time_ = true;
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint64 SwapMetrics::Backend::swap_total_kb_ = 0;
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint SwapMetrics::Backend::number_of_cpus_ = 0;
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSwapMetrics::Backend::Backend(const std::string& reason)
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : last_uptime_secs_(0.0),
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      last_idle_time_secs_(0.0),
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      last_page_faults_(0),
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      swap_group_(0),
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      reason_(reason) {
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSwapMetrics::Backend::~Backend() {
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::Backend::RecordMetricsOnBlockingPool(size_t time_index) {
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Another UI event might have occurred. Don't run this metrics collection
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // and don't post another task. This object's refcount will drop and it will
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // be deleted when the next backend is created on the UI thread.
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (cancelled_.IsSet())
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DVLOG(1) << "RecordMetricsInBlockingPool " << time_index;
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // At init time, get the number of cpus and the total swap. The number of cpus
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // is necessary because the idle time reported is the sum of the idle
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // times of all cpus.
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // When an event occurs:
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // - At time t_0, save the initial values for uptime, idle_time, page_faults,
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //   and swap used.
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // - At time t_i, compute cpu utilization as a fraction (1 = fully utilized):
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //  utilization =
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //      1 - (idle_time_i - idle_time_0) / (uptime_i - uptime_0) / ncpus
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // then UMA-report it in the right swap group. Do the same for page faults.
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (first_time_) {
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    first_time_ = false;
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    number_of_cpus_ = base::SysInfo::NumberOfProcessors();
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Avoid divide by zero in case of errors.
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (number_of_cpus_ == 0)
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      number_of_cpus_ = 1;
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetMeminfoField("SwapTotal:", &swap_total_kb_);
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (time_index == 0) {
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Record baseline data.
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetUptime(&last_uptime_secs_, &last_idle_time_secs_);
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetPageFaults(&last_page_faults_);
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int64 swap_free_kb = 0;
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetMeminfoField("SwapFree:", &swap_free_kb);
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int swap_percent = swap_total_kb_ > 0
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        ? (swap_total_kb_ - swap_free_kb) * 100 / swap_total_kb_
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        : 0;
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (swap_percent < 10)
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      swap_group_ = 0;
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else if (swap_percent < 30)
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      swap_group_ = 1;
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else if (swap_percent < 60)
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      swap_group_ = 2;
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      swap_group_ = 3;
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int64 page_faults = 0;
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    double idle_time_secs = 0.0;
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    double uptime_secs = 0.0;
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetUptime(&uptime_secs, &idle_time_secs);
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    GetPageFaults(&page_faults);
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    double delta_time_secs = uptime_secs - last_uptime_secs_;
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Unexpected, but not worth agonizing over it.
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (delta_time_secs == 0)
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return;
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int cpu = (1.0 - (idle_time_secs - last_idle_time_secs_) /
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               delta_time_secs / number_of_cpus_) * 100;
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int faults_per_sec = (page_faults - last_page_faults_) / delta_time_secs;
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordCpuHistogramSample(cpu, reason_, swap_group_, time_index);
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RecordFaultsHistogramSample(faults_per_sec, reason_,
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                swap_group_, time_index);
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    last_uptime_secs_ = uptime_secs;
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    last_page_faults_ = page_faults;
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    last_idle_time_secs_ = idle_time_secs;
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Check if another metrics recording is needed.
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (++time_index >= arraysize(kMetricsDelayMs))
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PostTaskRecordMetrics(
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      scoped_refptr<Backend>(this),
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      time_index,
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kMetricsDelayMs[time_index] - kMetricsDelayMs[time_index - 1]);
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::Backend::RecordFaultsHistogramSample(
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int faults,
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& reason,
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int swap_group,
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int time_index) {
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string name =
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::StringPrintf("Platform.SwapJank.%s.Faults.Swap%d.Time%d",
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         reason.c_str(),
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         swap_group,
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         time_index);
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int kMinimumBucket = 10;
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int kMaximumBucket = 200000;
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const size_t kBucketCount = 50;
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::HistogramBase* counter =
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Histogram::FactoryGet(name,
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  kMinimumBucket,
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  kMaximumBucket,
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  kBucketCount,
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  base::Histogram::kUmaTargetedHistogramFlag);
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  counter->Add(faults);
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::Backend::RecordCpuHistogramSample(int cpu,
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    const std::string& reason,
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    int swap_group,
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    int time_index) {
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string name =
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::StringPrintf("Platform.SwapJank.%s.Cpu.Swap%d.Time%d",
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         reason.c_str(),
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         swap_group,
244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                         time_index);
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int kMinimumBucket = 0;
246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int kMaximumBucket = 101;
247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const size_t kBucketCount = 102;
248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      name,
250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kMinimumBucket,
251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kMaximumBucket,
252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kBucketCount,
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Histogram::kUmaTargetedHistogramFlag);
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  counter->Add(cpu);
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Extracts a field value from a list of name-value pairs
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// in a file (typically a /proc or /sys file). Returns false
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// if the field is not found, or for other errors.
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::GetFieldFromKernelOutput(const std::string& path,
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    const std::string& field,
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                    int64* value) {
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string file_content;
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!file_util::ReadFileToString(FilePath(path), &file_content)) {
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "Cannot read " << path;
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<std::string> lines;
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t line_count = Tokenize(file_content, "\n", &lines);
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (line_count < 2) {
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "Error breaking " << path << " into lines";
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < line_count; ++i) {
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::vector<std::string> tokens;
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    size_t token_count = Tokenize(lines[i], " ", &tokens);
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (token_count < 2) {
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      LOG(WARNING) << "Unexpected line: " << lines[i];
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (tokens[0].compare(field) != 0)
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!base::StringToInt64(tokens[1], value)) {
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      LOG(WARNING) << "Cannot convert " << tokens[1] << " to int";
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  LOG(WARNING) << "could not find field " << field;
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return false;
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::TokenizeOneLineFile(const std::string& path,
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               size_t expected_tokens_count,
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               const std::string& delimiters,
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               std::vector<std::string>*
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               tokens) {
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string file_content;
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!file_util::ReadFileToString(FilePath(path), &file_content)) {
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "cannot read " << path;
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t tokens_count = Tokenize(file_content, delimiters, tokens);
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (tokens_count != expected_tokens_count) {
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "unexpected content of " << path << ": " << file_content;
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::GetMeminfoField(const std::string& name,
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                           int64* value) {
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GetFieldFromKernelOutput("/proc/meminfo", name, value);
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::GetUptime(double* uptime_secs,
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     double* idle_time_secs) {
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Get the time since boot.
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const char kUptimePath[] = "/proc/uptime";
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<std::string> tokens;
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!TokenizeOneLineFile(kUptimePath, 2, " \n", &tokens))
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!base::StringToDouble(tokens[0], uptime_secs)) {
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "cannot convert " << tokens[0] << " to double";
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Get the idle time since boot. The number available in /proc/stat is more
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // precise, but this one should be good enough.
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!base::StringToDouble(tokens[1], idle_time_secs)) {
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "cannot convert " << tokens[0] << " to double";
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SwapMetrics::Backend::GetPageFaults(int64* page_faults) {
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Get number of page faults.
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GetFieldFromKernelOutput("/proc/vmstat", "pgmajfault", page_faults);
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch///////////////////////////////////////////////////////////////////////////////
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSwapMetrics::SwapMetrics() : browser_(NULL) {
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ash::Shell::GetInstance()->AddPreTargetHandler(this);
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserList::AddObserver(this);
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSwapMetrics::~SwapMetrics() {
3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (backend_.get())
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    backend_->CancelOnUIThread();
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserList::RemoveObserver(this);
355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetBrowser(NULL);
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::OnBrowserRemoved(Browser* browser) {
359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (browser_ == browser)
360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SetBrowser(NULL);
361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::OnBrowserSetLastActive(Browser* browser) {
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (browser && browser->type() == Browser::TYPE_TABBED)
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SetBrowser(browser);
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  else
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SetBrowser(NULL);
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::ActiveTabChanged(content::WebContents* old_contents,
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   content::WebContents* new_contents,
372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   int index,
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   int reason) {
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Only measure tab switches, not tabs being replaced with new contents.
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (reason != TabStripModelObserver::CHANGE_REASON_USER_GESTURE)
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DVLOG(1) << "ActiveTabChanged";
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StartMetricsCollection("TabSwitch");
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// This exists primarily for debugging on desktop builds.
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::OnMouseEvent(ui::MouseEvent* event) {
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (event->type() != ui::ET_MOUSEWHEEL)
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DVLOG(1) << "OnMouseEvent";
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StartMetricsCollection("Scroll");
387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::OnScrollEvent(ui::ScrollEvent* event) {
390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (event->type() != ui::ET_SCROLL &&
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      event->type() != ui::ET_SCROLL_FLING_START)
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DVLOG(1) << "OnScrollEvent";
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StartMetricsCollection("Scroll");
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::PostTaskRecordMetrics(scoped_refptr<Backend> backend,
399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                        size_t time_index,
400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                        int delay_ms) {
401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Don't block shutdown on these tasks, as UMA will be disappearing.
402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_refptr<base::TaskRunner> runner =
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      content::BrowserThread::GetBlockingPool()->
404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          GetTaskRunnerWithShutdownBehavior(
405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  runner->PostDelayedTask(
407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FROM_HERE,
408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(&SwapMetrics::Backend::RecordMetricsOnBlockingPool,
409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 backend,
410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 time_index),
411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::TimeDelta::FromMilliseconds(delay_ms));
412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::StartMetricsCollection(const std::string& reason) {
415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Cancel any existing metrics run.
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (backend_.get())
417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    backend_->CancelOnUIThread();
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  backend_ = new Backend(reason);
419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PostTaskRecordMetrics(backend_, 0, kMetricsDelayMs[0]);
420eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SwapMetrics::SetBrowser(Browser* browser) {
423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (browser_ == browser)
424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (browser_)
426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    browser_->tab_strip_model()->RemoveObserver(this);
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  browser_ = browser;
428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (browser_)
429eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    browser_->tab_strip_model()->AddObserver(this);
430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace chromeos
433