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 25 matching lines...) Expand all Loading... |
61 bool IsNormalUserLoggedIn() { | 67 bool IsNormalUserLoggedIn() { |
62 return chromeos::LoginState::Get()->IsUserAuthenticated(); | 68 return chromeos::LoginState::Get()->IsUserAuthenticated(); |
63 } | 69 } |
64 | 70 |
65 // Returns a random TimeDelta between zero and |max|. | 71 // Returns a random TimeDelta between zero and |max|. |
66 base::TimeDelta RandomTimeDelta(base::TimeDelta max) { | 72 base::TimeDelta RandomTimeDelta(base::TimeDelta max) { |
67 return base::TimeDelta::FromMicroseconds( | 73 return base::TimeDelta::FromMicroseconds( |
68 base::RandGenerator(max.InMicroseconds())); | 74 base::RandGenerator(max.InMicroseconds())); |
69 } | 75 } |
70 | 76 |
| 77 // Gets parameter named by |key| from the map. If it is present and is an |
| 78 // integer, stores the result in |out| and return true. Otherwise return false. |
| 79 bool GetInt64Param(const std::map<std::string, std::string>& params, |
| 80 const std::string& key, |
| 81 int64* out) { |
| 82 auto it = params.find(key); |
| 83 if (it == params.end()) |
| 84 return false; |
| 85 int64 value; |
| 86 // NB: StringToInt64 will set value even if the conversion fails. |
| 87 if (!base::StringToInt64(it->second, &value)) |
| 88 return false; |
| 89 *out = value; |
| 90 return true; |
| 91 } |
| 92 |
| 93 // Parses the key. e.g.: "PerfCommand::arm::0" returns "arm" |
| 94 bool ExtractPerfCommandCpuSpecifier(const std::string& key, |
| 95 std::string* cpu_specifier) { |
| 96 std::vector<std::string> tokens; |
| 97 base::SplitStringUsingSubstr(key, "::", &tokens); |
| 98 if (tokens.size() != 3) |
| 99 return false; |
| 100 if (tokens[0] != "PerfCommand") |
| 101 return false; |
| 102 *cpu_specifier = tokens[1]; |
| 103 // tokens[2] is just a unique string (usually an index). |
| 104 return true; |
| 105 } |
| 106 |
71 // Hopefully we never need a space in a command argument. | 107 // Hopefully we never need a space in a command argument. |
72 const char kPerfCommandDelimiter[] = " "; | 108 const char kPerfCommandDelimiter[] = " "; |
73 | 109 |
74 const char kPerfRecordCyclesCmd[] = | 110 const char kPerfRecordCyclesCmd[] = |
75 "perf record -a -e cycles -c 1000003"; | 111 "perf record -a -e cycles -c 1000003"; |
76 | 112 |
77 const char kPerfRecordCallgraphCmd[] = | 113 const char kPerfRecordCallgraphCmd[] = |
78 "perf record -a -e cycles -g -c 4000037"; | 114 "perf record -a -e cycles -g -c 4000037"; |
79 | 115 |
80 const char kPerfRecordLBRCmd[] = | 116 const char kPerfRecordLBRCmd[] = |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 /* max_collection_delay = */ base::TimeDelta::FromSeconds(5)), | 213 /* max_collection_delay = */ base::TimeDelta::FromSeconds(5)), |
178 /* restore_session = */ PerfProvider::CollectionParams::TriggerParams( | 214 /* restore_session = */ PerfProvider::CollectionParams::TriggerParams( |
179 /* sampling_factor = */ 10, | 215 /* sampling_factor = */ 10, |
180 /* max_collection_delay = */ base::TimeDelta::FromSeconds(10))); | 216 /* max_collection_delay = */ base::TimeDelta::FromSeconds(10))); |
181 | 217 |
182 PerfProvider::PerfProvider() | 218 PerfProvider::PerfProvider() |
183 : collection_params_(kDefaultParameters), | 219 : collection_params_(kDefaultParameters), |
184 login_observer_(this), | 220 login_observer_(this), |
185 next_profiling_interval_start_(base::TimeTicks::Now()), | 221 next_profiling_interval_start_(base::TimeTicks::Now()), |
186 weak_factory_(this) { | 222 weak_factory_(this) { |
187 command_selector_.SetOdds( | 223 CHECK(command_selector_.SetOdds( |
188 internal::GetDefaultCommandsForCpu(GetCPUIdentity())), | 224 internal::GetDefaultCommandsForCpu(GetCPUIdentity()))); |
| 225 std::map<std::string, std::string> params; |
| 226 if (variations::GetVariationParams(kCWPFieldTrialName, ¶ms)) |
| 227 SetCollectionParamsFromVariationParams(params); |
189 | 228 |
190 // Register the login observer with LoginState. | 229 // Register the login observer with LoginState. |
191 chromeos::LoginState::Get()->AddObserver(&login_observer_); | 230 chromeos::LoginState::Get()->AddObserver(&login_observer_); |
192 | 231 |
193 // Register as an observer of power manager events. | 232 // Register as an observer of power manager events. |
194 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | 233 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> |
195 AddObserver(this); | 234 AddObserver(this); |
196 | 235 |
197 // Register as an observer of session restore. | 236 // Register as an observer of session restore. |
198 on_session_restored_callback_subscription_ = | 237 on_session_restored_callback_subscription_ = |
199 SessionRestore::RegisterOnSessionRestoredCallback( | 238 SessionRestore::RegisterOnSessionRestoredCallback( |
200 base::Bind(&PerfProvider::OnSessionRestoreDone, | 239 base::Bind(&PerfProvider::OnSessionRestoreDone, |
201 weak_factory_.GetWeakPtr())); | 240 weak_factory_.GetWeakPtr())); |
202 | 241 |
203 // Check the login state. At the time of writing, this class is instantiated | 242 // Check the login state. At the time of writing, this class is instantiated |
204 // before login. A subsequent login would activate the profiling. However, | 243 // 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 | 244 // that behavior may change in the future so that the user is already logged |
206 // when this class is instantiated. By calling LoggedInStateChanged() here, | 245 // when this class is instantiated. By calling LoggedInStateChanged() here, |
207 // PerfProvider will recognize that the system is already logged in. | 246 // PerfProvider will recognize that the system is already logged in. |
208 login_observer_.LoggedInStateChanged(); | 247 login_observer_.LoggedInStateChanged(); |
209 } | 248 } |
210 | 249 |
211 PerfProvider::~PerfProvider() { | 250 PerfProvider::~PerfProvider() { |
212 chromeos::LoginState::Get()->RemoveObserver(&login_observer_); | 251 chromeos::LoginState::Get()->RemoveObserver(&login_observer_); |
213 } | 252 } |
214 | 253 |
| 254 namespace internal { |
| 255 |
| 256 std::string FindBestCpuSpecifierFromParams( |
| 257 const std::map<std::string, std::string>& params, |
| 258 const CPUIdentity& cpuid) { |
| 259 std::string ret; |
| 260 // The CPU specified in the variation params could be "default", a system |
| 261 // architecture, a CPU microarchitecture, or a CPU model substring. We should |
| 262 // prefer to match the most specific. |
| 263 enum MatchSpecificity { |
| 264 NO_MATCH, |
| 265 DEFAULT, |
| 266 SYSTEM_ARCH, |
| 267 CPU_UARCH, |
| 268 CPU_MODEL, |
| 269 }; |
| 270 MatchSpecificity match_level = NO_MATCH; |
| 271 |
| 272 const std::string intel_uarch = GetIntelUarch(cpuid); |
| 273 const std::string simplified_cpu_model = |
| 274 SimplifyCPUModelName(cpuid.model_name); |
| 275 |
| 276 for (const auto& key_val : params) { |
| 277 const std::string& key = key_val.first; |
| 278 |
| 279 std::string cpu_specifier; |
| 280 if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) |
| 281 continue; |
| 282 |
| 283 if (match_level < DEFAULT && cpu_specifier == "default") { |
| 284 match_level = DEFAULT; |
| 285 ret = cpu_specifier; |
| 286 } |
| 287 if (match_level < SYSTEM_ARCH && cpu_specifier == cpuid.arch) { |
| 288 match_level = SYSTEM_ARCH; |
| 289 ret = cpu_specifier; |
| 290 } |
| 291 if (match_level < CPU_UARCH && |
| 292 !intel_uarch.empty() && cpu_specifier == intel_uarch) { |
| 293 match_level = CPU_UARCH; |
| 294 ret = cpu_specifier; |
| 295 } |
| 296 if (match_level < CPU_MODEL && |
| 297 simplified_cpu_model.find(cpu_specifier) != std::string::npos) { |
| 298 match_level = CPU_MODEL; |
| 299 ret = cpu_specifier; |
| 300 } |
| 301 } |
| 302 return ret; |
| 303 } |
| 304 |
| 305 } // namespace internal |
| 306 |
| 307 void PerfProvider::SetCollectionParamsFromVariationParams( |
| 308 const std::map<std::string, std::string>& params) { |
| 309 int64 value; |
| 310 if (GetInt64Param(params, "ProfileCollectionDurationSec", &value)) { |
| 311 collection_params_.set_collection_duration( |
| 312 base::TimeDelta::FromSeconds(value)); |
| 313 } |
| 314 if (GetInt64Param(params, "PeriodicProfilingIntervalMs", &value)) { |
| 315 collection_params_.set_periodic_interval( |
| 316 base::TimeDelta::FromMilliseconds(value)); |
| 317 } |
| 318 if (GetInt64Param(params, "ResumeFromSuspend::SamplingFactor", &value)) { |
| 319 collection_params_.mutable_resume_from_suspend() |
| 320 ->set_sampling_factor(value); |
| 321 } |
| 322 if (GetInt64Param(params, "ResumeFromSuspend::MaxDelaySec", &value)) { |
| 323 collection_params_.mutable_resume_from_suspend()->set_max_collection_delay( |
| 324 base::TimeDelta::FromSeconds(value)); |
| 325 } |
| 326 if (GetInt64Param(params, "RestoreSession::SamplingFactor", &value)) { |
| 327 collection_params_.mutable_restore_session()->set_sampling_factor(value); |
| 328 } |
| 329 if (GetInt64Param(params, "RestoreSession::MaxDelaySec", &value)) { |
| 330 collection_params_.mutable_restore_session()->set_max_collection_delay( |
| 331 base::TimeDelta::FromSeconds(value)); |
| 332 } |
| 333 |
| 334 const std::string best_cpu_specifier = |
| 335 internal::FindBestCpuSpecifierFromParams(params, GetCPUIdentity()); |
| 336 |
| 337 if (best_cpu_specifier.empty()) // No matching cpu specifier. Keep defaults. |
| 338 return; |
| 339 |
| 340 std::vector<RandomSelector::WeightAndValue> commands; |
| 341 for (const auto& key_val : params) { |
| 342 const std::string& key = key_val.first; |
| 343 const std::string& val = key_val.second; |
| 344 |
| 345 std::string cpu_specifier; |
| 346 if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) |
| 347 continue; |
| 348 if (cpu_specifier != best_cpu_specifier) |
| 349 continue; |
| 350 |
| 351 auto split = val.find(" "); |
| 352 if (split == std::string::npos) |
| 353 continue; // Just drop invalid commands. |
| 354 std::string weight_str = std::string(val.begin(), val.begin() + split); |
| 355 |
| 356 double weight; |
| 357 if (!(base::StringToDouble(weight_str, &weight) && weight > 0.0)) |
| 358 continue; // Just drop invalid commands. |
| 359 std::string command(val.begin() + split + 1, val.end()); |
| 360 commands.push_back(RandomSelector::WeightAndValue(weight, command)); |
| 361 } |
| 362 command_selector_.SetOdds(commands); |
| 363 } |
| 364 |
215 bool PerfProvider::GetSampledProfiles( | 365 bool PerfProvider::GetSampledProfiles( |
216 std::vector<SampledProfile>* sampled_profiles) { | 366 std::vector<SampledProfile>* sampled_profiles) { |
217 DCHECK(CalledOnValidThread()); | 367 DCHECK(CalledOnValidThread()); |
218 if (cached_perf_data_.empty()) { | 368 if (cached_perf_data_.empty()) { |
219 AddToPerfHistogram(NOT_READY_TO_UPLOAD); | 369 AddToPerfHistogram(NOT_READY_TO_UPLOAD); |
220 return false; | 370 return false; |
221 } | 371 } |
222 | 372 |
223 sampled_profiles->swap(cached_perf_data_); | 373 sampled_profiles->swap(cached_perf_data_); |
224 cached_perf_data_.clear(); | 374 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); | 612 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
463 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 613 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); |
464 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | 614 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); |
465 sampled_profile->set_num_tabs_restored(num_tabs_restored); | 615 sampled_profile->set_num_tabs_restored(num_tabs_restored); |
466 | 616 |
467 CollectIfNecessary(sampled_profile.Pass()); | 617 CollectIfNecessary(sampled_profile.Pass()); |
468 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 618 last_session_restore_collection_time_ = base::TimeTicks::Now(); |
469 } | 619 } |
470 | 620 |
471 } // namespace metrics | 621 } // namespace metrics |
OLD | NEW |