Commit 108d547b authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

base::CPU: Return no-destruct reference from GuessCoreTypes()

Currently, base::CPU::GuessCoreTypes() is called in multiple places and
executes the same code multiple times, even though the result is
constant. There's already some static caching in different places.

This patch moves the static caching into base::CPU::GuessCoreTypes()
and renames it to base::CPU::GetGuessedCoreTypes().

Bug: 1081760
Change-Id: Ifaff01cc19abc48a36d5fe19bc4cb9a9cfa4fd24
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463309
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816122}
parent 265aefa0
...@@ -388,16 +388,14 @@ bool ParseTimeInState(const std::string& content, ...@@ -388,16 +388,14 @@ bool ParseTimeInState(const std::string& content,
return true; return true;
} }
} // namespace std::vector<CPU::CoreType> GuessCoreTypes() {
// static
std::vector<CPU::CoreType> CPU::GuessCoreTypes() {
// Try to guess the CPU architecture and cores of each cluster by comparing // Try to guess the CPU architecture and cores of each cluster by comparing
// the maximum frequencies of the available (online and offline) cores. // the maximum frequencies of the available (online and offline) cores.
const char kCPUMaxFreqPath[] = const char kCPUMaxFreqPath[] =
"/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq"; "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq";
int num_cpus = SysInfo::NumberOfProcessors(); int num_cpus = SysInfo::NumberOfProcessors();
std::vector<CPU::CoreType> core_index_to_type(num_cpus, CoreType::kUnknown); std::vector<CPU::CoreType> core_index_to_type(num_cpus,
CPU::CoreType::kUnknown);
std::vector<uint32_t> max_core_frequencies_mhz(num_cpus, 0); std::vector<uint32_t> max_core_frequencies_mhz(num_cpus, 0);
flat_set<uint32_t> frequencies_mhz; flat_set<uint32_t> frequencies_mhz;
...@@ -424,9 +422,9 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() { ...@@ -424,9 +422,9 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() {
for (int core_index = 0; core_index < num_cpus; ++core_index) { for (int core_index = 0; core_index < num_cpus; ++core_index) {
uint32_t core_frequency_mhz = max_core_frequencies_mhz[core_index]; uint32_t core_frequency_mhz = max_core_frequencies_mhz[core_index];
CoreType core_type = CoreType::kOther; CPU::CoreType core_type = CPU::CoreType::kOther;
if (num_frequencies == 1u) { if (num_frequencies == 1u) {
core_type = CoreType::kSymmetric; core_type = CPU::CoreType::kSymmetric;
} else if (num_frequencies == 2u || num_frequencies == 3u) { } else if (num_frequencies == 2u || num_frequencies == 3u) {
auto it = frequencies_mhz.find(core_frequency_mhz); auto it = frequencies_mhz.find(core_frequency_mhz);
if (it != frequencies_mhz.end()) { if (it != frequencies_mhz.end()) {
...@@ -435,16 +433,17 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() { ...@@ -435,16 +433,17 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() {
switch (frequency_index) { switch (frequency_index) {
case 0: case 0:
core_type = num_frequencies == 2u core_type = num_frequencies == 2u
? CoreType::kBigLittle_Little ? CPU::CoreType::kBigLittle_Little
: CoreType::kBigLittleBigger_Little; : CPU::CoreType::kBigLittleBigger_Little;
break; break;
case 1: case 1:
core_type = num_frequencies == 2u ? CoreType::kBigLittle_Big core_type = num_frequencies == 2u
: CoreType::kBigLittleBigger_Big; ? CPU::CoreType::kBigLittle_Big
: CPU::CoreType::kBigLittleBigger_Big;
break; break;
case 2: case 2:
DCHECK_EQ(num_frequencies, 3u); DCHECK_EQ(num_frequencies, 3u);
core_type = CoreType::kBigLittleBigger_Bigger; core_type = CPU::CoreType::kBigLittleBigger_Bigger;
break; break;
default: default:
NOTREACHED(); NOTREACHED();
...@@ -458,6 +457,14 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() { ...@@ -458,6 +457,14 @@ std::vector<CPU::CoreType> CPU::GuessCoreTypes() {
return core_index_to_type; return core_index_to_type;
} }
} // namespace
// static
const std::vector<CPU::CoreType>& CPU::GetGuessedCoreTypes() {
static NoDestructor<std::vector<CoreType>> kCoreTypes(GuessCoreTypes());
return *kCoreTypes.get();
}
// static // static
bool CPU::GetTimeInState(TimeInState& time_in_state) { bool CPU::GetTimeInState(TimeInState& time_in_state) {
time_in_state.clear(); time_in_state.clear();
...@@ -467,7 +474,7 @@ bool CPU::GetTimeInState(TimeInState& time_in_state) { ...@@ -467,7 +474,7 @@ bool CPU::GetTimeInState(TimeInState& time_in_state) {
if (!kSupportsTimeInState) if (!kSupportsTimeInState)
return false; return false;
static NoDestructor<std::vector<CoreType>> kCoreTypes(GuessCoreTypes()); static const std::vector<CoreType>& kCoreTypes = GetGuessedCoreTypes();
// time_in_state is reported per cluster. Identify the first cores of each // time_in_state is reported per cluster. Identify the first cores of each
// cluster. // cluster.
...@@ -516,7 +523,7 @@ bool CPU::GetTimeInState(TimeInState& time_in_state) { ...@@ -516,7 +523,7 @@ bool CPU::GetTimeInState(TimeInState& time_in_state) {
if (!ReadFileToString(time_in_state_path, &buffer)) if (!ReadFileToString(time_in_state_path, &buffer))
return false; return false;
if (!ParseTimeInState(buffer, (*kCoreTypes)[cluster_core_index], if (!ParseTimeInState(buffer, kCoreTypes[cluster_core_index],
cluster_core_index, time_in_state)) { cluster_core_index, time_in_state)) {
return false; return false;
} }
......
...@@ -90,10 +90,9 @@ class BASE_EXPORT CPU final { ...@@ -90,10 +90,9 @@ class BASE_EXPORT CPU final {
// Attempts to guess the core types of individual CPU cores based on frequency // Attempts to guess the core types of individual CPU cores based on frequency
// information from /sys/devices/system/cpu/cpuN/cpufreq/cpuinfo_max_freq. // information from /sys/devices/system/cpu/cpuN/cpufreq/cpuinfo_max_freq.
// Beware that it is kernel/hardware dependent whether the information from // Beware that it is kernel/hardware dependent whether the information from
// sys is accurate. // sys is accurate. Returns a reference to a static-storage vector (leaked on
// // shutdown) with the guessed type for core N at index N.
// Returns a vector with the guessed type for core N at index N. static const std::vector<CoreType>& GetGuessedCoreTypes();
static std::vector<CoreType> GuessCoreTypes();
struct TimeInStateEntry { struct TimeInStateEntry {
CPU::CoreType core_type; // type of the cores in this cluster. CPU::CoreType core_type; // type of the cores in this cluster.
......
...@@ -17,7 +17,7 @@ const cpu_set_t& AllCores() { ...@@ -17,7 +17,7 @@ const cpu_set_t& AllCores() {
static const cpu_set_t kAllCores = []() { static const cpu_set_t kAllCores = []() {
cpu_set_t set; cpu_set_t set;
CPU_ZERO(&set); CPU_ZERO(&set);
std::vector<CPU::CoreType> core_types = CPU::GuessCoreTypes(); const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
if (core_types.empty()) { if (core_types.empty()) {
memset(&set, 0xff, sizeof(set)); memset(&set, 0xff, sizeof(set));
} else { } else {
...@@ -31,7 +31,7 @@ const cpu_set_t& AllCores() { ...@@ -31,7 +31,7 @@ const cpu_set_t& AllCores() {
const cpu_set_t& LittleCores() { const cpu_set_t& LittleCores() {
static const cpu_set_t kLittleCores = []() { static const cpu_set_t kLittleCores = []() {
std::vector<CPU::CoreType> core_types = CPU::GuessCoreTypes(); const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
if (core_types.empty()) if (core_types.empty())
return AllCores(); return AllCores();
...@@ -64,7 +64,7 @@ const cpu_set_t& LittleCores() { ...@@ -64,7 +64,7 @@ const cpu_set_t& LittleCores() {
bool HasBigCpuCores() { bool HasBigCpuCores() {
static const bool kHasBigCores = []() { static const bool kHasBigCores = []() {
std::vector<CPU::CoreType> core_types = CPU::GuessCoreTypes(); const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
if (core_types.empty()) if (core_types.empty())
return false; return false;
for (CPU::CoreType core_type : core_types) { for (CPU::CoreType core_type : core_types) {
......
...@@ -249,9 +249,6 @@ class BASE_EXPORT ProcessMetrics { ...@@ -249,9 +249,6 @@ class BASE_EXPORT ProcessMetrics {
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \ #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
defined(OS_AIX) defined(OS_AIX)
CPU::CoreType GetCoreType(int core_index); CPU::CoreType GetCoreType(int core_index);
// Initialized on the first call to GetCoreType().
base::Optional<std::vector<CPU::CoreType>> core_index_to_type_;
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) ||
// defined(OS_AIX) // defined(OS_AIX)
......
...@@ -481,13 +481,10 @@ bool ProcessMetrics::ParseProcTimeInState( ...@@ -481,13 +481,10 @@ bool ProcessMetrics::ParseProcTimeInState(
} }
CPU::CoreType ProcessMetrics::GetCoreType(int core_index) { CPU::CoreType ProcessMetrics::GetCoreType(int core_index) {
if (!core_index_to_type_) const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
core_index_to_type_ = CPU::GuessCoreTypes(); if (static_cast<size_t>(core_index) >= core_types.size())
if (static_cast<size_t>(core_index) >= core_index_to_type_->size())
return CPU::CoreType::kUnknown; return CPU::CoreType::kUnknown;
return core_types[static_cast<size_t>(core_index)];
return core_index_to_type_->at(static_cast<size_t>(core_index));
} }
const char kProcSelfExe[] = "/proc/self/exe"; const char kProcSelfExe[] = "/proc/self/exe";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment