Chromium Code Reviews| 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 { | |
|
Alexei Svitkine (slow)
2015/10/16 15:37:50
Put these in the existing anon namespaces.
dhsharp
2015/10/19 22:45:28
I'd prefer to keep these near where they are used.
Alexei Svitkine (slow)
2015/10/20 20:24:58
In Chromium, the convention is to have a single an
dhsharp
2015/10/21 02:17:02
Well, okay. Done.
But you might want to tell thes
| |
| 225 | |
| 226 bool GetInt64Param(const std::map<std::string, std::string>& params, | |
| 227 const std::string& key, int64* out) { | |
| 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)) | |
| 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") | |
| 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 Finch params could be "default", a system | |
|
Alexei Svitkine (slow)
2015/10/16 15:37:50
Nit: Finch is an internal codename. Use "Variation
dhsharp
2015/10/19 22:45:28
Done.
| |
| 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) { | |
| 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)) | |
|
Alexei Svitkine (slow)
2015/10/16 15:37:50
Nit: {}'s for multi-line bodies.
dhsharp
2015/10/19 22:45:28
Done.
| |
| 312 collection_params_.set_collection_duration( | |
| 313 base::TimeDelta::FromSeconds(value)); | |
| 314 if (GetInt64Param(params, "PeriodicProfilingIntervalMs", &value)) | |
| 315 collection_params_.set_periodic_interval( | |
| 316 base::TimeDelta::FromMilliseconds(value)); | |
| 317 if (GetInt64Param(params, "ResumeFromSuspend::SamplingFactor", &value)) | |
| 318 collection_params_.mutable_resume_from_suspend() | |
| 319 ->set_sampling_factor(value); | |
| 320 if (GetInt64Param(params, "ResumeFromSuspend::MaxCollectionDelaySec", &value)) | |
| 321 collection_params_.mutable_resume_from_suspend()->set_max_collection_delay( | |
| 322 base::TimeDelta::FromSeconds(value)); | |
| 323 if (GetInt64Param(params, "RestoreSession::SamplingFactor", &value)) | |
| 324 collection_params_.mutable_restore_session()->set_sampling_factor(value); | |
| 325 if (GetInt64Param(params, "RestoreSession::MaxCollectionDelaySec", &value)) | |
|
Alexei Svitkine (slow)
2015/10/16 15:37:50
Nit: Is it possible to use shorter names for these
dhsharp
2015/10/19 22:45:28
It's certainly possible, heh. I guess it's a trade
Alexei Svitkine (slow)
2015/10/20 20:24:58
Another option is to have the string names themsel
| |
| 326 collection_params_.mutable_restore_session()->set_max_collection_delay( | |
| 327 base::TimeDelta::FromSeconds(value)); | |
| 328 | |
| 329 const std::string best_cpu_specifier = | |
| 330 internal::FindBestCpuSpecifierFromParams(params, GetCPUIdentity()); | |
| 331 | |
| 332 if (best_cpu_specifier.empty()) // no matching cpu specifier. Keep defaults. | |
| 333 return; | |
| 334 | |
| 335 std::vector<RandomSelector::WeightAndValue> commands; | |
| 336 for (const auto& key_val : params) { | |
| 337 const std::string& key = key_val.first; | |
| 338 const std::string& val = key_val.second; | |
| 339 | |
| 340 std::string cpu_specifier; | |
| 341 if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) | |
| 342 continue; | |
| 343 if (cpu_specifier != best_cpu_specifier) | |
| 344 continue; | |
| 345 | |
| 346 auto split = val.find(" "); | |
| 347 if (split == std::string::npos) | |
| 348 continue; // Just drop invalid commands. | |
| 349 std::string weight_str = std::string(val.begin(), val.begin() + split); | |
| 350 | |
| 351 double weight; | |
| 352 if (!(base::StringToDouble(weight_str, &weight) && weight > 0.0)) | |
|
Alexei Svitkine (slow)
2015/10/16 15:37:50
Nit: !(a && b) -> !a || !b
dhsharp
2015/10/19 22:45:28
I could apply DeMorgan's laws. However:
- I prefer
| |
| 353 continue; // Just drop invalid commands. | |
| 354 std::string command(val.begin() + split + 1, val.end()); | |
| 355 commands.push_back(RandomSelector::WeightAndValue(weight, command)); | |
| 356 } | |
| 357 command_selector_.SetOdds(commands); | |
| 358 } | |
| 359 | |
| 215 bool PerfProvider::GetSampledProfiles( | 360 bool PerfProvider::GetSampledProfiles( |
| 216 std::vector<SampledProfile>* sampled_profiles) { | 361 std::vector<SampledProfile>* sampled_profiles) { |
| 217 DCHECK(CalledOnValidThread()); | 362 DCHECK(CalledOnValidThread()); |
| 218 if (cached_perf_data_.empty()) { | 363 if (cached_perf_data_.empty()) { |
| 219 AddToPerfHistogram(NOT_READY_TO_UPLOAD); | 364 AddToPerfHistogram(NOT_READY_TO_UPLOAD); |
| 220 return false; | 365 return false; |
| 221 } | 366 } |
| 222 | 367 |
| 223 sampled_profiles->swap(cached_perf_data_); | 368 sampled_profiles->swap(cached_perf_data_); |
| 224 cached_perf_data_.clear(); | 369 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); | 607 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
| 463 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 608 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); |
| 464 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | 609 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); |
| 465 sampled_profile->set_num_tabs_restored(num_tabs_restored); | 610 sampled_profile->set_num_tabs_restored(num_tabs_restored); |
| 466 | 611 |
| 467 CollectIfNecessary(sampled_profile.Pass()); | 612 CollectIfNecessary(sampled_profile.Pass()); |
| 468 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 613 last_session_restore_collection_time_ = base::TimeTicks::Now(); |
| 469 } | 614 } |
| 470 | 615 |
| 471 } // namespace metrics | 616 } // namespace metrics |
| OLD | NEW |