Index: chrome/browser/metrics/perf/perf_provider_chromeos.cc |
diff --git a/chrome/browser/metrics/perf/perf_provider_chromeos.cc b/chrome/browser/metrics/perf/perf_provider_chromeos.cc |
index bcd88348cb7f6fd462e5d6ab5c1317b3cf5b91aa..d7b1f8e572108eb1b455a93b1d43beba202874ba 100644 |
--- a/chrome/browser/metrics/perf/perf_provider_chromeos.cc |
+++ b/chrome/browser/metrics/perf/perf_provider_chromeos.cc |
@@ -5,24 +5,30 @@ |
#include "chrome/browser/metrics/perf/perf_provider_chromeos.h" |
#include <algorithm> |
+#include <map> |
#include <string> |
#include "base/bind.h" |
#include "base/callback.h" |
#include "base/compiler_specific.h" |
+#include "base/metrics/field_trial.h" |
#include "base/metrics/histogram.h" |
#include "base/rand_util.h" |
+#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_split.h" |
#include "base/threading/sequenced_worker_pool.h" |
#include "chrome/browser/metrics/perf/windowed_incognito_observer.h" |
#include "chrome/browser/ui/browser_list.h" |
#include "chromeos/dbus/dbus_thread_manager.h" |
#include "chromeos/dbus/debug_daemon_client.h" |
+#include "components/variations/variations_associated_data.h" |
namespace metrics { |
namespace { |
+const char kCWPFieldTrialName[] = "ChromeOSWideProfilingCollection"; |
+ |
// Limit the total size of protobufs that can be cached, so they don't take up |
// too much memory. If the size of cached protobufs exceeds this value, stop |
// collecting further perf data. The current value is 4 MB. |
@@ -184,8 +190,11 @@ PerfProvider::PerfProvider() |
login_observer_(this), |
next_profiling_interval_start_(base::TimeTicks::Now()), |
weak_factory_(this) { |
- command_selector_.SetOdds( |
- internal::GetDefaultCommandsForCpu(GetCPUIdentity())), |
+ CHECK(command_selector_.SetOdds( |
+ internal::GetDefaultCommandsForCpu(GetCPUIdentity()))); |
+ std::map<std::string, std::string> params; |
+ if (variations::GetVariationParams(kCWPFieldTrialName, ¶ms)) |
+ SetCollectionParamsFromVariationParams(params); |
// Register the login observer with LoginState. |
chromeos::LoginState::Get()->AddObserver(&login_observer_); |
@@ -212,6 +221,148 @@ PerfProvider::~PerfProvider() { |
chromeos::LoginState::Get()->RemoveObserver(&login_observer_); |
} |
+namespace { |
+ |
+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.
|
+ 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.
|
+ auto it = params.find(key); |
+ if (it == params.end()) |
+ return false; |
+ int64 value; |
+ // NB: StringToInt64 will set value even if the conversion fails. |
+ 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
|
+ return false; |
+ *out = value; |
+ return true; |
+} |
+ |
+// Parse the key. e.g.: "PerfCommand::arm::0" returns "arm" |
+bool ExtractPerfCommandCpuSpecifier(const std::string& key, |
+ std::string* cpu_specifier) { |
+ std::vector<std::string> tokens; |
+ base::SplitStringUsingSubstr(key, "::", &tokens); |
+ if (tokens.size() != 3) |
+ return false; |
+ 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
|
+ return false; |
+ *cpu_specifier = tokens[1]; |
+ // tokens[2] is just a unique string (usually an index). |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+namespace internal { |
+ |
+std::string FindBestCpuSpecifierFromParams( |
+ const std::map<std::string, std::string>& params, |
+ const CPUIdentity& cpuid) { |
+ std::string ret; |
+ // The CPU specified in the variation params could be "default", a system |
+ // architecture, a CPU microarchitecture, or a CPU model substring. We should |
+ // prefer to match the most specific. |
+ enum MatchSpecificity { |
+ NO_MATCH, |
+ DEFAULT, |
+ SYSTEM_ARCH, |
+ CPU_UARCH, |
+ CPU_MODEL, |
+ }; |
+ MatchSpecificity match_level = NO_MATCH; |
+ |
+ const std::string intel_uarch = GetIntelUarch(cpuid); |
+ const std::string simplified_cpu_model = |
+ SimplifyCPUModelName(cpuid.model_name); |
+ |
+ for (const auto& key_val : params) { |
+ const std::string& key = key_val.first; |
+ |
+ std::string cpu_specifier; |
+ if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) |
+ continue; |
+ |
+ if (match_level < DEFAULT && cpu_specifier == "default") { |
+ match_level = DEFAULT; |
+ ret = cpu_specifier; |
+ } |
+ if (match_level < SYSTEM_ARCH && cpu_specifier == cpuid.arch) { |
+ match_level = SYSTEM_ARCH; |
+ ret = cpu_specifier; |
+ } |
+ if (match_level < CPU_UARCH && |
+ 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.
|
+ match_level = CPU_UARCH; |
+ ret = cpu_specifier; |
+ } |
+ if (match_level < CPU_MODEL && |
+ simplified_cpu_model.find(cpu_specifier) != std::string::npos) { |
+ match_level = CPU_MODEL; |
+ ret = cpu_specifier; |
+ } |
+ } |
+ return ret; |
+} |
+ |
+} // namespace internal |
+ |
+void PerfProvider::SetCollectionParamsFromVariationParams( |
+ const std::map<std::string, std::string>& params) { |
+ int64 value; |
+ if (GetInt64Param(params, "ProfileCollectionDurationSec", &value)) { |
+ collection_params_.set_collection_duration( |
+ base::TimeDelta::FromSeconds(value)); |
+ } |
+ if (GetInt64Param(params, "PeriodicProfilingIntervalMs", &value)) { |
+ collection_params_.set_periodic_interval( |
+ base::TimeDelta::FromMilliseconds(value)); |
+ } |
+ if (GetInt64Param(params, "ResumeFromSuspend::SamplingFactor", &value)) { |
+ collection_params_.mutable_resume_from_suspend() |
+ ->set_sampling_factor(value); |
+ } |
+ if (GetInt64Param(params, "ResumeFromSuspend::MaxDelaySec", &value)) { |
+ collection_params_.mutable_resume_from_suspend()->set_max_collection_delay( |
+ base::TimeDelta::FromSeconds(value)); |
+ } |
+ if (GetInt64Param(params, "RestoreSession::SamplingFactor", &value)) { |
+ collection_params_.mutable_restore_session()->set_sampling_factor(value); |
+ } |
+ if (GetInt64Param(params, "RestoreSession::MaxDelaySec", &value)) { |
+ collection_params_.mutable_restore_session()->set_max_collection_delay( |
+ base::TimeDelta::FromSeconds(value)); |
+ } |
+ |
+ const std::string best_cpu_specifier = |
+ internal::FindBestCpuSpecifierFromParams(params, GetCPUIdentity()); |
+ |
+ 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.
|
+ return; |
+ |
+ std::vector<RandomSelector::WeightAndValue> commands; |
+ for (const auto& key_val : params) { |
+ const std::string& key = key_val.first; |
+ const std::string& val = key_val.second; |
+ |
+ std::string cpu_specifier; |
+ if (!ExtractPerfCommandCpuSpecifier(key, &cpu_specifier)) |
+ continue; |
+ if (cpu_specifier != best_cpu_specifier) |
+ continue; |
+ |
+ auto split = val.find(" "); |
+ if (split == std::string::npos) |
+ continue; // Just drop invalid commands. |
+ std::string weight_str = std::string(val.begin(), val.begin() + split); |
+ |
+ double weight; |
+ if (!(base::StringToDouble(weight_str, &weight) && weight > 0.0)) |
+ continue; // Just drop invalid commands. |
+ std::string command(val.begin() + split + 1, val.end()); |
+ commands.push_back(RandomSelector::WeightAndValue(weight, command)); |
+ } |
+ command_selector_.SetOdds(commands); |
+} |
+ |
bool PerfProvider::GetSampledProfiles( |
std::vector<SampledProfile>* sampled_profiles) { |
DCHECK(CalledOnValidThread()); |