| 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 "base/cpu.h" | 5 #include "base/cpu.h" |
| 6 | 6 |
| 7 #include <stdlib.h> |
| 7 #include <string.h> | 8 #include <string.h> |
| 8 | 9 |
| 9 #include <algorithm> | 10 #include <algorithm> |
| 10 | 11 |
| 11 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/strings/string_piece.h" |
| 12 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 13 | 15 |
| 14 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 16 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| 15 #include "base/file_util.h" | 17 #include "base/file_util.h" |
| 16 #include "base/lazy_instance.h" | 18 #include "base/lazy_instance.h" |
| 17 #endif | 19 #endif |
| 18 | 20 |
| 19 #if defined(ARCH_CPU_X86_FAMILY) | 21 #if defined(ARCH_CPU_X86_FAMILY) |
| 20 #if defined(_MSC_VER) | 22 #if defined(_MSC_VER) |
| 21 #include <intrin.h> | 23 #include <intrin.h> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 37 has_sse_(false), | 39 has_sse_(false), |
| 38 has_sse2_(false), | 40 has_sse2_(false), |
| 39 has_sse3_(false), | 41 has_sse3_(false), |
| 40 has_ssse3_(false), | 42 has_ssse3_(false), |
| 41 has_sse41_(false), | 43 has_sse41_(false), |
| 42 has_sse42_(false), | 44 has_sse42_(false), |
| 43 has_avx_(false), | 45 has_avx_(false), |
| 44 has_avx_hardware_(false), | 46 has_avx_hardware_(false), |
| 45 has_aesni_(false), | 47 has_aesni_(false), |
| 46 has_non_stop_time_stamp_counter_(false), | 48 has_non_stop_time_stamp_counter_(false), |
| 49 has_broken_neon_(false), |
| 47 cpu_vendor_("unknown") { | 50 cpu_vendor_("unknown") { |
| 48 Initialize(); | 51 Initialize(); |
| 49 } | 52 } |
| 50 | 53 |
| 51 namespace { | 54 namespace { |
| 52 | 55 |
| 53 #if defined(ARCH_CPU_X86_FAMILY) | 56 #if defined(ARCH_CPU_X86_FAMILY) |
| 54 #ifndef _MSC_VER | 57 #ifndef _MSC_VER |
| 55 | 58 |
| 56 #if defined(__pic__) && defined(__i386__) | 59 #if defined(__pic__) && defined(__i386__) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 83 uint32 eax, edx; | 86 uint32 eax, edx; |
| 84 | 87 |
| 85 __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); | 88 __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); |
| 86 return (static_cast<uint64>(edx) << 32) | eax; | 89 return (static_cast<uint64>(edx) << 32) | eax; |
| 87 } | 90 } |
| 88 | 91 |
| 89 #endif // !_MSC_VER | 92 #endif // !_MSC_VER |
| 90 #endif // ARCH_CPU_X86_FAMILY | 93 #endif // ARCH_CPU_X86_FAMILY |
| 91 | 94 |
| 92 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 95 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| 96 class LazyCpuInfoValue { |
| 97 public: |
| 98 LazyCpuInfoValue() : has_broken_neon_(false) { |
| 99 // This function finds the value from /proc/cpuinfo under the key "model |
| 100 // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7 |
| 101 // and later for arm64) and is shown once per CPU. "Processor" is used in |
| 102 // earler versions and is shown only once at the top of /proc/cpuinfo |
| 103 // regardless of the number CPUs. |
| 104 const char kModelNamePrefix[] = "model name\t: "; |
| 105 const char kProcessorPrefix[] = "Processor\t: "; |
| 93 | 106 |
| 94 // Returns the string found in /proc/cpuinfo under the key "model name" or | 107 // This function also calculates whether we believe that this CPU has a |
| 95 // "Processor". "model name" is used in Linux 3.8 and later (3.7 and later for | 108 // broken NEON unit based on these fields from cpuinfo: |
| 96 // arm64) and is shown once per CPU. "Processor" is used in earler versions and | 109 unsigned implementer = 0, architecture = 0, variant = 0, part = 0, |
| 97 // is shown only once at the top of /proc/cpuinfo regardless of the number CPUs. | 110 revision = 0; |
| 98 std::string ParseCpuInfo() { | 111 const struct { |
| 99 const char kModelNamePrefix[] = "model name\t: "; | 112 const char key[17]; |
| 100 const char kProcessorPrefix[] = "Processor\t: "; | 113 unsigned *result; |
| 101 std::string contents; | 114 } kUnsignedValues[] = { |
| 102 ReadFileToString(FilePath("/proc/cpuinfo"), &contents); | 115 {"CPU implementer", &implementer}, |
| 103 DCHECK(!contents.empty()); | 116 {"CPU architecture", &architecture}, |
| 104 std::string cpu_brand; | 117 {"CPU variant", &variant}, |
| 105 if (!contents.empty()) { | 118 {"CPU part", &part}, |
| 119 {"CPU revision", &revision}, |
| 120 }; |
| 121 |
| 122 std::string contents; |
| 123 ReadFileToString(FilePath("/proc/cpuinfo"), &contents); |
| 124 DCHECK(!contents.empty()); |
| 125 if (contents.empty()) { |
| 126 return; |
| 127 } |
| 128 |
| 106 std::istringstream iss(contents); | 129 std::istringstream iss(contents); |
| 107 std::string line; | 130 std::string line; |
| 108 while (std::getline(iss, line)) { | 131 while (std::getline(iss, line)) { |
| 109 if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) { | 132 if (brand_.empty() && |
| 110 cpu_brand.assign(line.substr(strlen(kModelNamePrefix))); | 133 (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 || |
| 111 break; | 134 line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) { |
| 135 brand_.assign(line.substr(strlen(kModelNamePrefix))); |
| 112 } | 136 } |
| 113 if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) { | 137 |
| 114 cpu_brand.assign(line.substr(strlen(kProcessorPrefix))); | 138 for (size_t i = 0; i < arraysize(kUnsignedValues); i++) { |
| 115 break; | 139 const char *key = kUnsignedValues[i].key; |
| 140 const size_t len = strlen(key); |
| 141 |
| 142 if (line.compare(0, len, key) == 0 && |
| 143 line.size() >= len + 1 && |
| 144 (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) { |
| 145 size_t colon_pos = line.find(':', len); |
| 146 if (colon_pos == std::string::npos) { |
| 147 continue; |
| 148 } |
| 149 |
| 150 const StringPiece line_sp(line); |
| 151 StringPiece value_sp = line_sp.substr(colon_pos + 1); |
| 152 while (!value_sp.empty() && |
| 153 (value_sp[0] == ' ' || value_sp[0] == '\t')) { |
| 154 value_sp = value_sp.substr(1); |
| 155 } |
| 156 |
| 157 // The string may have leading "0x" or not, so we use strtoul to |
| 158 // handle that. |
| 159 char *endptr; |
| 160 std::string value(value_sp.as_string()); |
| 161 unsigned long int result = strtoul(value.c_str(), &endptr, 0); |
| 162 if (*endptr == 0 && result <= UINT_MAX) { |
| 163 *kUnsignedValues[i].result = result; |
| 164 } |
| 165 } |
| 116 } | 166 } |
| 117 } | 167 } |
| 168 |
| 169 has_broken_neon_ = |
| 170 implementer == 0x51 && |
| 171 architecture == 7 && |
| 172 variant == 1 && |
| 173 part == 0x4d && |
| 174 revision == 0; |
| 118 } | 175 } |
| 119 return cpu_brand; | |
| 120 } | |
| 121 | 176 |
| 122 class LazyCpuInfoValue { | 177 const std::string& brand() const { return brand_; } |
| 123 public: | 178 bool has_broken_neon() const { return has_broken_neon_; } |
| 124 LazyCpuInfoValue() : value_(ParseCpuInfo()) {} | |
| 125 const std::string& value() { return value_; } | |
| 126 | 179 |
| 127 private: | 180 private: |
| 128 const std::string value_; | 181 std::string brand_; |
| 182 bool has_broken_neon_; |
| 129 DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); | 183 DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); |
| 130 }; | 184 }; |
| 131 | 185 |
| 132 base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand = | 186 base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo = |
| 133 LAZY_INSTANCE_INITIALIZER; | 187 LAZY_INSTANCE_INITIALIZER; |
| 134 | 188 |
| 135 const std::string& CpuBrandInfo() { | |
| 136 return g_lazy_cpu_brand.Get().value(); | |
| 137 } | |
| 138 | |
| 139 #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || | 189 #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || |
| 140 // defined(OS_LINUX)) | 190 // defined(OS_LINUX)) |
| 141 | 191 |
| 142 } // anonymous namespace | 192 } // anonymous namespace |
| 143 | 193 |
| 144 void CPU::Initialize() { | 194 void CPU::Initialize() { |
| 145 #if defined(ARCH_CPU_X86_FAMILY) | 195 #if defined(ARCH_CPU_X86_FAMILY) |
| 146 int cpu_info[4] = {-1}; | 196 int cpu_info[4] = {-1}; |
| 147 char cpu_string[48]; | 197 char cpu_string[48]; |
| 148 | 198 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 } | 262 } |
| 213 cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string); | 263 cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string); |
| 214 } | 264 } |
| 215 | 265 |
| 216 const int parameter_containing_non_stop_time_stamp_counter = 0x80000007; | 266 const int parameter_containing_non_stop_time_stamp_counter = 0x80000007; |
| 217 if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) { | 267 if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) { |
| 218 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); | 268 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); |
| 219 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; | 269 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; |
| 220 } | 270 } |
| 221 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 271 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| 222 cpu_brand_.assign(CpuBrandInfo()); | 272 cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); |
| 273 has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); |
| 223 #endif | 274 #endif |
| 224 } | 275 } |
| 225 | 276 |
| 226 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { | 277 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { |
| 227 if (has_avx()) return AVX; | 278 if (has_avx()) return AVX; |
| 228 if (has_sse42()) return SSE42; | 279 if (has_sse42()) return SSE42; |
| 229 if (has_sse41()) return SSE41; | 280 if (has_sse41()) return SSE41; |
| 230 if (has_ssse3()) return SSSE3; | 281 if (has_ssse3()) return SSSE3; |
| 231 if (has_sse3()) return SSE3; | 282 if (has_sse3()) return SSE3; |
| 232 if (has_sse2()) return SSE2; | 283 if (has_sse2()) return SSE2; |
| 233 if (has_sse()) return SSE; | 284 if (has_sse()) return SSE; |
| 234 return PENTIUM; | 285 return PENTIUM; |
| 235 } | 286 } |
| 236 | 287 |
| 237 } // namespace base | 288 } // namespace base |
| OLD | NEW |