OLD | NEW |
---|---|
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 "chrome/browser/metrics/perf/perf_provider_chromeos.h" | 5 #include "chrome/browser/metrics/perf/perf_provider_chromeos.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | |
8 #include <string> | 9 #include <string> |
9 | 10 |
10 #include "base/bind.h" | 11 #include "base/bind.h" |
11 #include "base/callback.h" | 12 #include "base/callback.h" |
12 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/metrics/field_trial.h" | |
13 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
14 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
17 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/string_split.h" | 18 #include "base/strings/string_split.h" |
16 #include "base/threading/sequenced_worker_pool.h" | 19 #include "base/threading/sequenced_worker_pool.h" |
17 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h" | 20 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h" |
18 #include "chrome/browser/ui/browser_list.h" | 21 #include "chrome/browser/ui/browser_list.h" |
19 #include "chromeos/dbus/dbus_thread_manager.h" | 22 #include "chromeos/dbus/dbus_thread_manager.h" |
20 #include "chromeos/dbus/debug_daemon_client.h" | 23 #include "chromeos/dbus/debug_daemon_client.h" |
24 #include "components/variations/variations_associated_data.h" | |
21 | 25 |
22 namespace metrics { | 26 namespace metrics { |
23 | 27 |
24 namespace { | 28 namespace { |
25 | 29 |
30 const char kCWPFieldTrialName[] = "ChromeOSWideProfilingCollection"; | |
31 | |
26 // Limit the total size of protobufs that can be cached, so they don't take up | 32 // Limit the total size of protobufs that can be cached, so they don't take up |
27 // too much memory. If the size of cached protobufs exceeds this value, stop | 33 // too much memory. If the size of cached protobufs exceeds this value, stop |
28 // collecting further perf data. The current value is 4 MB. | 34 // collecting further perf data. The current value is 4 MB. |
29 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; | 35 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; |
30 | 36 |
31 // This is used to space out session restore collections in the face of several | 37 // This is used to space out session restore collections in the face of several |
32 // notifications in a short period of time. There should be no less than this | 38 // notifications in a short period of time. There should be no less than this |
33 // much time between collections. | 39 // much time between collections. |
34 const int kMinIntervalBetweenSessionRestoreCollectionsInSec = 30; | 40 const int kMinIntervalBetweenSessionRestoreCollectionsInSec = 30; |
35 | 41 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 /* max_collection_delay = */ base::TimeDelta::FromSeconds(5)), | 183 /* max_collection_delay = */ base::TimeDelta::FromSeconds(5)), |
178 /* restore_session = */ PerfProvider::CollectionParams::TriggerParams( | 184 /* restore_session = */ PerfProvider::CollectionParams::TriggerParams( |
179 /* sampling_factor = */ 10, | 185 /* sampling_factor = */ 10, |
180 /* max_collection_delay = */ base::TimeDelta::FromSeconds(10))); | 186 /* max_collection_delay = */ base::TimeDelta::FromSeconds(10))); |
181 | 187 |
182 PerfProvider::PerfProvider() | 188 PerfProvider::PerfProvider() |
183 : collection_params_(kDefaultParameters), | 189 : collection_params_(kDefaultParameters), |
184 login_observer_(this), | 190 login_observer_(this), |
185 next_profiling_interval_start_(base::TimeTicks::Now()), | 191 next_profiling_interval_start_(base::TimeTicks::Now()), |
186 weak_factory_(this) { | 192 weak_factory_(this) { |
187 command_selector_.SetOdds( | 193 CHECK(command_selector_.SetOdds( |
188 internal::GetDefaultCommandsForCpu(GetCPUIdentity())), | 194 internal::GetDefaultCommandsForCpu(GetCPUIdentity()))); |
195 std::map<std::string, std::string> params; | |
196 if (variations::GetVariationParams(kCWPFieldTrialName, ¶ms)) | |
197 SetCollectionParamsFromVariationParams(params); | |
189 | 198 |
190 // Register the login observer with LoginState. | 199 // Register the login observer with LoginState. |
191 chromeos::LoginState::Get()->AddObserver(&login_observer_); | 200 chromeos::LoginState::Get()->AddObserver(&login_observer_); |
192 | 201 |
193 // Register as an observer of power manager events. | 202 // Register as an observer of power manager events. |
194 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | 203 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> |
195 AddObserver(this); | 204 AddObserver(this); |
196 | 205 |
197 // Register as an observer of session restore. | 206 // Register as an observer of session restore. |
198 on_session_restored_callback_subscription_ = | 207 on_session_restored_callback_subscription_ = |
199 SessionRestore::RegisterOnSessionRestoredCallback( | 208 SessionRestore::RegisterOnSessionRestoredCallback( |
200 base::Bind(&PerfProvider::OnSessionRestoreDone, | 209 base::Bind(&PerfProvider::OnSessionRestoreDone, |
201 weak_factory_.GetWeakPtr())); | 210 weak_factory_.GetWeakPtr())); |
202 | 211 |
203 // Check the login state. At the time of writing, this class is instantiated | 212 // Check the login state. At the time of writing, this class is instantiated |
204 // before login. A subsequent login would activate the profiling. However, | 213 // before login. A subsequent login would activate the profiling. However, |
205 // that behavior may change in the future so that the user is already logged | 214 // that behavior may change in the future so that the user is already logged |
206 // when this class is instantiated. By calling LoggedInStateChanged() here, | 215 // when this class is instantiated. By calling LoggedInStateChanged() here, |
207 // PerfProvider will recognize that the system is already logged in. | 216 // PerfProvider will recognize that the system is already logged in. |
208 login_observer_.LoggedInStateChanged(); | 217 login_observer_.LoggedInStateChanged(); |
209 } | 218 } |
210 | 219 |
211 PerfProvider::~PerfProvider() { | 220 PerfProvider::~PerfProvider() { |
212 chromeos::LoginState::Get()->RemoveObserver(&login_observer_); | 221 chromeos::LoginState::Get()->RemoveObserver(&login_observer_); |
213 } | 222 } |
214 | 223 |
224 namespace { | |
225 | |
226 bool GetInt64Param(const std::map<std::string, std::string>& params, | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: Add a short comment.
dhsharp
2015/10/21 02:17:02
Done.
| |
227 const std::string& key, int64* out) { | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: I'd prefer the last param be on a separate li
dhsharp
2015/10/21 02:17:02
Done.
| |
228 auto it = params.find(key); | |
229 if (it == params.end()) | |
230 return false; | |
231 int64 value; | |
232 // NB: StringToInt64 will set value even if the conversion fails. | |
233 if (!base::StringToInt64(it->second, &value)) | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: How about this more concise form:
if (it ==
dhsharp
2015/10/21 02:17:02
I don't like to combine unrelated conditions. In t
| |
234 return false; | |
235 *out = value; | |
236 return true; | |
237 } | |
238 | |
239 // Parse the key. e.g.: "PerfCommand::arm::0" returns "arm" | |
240 bool ExtractPerfCommandCpuSpecifier(const std::string& key, | |
241 std::string* cpu_specifier) { | |
242 std::vector<std::string> tokens; | |
243 base::SplitStringUsingSubstr(key, "::", &tokens); | |
244 if (tokens.size() != 3) | |
245 return false; | |
246 if (tokens[0] != "PerfCommand") | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: Ditto, combine the ifs.
dhsharp
2015/10/21 02:17:03
I don't like how the code reads. I think it minimi
| |
247 return false; | |
248 *cpu_specifier = tokens[1]; | |
249 // tokens[2] is just a unique string (usually an index). | |
250 return true; | |
251 } | |
252 | |
253 } // namespace | |
254 | |
255 namespace internal { | |
256 | |
257 std::string FindBestCpuSpecifierFromParams( | |
258 const std::map<std::string, std::string>& params, | |
259 const CPUIdentity& cpuid) { | |
260 std::string ret; | |
261 // The CPU specified in the variation params could be "default", a system | |
262 // architecture, a CPU microarchitecture, or a CPU model substring. We should | |
263 // prefer to match the most specific. | |
264 enum MatchSpecificity { | |
265 NO_MATCH, | |
266 DEFAULT, | |
267 SYSTEM_ARCH, | |
268 CPU_UARCH, | |
269 CPU_MODEL, | |
270 }; | |
271 MatchSpecificity match_level = NO_MATCH; | |
272 | |
273 const std::string intel_uarch = GetIntelUarch(cpuid); | |
274 const std::string simplified_cpu_model = | |
275 SimplifyCPUModelName(cpuid.model_name); | |
276 | |
277 for (const auto& key_val : params) { | |
278 const std::string& key = key_val.first; | |
279 | |
280 std::string cpu_specifier; | |
281 if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) | |
282 continue; | |
283 | |
284 if (match_level < DEFAULT && cpu_specifier == "default") { | |
285 match_level = DEFAULT; | |
286 ret = cpu_specifier; | |
287 } | |
288 if (match_level < SYSTEM_ARCH && cpu_specifier == cpuid.arch) { | |
289 match_level = SYSTEM_ARCH; | |
290 ret = cpu_specifier; | |
291 } | |
292 if (match_level < CPU_UARCH && | |
293 intel_uarch != "" && cpu_specifier == intel_uarch) { | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: !intel_uarch.empty()
dhsharp
2015/10/21 02:17:03
Done.
| |
294 match_level = CPU_UARCH; | |
295 ret = cpu_specifier; | |
296 } | |
297 if (match_level < CPU_MODEL && | |
298 simplified_cpu_model.find(cpu_specifier) != std::string::npos) { | |
299 match_level = CPU_MODEL; | |
300 ret = cpu_specifier; | |
301 } | |
302 } | |
303 return ret; | |
304 } | |
305 | |
306 } // namespace internal | |
307 | |
308 void PerfProvider::SetCollectionParamsFromVariationParams( | |
309 const std::map<std::string, std::string>& params) { | |
310 int64 value; | |
311 if (GetInt64Param(params, "ProfileCollectionDurationSec", &value)) { | |
312 collection_params_.set_collection_duration( | |
313 base::TimeDelta::FromSeconds(value)); | |
314 } | |
315 if (GetInt64Param(params, "PeriodicProfilingIntervalMs", &value)) { | |
316 collection_params_.set_periodic_interval( | |
317 base::TimeDelta::FromMilliseconds(value)); | |
318 } | |
319 if (GetInt64Param(params, "ResumeFromSuspend::SamplingFactor", &value)) { | |
320 collection_params_.mutable_resume_from_suspend() | |
321 ->set_sampling_factor(value); | |
322 } | |
323 if (GetInt64Param(params, "ResumeFromSuspend::MaxDelaySec", &value)) { | |
324 collection_params_.mutable_resume_from_suspend()->set_max_collection_delay( | |
325 base::TimeDelta::FromSeconds(value)); | |
326 } | |
327 if (GetInt64Param(params, "RestoreSession::SamplingFactor", &value)) { | |
328 collection_params_.mutable_restore_session()->set_sampling_factor(value); | |
329 } | |
330 if (GetInt64Param(params, "RestoreSession::MaxDelaySec", &value)) { | |
331 collection_params_.mutable_restore_session()->set_max_collection_delay( | |
332 base::TimeDelta::FromSeconds(value)); | |
333 } | |
334 | |
335 const std::string best_cpu_specifier = | |
336 internal::FindBestCpuSpecifierFromParams(params, GetCPUIdentity()); | |
337 | |
338 if (best_cpu_specifier.empty()) // no matching cpu specifier. Keep defaults. | |
Alexei Svitkine (slow)
2015/10/20 20:24:58
Nit: Capitalize No
dhsharp
2015/10/21 02:17:03
Done.
| |
339 return; | |
340 | |
341 std::vector<RandomSelector::WeightAndValue> commands; | |
342 for (const auto& key_val : params) { | |
343 const std::string& key = key_val.first; | |
344 const std::string& val = key_val.second; | |
345 | |
346 std::string cpu_specifier; | |
347 if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) | |
348 continue; | |
349 if (cpu_specifier != best_cpu_specifier) | |
350 continue; | |
351 | |
352 auto split = val.find(" "); | |
353 if (split == std::string::npos) | |
354 continue; // Just drop invalid commands. | |
355 std::string weight_str = std::string(val.begin(), val.begin() + split); | |
356 | |
357 double weight; | |
358 if (!(base::StringToDouble(weight_str, &weight) && weight > 0.0)) | |
359 continue; // Just drop invalid commands. | |
360 std::string command(val.begin() + split + 1, val.end()); | |
361 commands.push_back(RandomSelector::WeightAndValue(weight, command)); | |
362 } | |
363 command_selector_.SetOdds(commands); | |
364 } | |
365 | |
215 bool PerfProvider::GetSampledProfiles( | 366 bool PerfProvider::GetSampledProfiles( |
216 std::vector<SampledProfile>* sampled_profiles) { | 367 std::vector<SampledProfile>* sampled_profiles) { |
217 DCHECK(CalledOnValidThread()); | 368 DCHECK(CalledOnValidThread()); |
218 if (cached_perf_data_.empty()) { | 369 if (cached_perf_data_.empty()) { |
219 AddToPerfHistogram(NOT_READY_TO_UPLOAD); | 370 AddToPerfHistogram(NOT_READY_TO_UPLOAD); |
220 return false; | 371 return false; |
221 } | 372 } |
222 | 373 |
223 sampled_profiles->swap(cached_perf_data_); | 374 sampled_profiles->swap(cached_perf_data_); |
224 cached_perf_data_.clear(); | 375 cached_perf_data_.clear(); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 613 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
463 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 614 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); |
464 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | 615 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); |
465 sampled_profile->set_num_tabs_restored(num_tabs_restored); | 616 sampled_profile->set_num_tabs_restored(num_tabs_restored); |
466 | 617 |
467 CollectIfNecessary(sampled_profile.Pass()); | 618 CollectIfNecessary(sampled_profile.Pass()); |
468 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 619 last_session_restore_collection_time_ = base::TimeTicks::Now(); |
469 } | 620 } |
470 | 621 |
471 } // namespace metrics | 622 } // namespace metrics |
OLD | NEW |