Chromium Code Reviews| Index: base/cpu.cc |
| diff --git a/base/cpu.cc b/base/cpu.cc |
| index dcba3b6e73e5aa7884d02b59794adfafa505ca9d..453e6c7014150e1e54ae9176c4f1a64895445e16 100644 |
| --- a/base/cpu.cc |
| +++ b/base/cpu.cc |
| @@ -4,6 +4,7 @@ |
| #include "base/cpu.h" |
| +#include <stdlib.h> |
| #include <string.h> |
| #include <algorithm> |
| @@ -44,6 +45,7 @@ CPU::CPU() |
| has_avx_hardware_(false), |
| has_aesni_(false), |
| has_non_stop_time_stamp_counter_(false), |
| + has_broken_neon_(false), |
| cpu_vendor_("unknown") { |
| Initialize(); |
| } |
| @@ -90,52 +92,97 @@ uint64 _xgetbv(uint32 xcr) { |
| #endif // ARCH_CPU_X86_FAMILY |
| #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| +class LazyCpuInfoValue { |
| + public: |
| + LazyCpuInfoValue() : |
|
willchan no longer on Chromium
2014/08/05 22:47:38
Google style guide says to move the ':' to the fir
agl
2014/08/07 01:53:49
Done.
|
| + has_broken_neon_(false) { |
| + // This function finds the value from /proc/cpuinfo under the key "model |
| + // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7 |
| + // and later for arm64) and is shown once per CPU. "Processor" is used in |
| + // earler versions and is shown only once at the top of /proc/cpuinfo |
| + // regardless of the number CPUs. |
| + const char kModelNamePrefix[] = "model name\t: "; |
| + const char kProcessorPrefix[] = "Processor\t: "; |
| + |
| + // This function also calculates whether we believe that this CPU has a |
| + // broken NEON unit based on these fields from cpuinfo: |
| + unsigned implementer = 0, architecture = 0, variant = 0, part = 0, |
| + revision = 0; |
| + const struct { |
| + const char key[17]; |
| + unsigned *result; |
| + } kUnsignedValues[] = { |
| + {"CPU implementer", &implementer}, |
| + {"CPU architecture", &architecture}, |
| + {"CPU variant", &variant}, |
| + {"CPU part", &part}, |
| + {"CPU revision", &revision}, |
| + }; |
| + |
| + std::string contents; |
| + ReadFileToString(FilePath("/proc/cpuinfo"), &contents); |
| + DCHECK(!contents.empty()); |
| + if (contents.empty()) { |
| + return; |
| + } |
| -// Returns the string found in /proc/cpuinfo under the key "model name" or |
| -// "Processor". "model name" is used in Linux 3.8 and later (3.7 and later for |
| -// arm64) and is shown once per CPU. "Processor" is used in earler versions and |
| -// is shown only once at the top of /proc/cpuinfo regardless of the number CPUs. |
| -std::string ParseCpuInfo() { |
| - const char kModelNamePrefix[] = "model name\t: "; |
| - const char kProcessorPrefix[] = "Processor\t: "; |
| - std::string contents; |
| - ReadFileToString(FilePath("/proc/cpuinfo"), &contents); |
| - DCHECK(!contents.empty()); |
| - std::string cpu_brand; |
| - if (!contents.empty()) { |
| std::istringstream iss(contents); |
| std::string line; |
| while (std::getline(iss, line)) { |
| - if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) { |
| - cpu_brand.assign(line.substr(strlen(kModelNamePrefix))); |
| - break; |
| + if (brand_.empty() && |
| + (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 || |
| + line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) { |
| + brand_.assign(line.substr(strlen(kModelNamePrefix))); |
| } |
| - if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) { |
| - cpu_brand.assign(line.substr(strlen(kProcessorPrefix))); |
| - break; |
| + |
| + for (size_t i = 0; i < arraysize(kUnsignedValues); i++) { |
| + const char *key = kUnsignedValues[i].key; |
| + const size_t len = strlen(key); |
| + |
| + if (line.compare(0, len, key) == 0 && |
| + line.size() >= len + 1 && |
| + (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) { |
| + size_t colon_pos = line.find(':', len); |
| + if (colon_pos == std::string::npos) { |
| + continue; |
| + } |
| + |
| + std::string value = line.substr(colon_pos + 1); |
| + while (!value.empty() && (value[0] == ' ' || value[0] == '\t')) { |
| + value = value.substr(1); |
|
willchan no longer on Chromium
2014/08/05 22:47:38
I probably shouldn't care, but all the copies in t
agl
2014/08/07 01:53:49
Have used StringPeice to save a couple of copies,
|
| + } |
| + |
| + // The string may have leading "0x" or not, so we use strtoul to |
| + // handle that. |
| + char *endptr; |
| + unsigned long int result = strtoul(value.c_str(), &endptr, 0); |
| + if (*endptr == 0 && result <= UINT_MAX) { |
| + *kUnsignedValues[i].result = result; |
| + } |
| + } |
| } |
| } |
| + |
| + has_broken_neon_ = |
| + implementer == 0x51 && |
| + architecture == 7 && |
| + variant == 1 && |
| + part == 0x4d && |
| + revision == 0; |
| } |
| - return cpu_brand; |
| -} |
| -class LazyCpuInfoValue { |
| - public: |
| - LazyCpuInfoValue() : value_(ParseCpuInfo()) {} |
| - const std::string& value() { return value_; } |
| + const std::string& brand() const { return brand_; } |
| + bool has_broken_neon() const { return has_broken_neon_; } |
| private: |
| - const std::string value_; |
| + std::string brand_; |
| + bool has_broken_neon_; |
| DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); |
| }; |
| -base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand = |
| +base::LazyInstance<LazyCpuInfoValue> g_lazy_cpuinfo = |
|
willchan no longer on Chromium
2014/08/05 22:47:38
Nit: Since the other singleton that uses this is l
agl
2014/08/07 01:53:49
Done.
|
| LAZY_INSTANCE_INITIALIZER; |
| -const std::string& CpuBrandInfo() { |
| - return g_lazy_cpu_brand.Get().value(); |
| -} |
| - |
| #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || |
| // defined(OS_LINUX)) |
| @@ -219,7 +266,8 @@ void CPU::Initialize() { |
| has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; |
| } |
| #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| - cpu_brand_.assign(CpuBrandInfo()); |
| + cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); |
| + has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); |
| #endif |
| } |