Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / metrics / perf_provider_chromeos.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/metrics/histogram.h"
13 #include "base/rand_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/metrics/perf_provider_chromeos.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/browser_list_observer.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/debug_daemon_client.h"
24
25 namespace {
26
27 // Default time in seconds between invocations of perf.
28 // This period is roughly 6.5 hours.
29 // This is chosen to be relatively prime with the number of seconds in:
30 // - one minute (60)
31 // - one hour (3600)
32 // - one day (86400)
33 const size_t kPerfCommandIntervalDefaultSeconds = 23093;
34
35 // The first collection interval is different from the interval above. This is
36 // because we want to collect the first profile quickly after Chrome is started.
37 // If this period is too long, the user will log off and Chrome will be killed
38 // before it is triggered. The following 2 variables determine the upper and
39 // lower bound on the interval.
40 // The reason we do not always want to collect the initial profile after a fixed
41 // period is to not over-represent task X in the profile where task X always
42 // runs at a fixed period after start-up. By selecting a period randomly between
43 // a lower and upper bound, we will hopefully collect a more fair profile.
44 const size_t kPerfCommandStartIntervalLowerBoundMinutes = 10;
45
46 const size_t kPerfCommandStartIntervalUpperBoundMinutes = 20;
47
48 // Default time in seconds perf is run for.
49 const size_t kPerfCommandDurationDefaultSeconds = 2;
50
51 // Limit the total size of protobufs that can be cached, so they don't take up
52 // too much memory. If the size of cached protobufs exceeds this value, stop
53 // collecting further perf data. The current value is 4 MB.
54 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024;
55
56 // Enumeration representing success and various failure modes for collecting and
57 // sending perf data.
58 enum GetPerfDataOutcome {
59   SUCCESS,
60   NOT_READY_TO_UPLOAD,
61   NOT_READY_TO_COLLECT,
62   INCOGNITO_ACTIVE,
63   INCOGNITO_LAUNCHED,
64   PROTOBUF_NOT_PARSED,
65   NUM_OUTCOMES
66 };
67
68 // Name of the histogram that represents the success and various failure modes
69 // for collecting and sending perf data.
70 const char kGetPerfDataOutcomeHistogram[] = "UMA.Perf.GetData";
71
72 void AddToPerfHistogram(GetPerfDataOutcome outcome) {
73   UMA_HISTOGRAM_ENUMERATION(kGetPerfDataOutcomeHistogram,
74                             outcome,
75                             NUM_OUTCOMES);
76 }
77
78 }  // namespace
79
80
81 namespace metrics {
82
83 // This class must be created and used on the UI thread. It watches for any
84 // incognito window being opened from the time it is instantiated to the time it
85 // is destroyed.
86 class WindowedIncognitoObserver : public chrome::BrowserListObserver {
87  public:
88   WindowedIncognitoObserver() : incognito_launched_(false) {
89     BrowserList::AddObserver(this);
90   }
91
92   virtual ~WindowedIncognitoObserver() {
93     BrowserList::RemoveObserver(this);
94   }
95
96   // This method can be checked to see whether any incognito window has been
97   // opened since the time this object was created.
98   bool incognito_launched() {
99     return incognito_launched_;
100   }
101
102  private:
103   // chrome::BrowserListObserver implementation.
104   virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
105     if (browser->profile()->IsOffTheRecord())
106       incognito_launched_ = true;
107   }
108
109   bool incognito_launched_;
110 };
111
112 PerfProvider::PerfProvider()
113       : weak_factory_(this) {
114   size_t collection_interval_minutes = base::RandInt(
115       kPerfCommandStartIntervalLowerBoundMinutes,
116       kPerfCommandStartIntervalUpperBoundMinutes);
117   ScheduleCollection(base::TimeDelta::FromMinutes(collection_interval_minutes));
118 }
119
120 PerfProvider::~PerfProvider() {}
121
122 bool PerfProvider::GetPerfData(std::vector<PerfDataProto>* perf_data) {
123   DCHECK(CalledOnValidThread());
124   if (cached_perf_data_.empty()) {
125     AddToPerfHistogram(NOT_READY_TO_UPLOAD);
126     return false;
127   }
128
129   perf_data->swap(cached_perf_data_);
130   cached_perf_data_.clear();
131
132   AddToPerfHistogram(SUCCESS);
133   return true;
134 }
135
136 void PerfProvider::ScheduleCollection(const base::TimeDelta& interval) {
137   DCHECK(CalledOnValidThread());
138   if (timer_.IsRunning())
139     return;
140
141   timer_.Start(FROM_HERE, interval, this,
142                &PerfProvider::CollectIfNecessaryAndReschedule);
143 }
144
145 void PerfProvider::CollectIfNecessary() {
146   DCHECK(CalledOnValidThread());
147
148   // Do not collect further data if we've already collected a substantial amount
149   // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|.
150   size_t cached_perf_data_size = 0;
151   for (size_t i = 0; i < cached_perf_data_.size(); ++i) {
152     cached_perf_data_size += cached_perf_data_[i].ByteSize();
153   }
154   if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) {
155     AddToPerfHistogram(NOT_READY_TO_COLLECT);
156     return;
157   }
158
159   // For privacy reasons, Chrome should only collect perf data if there is no
160   // incognito session active (or gets spawned during the collection).
161   if (BrowserList::IsOffTheRecordSessionActive()) {
162     AddToPerfHistogram(INCOGNITO_ACTIVE);
163     return;
164   }
165
166   scoped_ptr<WindowedIncognitoObserver> incognito_observer(
167       new WindowedIncognitoObserver);
168
169   chromeos::DebugDaemonClient* client =
170       chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
171
172   base::TimeDelta collection_duration = base::TimeDelta::FromSeconds(
173       kPerfCommandDurationDefaultSeconds);
174
175   client->GetPerfData(collection_duration.InSeconds(),
176                       base::Bind(&PerfProvider::ParseProtoIfValid,
177                                  weak_factory_.GetWeakPtr(),
178                                  base::Passed(&incognito_observer)));
179 }
180
181 void PerfProvider::CollectIfNecessaryAndReschedule() {
182   CollectIfNecessary();
183   ScheduleCollection(
184       base::TimeDelta::FromSeconds(kPerfCommandIntervalDefaultSeconds));
185 }
186
187 void PerfProvider::ParseProtoIfValid(
188     scoped_ptr<WindowedIncognitoObserver> incognito_observer,
189     const std::vector<uint8>& data) {
190   DCHECK(CalledOnValidThread());
191
192   if (incognito_observer->incognito_launched()) {
193     AddToPerfHistogram(INCOGNITO_LAUNCHED);
194     return;
195   }
196
197   PerfDataProto perf_data_proto;
198   if (!perf_data_proto.ParseFromArray(data.data(), data.size())) {
199     AddToPerfHistogram(PROTOBUF_NOT_PARSED);
200     return;
201   }
202
203   // Append a new PerfDataProto to the |cached_perf_data_| vector and swap in
204   // the contents.
205   cached_perf_data_.resize(cached_perf_data_.size() + 1);
206   cached_perf_data_.back().Swap(&perf_data_proto);
207 }
208
209 }  // namespace metrics