Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: chrome/browser/metrics/perf_provider_chromeos.cc

Issue 282093011: metrics: Use absolute interval-based perf collection (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refactor collection to allow different trigger events in the future Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string> 5 #include <string>
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/compiler_specific.h" 11 #include "base/compiler_specific.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/rand_util.h" 13 #include "base/rand_util.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/sequenced_worker_pool.h" 15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/metrics/perf_provider_chromeos.h" 16 #include "chrome/browser/metrics/perf_provider_chromeos.h"
17 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_list.h" 19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/browser_list_observer.h" 20 #include "chrome/browser/ui/browser_list_observer.h"
21 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/chrome_switches.h"
22 #include "chromeos/dbus/dbus_thread_manager.h" 22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/debug_daemon_client.h" 23 #include "chromeos/dbus/debug_daemon_client.h"
24 24
25 namespace { 25 namespace {
26 26
27 // Default time in seconds between invocations of perf. 27 // Partition time since the epoch into successive intervals of this size. In
28 // This period is roughly 6.5 hours. 28 // each interval that hasn't passed, pick a random time to collect a profile.
29 // This is chosen to be relatively prime with the number of seconds in: 29 // This interval is twenty-four hours.
Ilya Sherman 2014/05/29 22:56:49 nit: Please update this comment.
Simon Que 2014/05/30 01:21:45 Done.
30 // - one minute (60) 30 const size_t kPerfProfilingIntervalMs = 24 * 60 * 60 * 1000;
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 31
48 // Default time in seconds perf is run for. 32 // Default time in seconds perf is run for.
49 const size_t kPerfCommandDurationDefaultSeconds = 2; 33 const size_t kPerfCommandDurationDefaultSeconds = 2;
50 34
51 // Limit the total size of protobufs that can be cached, so they don't take up 35 // 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 36 // too much memory. If the size of cached protobufs exceeds this value, stop
53 // collecting further perf data. The current value is 4 MB. 37 // collecting further perf data. The current value is 4 MB.
54 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; 38 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024;
55 39
56 // Enumeration representing success and various failure modes for collecting and 40 // Enumeration representing success and various failure modes for collecting and
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 virtual void OnBrowserAdded(Browser* browser) OVERRIDE { 96 virtual void OnBrowserAdded(Browser* browser) OVERRIDE {
113 if (browser->profile()->IsOffTheRecord()) 97 if (browser->profile()->IsOffTheRecord())
114 incognito_launched_ = true; 98 incognito_launched_ = true;
115 } 99 }
116 100
117 bool incognito_launched_; 101 bool incognito_launched_;
118 }; 102 };
119 103
120 PerfProvider::PerfProvider() 104 PerfProvider::PerfProvider()
121 : login_observer_(this), 105 : login_observer_(this),
106 next_profiling_interval_start_(base::TimeTicks::Now()),
122 weak_factory_(this) { 107 weak_factory_(this) {
123 // Register the login observer with LoginState. 108 // Register the login observer with LoginState.
124 chromeos::LoginState::Get()->AddObserver(&login_observer_); 109 chromeos::LoginState::Get()->AddObserver(&login_observer_);
125 110
126 // Check the login state. At the time of writing, this class is instantiated 111 // Check the login state. At the time of writing, this class is instantiated
127 // before login. A subsequent login would activate the profiling. However, 112 // before login. A subsequent login would activate the profiling. However,
128 // that behavior may change in the future so that the user is already logged 113 // that behavior may change in the future so that the user is already logged
129 // when this class is instantiated. By calling LoggedInStateChanged() here, 114 // when this class is instantiated. By calling LoggedInStateChanged() here,
130 // PerfProvider will recognize that the system is already logged in. 115 // PerfProvider will recognize that the system is already logged in.
131 login_observer_.LoggedInStateChanged(); 116 login_observer_.LoggedInStateChanged();
132 } 117 }
133 118
134 PerfProvider::~PerfProvider() { 119 PerfProvider::~PerfProvider() {
135 chromeos::LoginState::Get()->RemoveObserver(&login_observer_); 120 chromeos::LoginState::Get()->RemoveObserver(&login_observer_);
136 } 121 }
137 122
138 bool PerfProvider::GetPerfData(std::vector<PerfDataProto>* perf_data) { 123 bool PerfProvider::GetPerfData(std::vector<SampledProfile>* perf_data) {
139 DCHECK(CalledOnValidThread()); 124 DCHECK(CalledOnValidThread());
140 if (cached_perf_data_.empty()) { 125 if (cached_perf_data_.empty()) {
141 AddToPerfHistogram(NOT_READY_TO_UPLOAD); 126 AddToPerfHistogram(NOT_READY_TO_UPLOAD);
142 return false; 127 return false;
143 } 128 }
144 129
145 perf_data->swap(cached_perf_data_); 130 perf_data->swap(cached_perf_data_);
146 cached_perf_data_.clear(); 131 cached_perf_data_.clear();
147 132
148 AddToPerfHistogram(SUCCESS); 133 AddToPerfHistogram(SUCCESS);
149 return true; 134 return true;
150 } 135 }
151 136
152 PerfProvider::LoginObserver::LoginObserver(PerfProvider* perf_provider) 137 PerfProvider::LoginObserver::LoginObserver(PerfProvider* perf_provider)
153 : perf_provider_(perf_provider) {} 138 : perf_provider_(perf_provider) {}
154 139
155 void PerfProvider::LoginObserver::LoggedInStateChanged() { 140 void PerfProvider::LoginObserver::LoggedInStateChanged() {
156 if (IsNormalUserLoggedIn()) 141 if (IsNormalUserLoggedIn())
157 perf_provider_->Activate(); 142 perf_provider_->Activate();
158 else 143 else
159 perf_provider_->Deactivate(); 144 perf_provider_->Deactivate();
160 } 145 }
161 146
162 void PerfProvider::Activate() { 147 void PerfProvider::Activate() {
Ilya Sherman 2014/05/29 22:56:49 nit: It might be wise to rename this method to som
Simon Que 2014/05/30 01:21:45 Done.
163 size_t collection_interval_minutes = base::RandInt( 148 login_time_ = base::TimeTicks::Now();
164 kPerfCommandStartIntervalLowerBoundMinutes, 149 ScheduleCollection();
165 kPerfCommandStartIntervalUpperBoundMinutes);
166 ScheduleCollection(base::TimeDelta::FromMinutes(collection_interval_minutes));
167 } 150 }
168 151
169 void PerfProvider::Deactivate() { 152 void PerfProvider::Deactivate() {
170 // Stop the timer, but leave |cached_perf_data_| intact. 153 // Stop the timer, but leave |cached_perf_data_| intact.
171 timer_.Stop(); 154 timer_.Stop();
172 } 155 }
173 156
174 void PerfProvider::ScheduleCollection(const base::TimeDelta& interval) { 157 void PerfProvider::ScheduleCollection() {
175 DCHECK(CalledOnValidThread()); 158 DCHECK(CalledOnValidThread());
176 if (timer_.IsRunning()) 159 if (timer_.IsRunning())
177 return; 160 return;
178 161
179 timer_.Start(FROM_HERE, interval, this, 162 // Pick a random time in the current interval.
180 &PerfProvider::CollectIfNecessaryAndReschedule); 163 base::TimeTicks scheduled_time =
164 next_profiling_interval_start_ +
165 base::TimeDelta::FromMilliseconds(
166 base::RandGenerator(kPerfProfilingIntervalMs));
167
168 // If the scheduled time has already passed in the time it took to make the
169 // above calculations, trigger the collection event immediately.
170 base::TimeTicks now = base::TimeTicks::Now();
171 if (scheduled_time < now) {
172 scheduled_time = now;
173 }
Ilya Sherman 2014/05/29 22:56:49 nit: No need for curly braces.
Simon Que 2014/05/30 01:21:45 Done.
174 timer_.Start(FROM_HERE, scheduled_time - now, this,
175 &PerfProvider::DoPeriodicCollection);
181 } 176 }
182 177
183 void PerfProvider::CollectIfNecessary() { 178 void PerfProvider::CollectIfNecessary(
179 SampledProfile::TriggerEvent trigger_event) {
184 DCHECK(CalledOnValidThread()); 180 DCHECK(CalledOnValidThread());
185 181
186 // Do not collect further data if we've already collected a substantial amount 182 // Do not collect further data if we've already collected a substantial amount
187 // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|. 183 // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|.
188 size_t cached_perf_data_size = 0; 184 size_t cached_perf_data_size = 0;
189 for (size_t i = 0; i < cached_perf_data_.size(); ++i) { 185 for (size_t i = 0; i < cached_perf_data_.size(); ++i) {
190 cached_perf_data_size += cached_perf_data_[i].ByteSize(); 186 cached_perf_data_size += cached_perf_data_[i].ByteSize();
191 } 187 }
192 if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) { 188 if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) {
193 AddToPerfHistogram(NOT_READY_TO_COLLECT); 189 AddToPerfHistogram(NOT_READY_TO_COLLECT);
(...skipping 12 matching lines...) Expand all
206 202
207 chromeos::DebugDaemonClient* client = 203 chromeos::DebugDaemonClient* client =
208 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); 204 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
209 205
210 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( 206 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds(
211 kPerfCommandDurationDefaultSeconds); 207 kPerfCommandDurationDefaultSeconds);
212 208
213 client->GetPerfData(collection_duration.InSeconds(), 209 client->GetPerfData(collection_duration.InSeconds(),
214 base::Bind(&PerfProvider::ParseProtoIfValid, 210 base::Bind(&PerfProvider::ParseProtoIfValid,
215 weak_factory_.GetWeakPtr(), 211 weak_factory_.GetWeakPtr(),
216 base::Passed(&incognito_observer))); 212 base::Passed(&incognito_observer),
213 trigger_event));
217 } 214 }
218 215
219 void PerfProvider::CollectIfNecessaryAndReschedule() { 216 void PerfProvider::DoPeriodicCollection() {
220 CollectIfNecessary(); 217 CollectIfNecessary(SampledProfile::PERIODIC_COLLECTION);
221 ScheduleCollection( 218
222 base::TimeDelta::FromSeconds(kPerfCommandIntervalDefaultSeconds)); 219 // Update the profiling interval tracker to the start of the next interval.
220 next_profiling_interval_start_ +=
221 base::TimeDelta::FromMilliseconds(kPerfProfilingIntervalMs);
Ilya Sherman 2014/05/29 22:56:49 nit: I think it would be slightly better to reset
Simon Que 2014/05/30 01:21:45 Done.
222 ScheduleCollection();
223 } 223 }
224 224
225 void PerfProvider::ParseProtoIfValid( 225 void PerfProvider::ParseProtoIfValid(
226 scoped_ptr<WindowedIncognitoObserver> incognito_observer, 226 scoped_ptr<WindowedIncognitoObserver> incognito_observer,
227 SampledProfile::TriggerEvent trigger_event,
227 const std::vector<uint8>& data) { 228 const std::vector<uint8>& data) {
228 DCHECK(CalledOnValidThread()); 229 DCHECK(CalledOnValidThread());
229 230
230 if (incognito_observer->incognito_launched()) { 231 if (incognito_observer->incognito_launched()) {
231 AddToPerfHistogram(INCOGNITO_LAUNCHED); 232 AddToPerfHistogram(INCOGNITO_LAUNCHED);
232 return; 233 return;
233 } 234 }
234 235
235 PerfDataProto perf_data_proto; 236 PerfDataProto perf_data_proto;
236 if (!perf_data_proto.ParseFromArray(data.data(), data.size())) { 237 if (!perf_data_proto.ParseFromArray(data.data(), data.size())) {
237 AddToPerfHistogram(PROTOBUF_NOT_PARSED); 238 AddToPerfHistogram(PROTOBUF_NOT_PARSED);
238 return; 239 return;
239 } 240 }
240 241
241 // Append a new PerfDataProto to the |cached_perf_data_| vector and swap in 242 // Populate a profile collection protobuf with the collected perf data and
242 // the contents. 243 // extra metadata.
243 cached_perf_data_.resize(cached_perf_data_.size() + 1); 244 cached_perf_data_.resize(cached_perf_data_.size() + 1);
244 cached_perf_data_.back().Swap(&perf_data_proto); 245 SampledProfile& collection_data = cached_perf_data_.back();
246 collection_data.set_trigger_event(trigger_event);
247 collection_data.set_ms_after_boot(perf_data_proto.timestamp_sec());
Ilya Sherman 2014/05/29 22:56:49 You are still assigning seconds to a millisecond f
Simon Que 2014/05/30 01:21:45 Done.
248 collection_data.
249 set_ms_after_login((base::TimeTicks::Now() - login_time_)
Ilya Sherman 2014/05/29 22:56:49 nit: Please add a DCHECK that login_time_ is non-n
Simon Que 2014/05/30 01:21:45 Done.
250 .InMilliseconds());
251 *collection_data.mutable_perf_data() = perf_data_proto;
245 } 252 }
246 253
247 } // namespace metrics 254 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698