| 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 <stdlib.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 ext_family_(0), | 37 ext_family_(0), |
| 38 has_mmx_(false), | 38 has_mmx_(false), |
| 39 has_sse_(false), | 39 has_sse_(false), |
| 40 has_sse2_(false), | 40 has_sse2_(false), |
| 41 has_sse3_(false), | 41 has_sse3_(false), |
| 42 has_ssse3_(false), | 42 has_ssse3_(false), |
| 43 has_sse41_(false), | 43 has_sse41_(false), |
| 44 has_sse42_(false), | 44 has_sse42_(false), |
| 45 has_avx_(false), | 45 has_avx_(false), |
| 46 has_avx_hardware_(false), | 46 has_avx_hardware_(false), |
| 47 has_avx2_(false), |
| 47 has_aesni_(false), | 48 has_aesni_(false), |
| 48 has_non_stop_time_stamp_counter_(false), | 49 has_non_stop_time_stamp_counter_(false), |
| 49 has_broken_neon_(false), | 50 has_broken_neon_(false), |
| 50 cpu_vendor_("unknown") { | 51 cpu_vendor_("unknown") { |
| 51 Initialize(); | 52 Initialize(); |
| 52 } | 53 } |
| 53 | 54 |
| 54 namespace { | 55 namespace { |
| 55 | 56 |
| 56 #if defined(ARCH_CPU_X86_FAMILY) | 57 #if defined(ARCH_CPU_X86_FAMILY) |
| 57 #ifndef _MSC_VER | 58 #ifndef _MSC_VER |
| 58 | 59 |
| 59 #if defined(__pic__) && defined(__i386__) | 60 #if defined(__pic__) && defined(__i386__) |
| 60 | 61 |
| 61 void __cpuid(int cpu_info[4], int info_type) { | 62 void __cpuid(int cpu_info[4], int info_type) { |
| 62 __asm__ volatile ( | 63 __asm__ volatile ( |
| 63 "mov %%ebx, %%edi\n" | 64 "mov %%ebx, %%edi\n" |
| 64 "cpuid\n" | 65 "cpuid\n" |
| 65 "xchg %%edi, %%ebx\n" | 66 "xchg %%edi, %%ebx\n" |
| 66 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) | 67 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
| 67 : "a"(info_type) | 68 : "a"(info_type) |
| 68 ); | 69 ); |
| 69 } | 70 } |
| 70 | 71 |
| 71 #else | 72 #else |
| 72 | 73 |
| 73 void __cpuid(int cpu_info[4], int info_type) { | 74 void __cpuid(int cpu_info[4], int info_type) { |
| 74 __asm__ volatile ( | 75 __asm__ volatile ( |
| 75 "cpuid \n\t" | 76 "cpuid\n" |
| 76 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) | 77 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
| 77 : "a"(info_type) | 78 : "a"(info_type) |
| 78 ); | 79 ); |
| 79 } | 80 } |
| 80 | 81 |
| 81 #endif | 82 #endif |
| 82 | 83 |
| 83 // _xgetbv returns the value of an Intel Extended Control Register (XCR). | 84 // _xgetbv returns the value of an Intel Extended Control Register (XCR). |
| 84 // Currently only XCR0 is defined by Intel so |xcr| should always be zero. | 85 // Currently only XCR0 is defined by Intel so |xcr| should always be zero. |
| 85 uint64 _xgetbv(uint32 xcr) { | 86 uint64 _xgetbv(uint32 xcr) { |
| 86 uint32 eax, edx; | 87 uint32 eax, edx; |
| 87 | 88 |
| 88 __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); | 89 __asm__ volatile ( |
| 90 "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); |
| 89 return (static_cast<uint64>(edx) << 32) | eax; | 91 return (static_cast<uint64>(edx) << 32) | eax; |
| 90 } | 92 } |
| 91 | 93 |
| 92 #endif // !_MSC_VER | 94 #endif // !_MSC_VER |
| 93 #endif // ARCH_CPU_X86_FAMILY | 95 #endif // ARCH_CPU_X86_FAMILY |
| 94 | 96 |
| 95 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 97 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| 96 class LazyCpuInfoValue { | 98 class LazyCpuInfoValue { |
| 97 public: | 99 public: |
| 98 LazyCpuInfoValue() : has_broken_neon_(false) { | 100 LazyCpuInfoValue() : has_broken_neon_(false) { |
| 99 // This function finds the value from /proc/cpuinfo under the key "model | 101 // 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 | 102 // 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 | 103 // 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 | 104 // earler versions and is shown only once at the top of /proc/cpuinfo |
| 103 // regardless of the number CPUs. | 105 // regardless of the number CPUs. |
| 104 const char kModelNamePrefix[] = "model name\t: "; | 106 const char kModelNamePrefix[] = "model name\t: "; |
| 105 const char kProcessorPrefix[] = "Processor\t: "; | 107 const char kProcessorPrefix[] = "Processor\t: "; |
| 106 | 108 |
| 107 // This function also calculates whether we believe that this CPU has a | 109 // This function also calculates whether we believe that this CPU has a |
| 108 // broken NEON unit based on these fields from cpuinfo: | 110 // broken NEON unit based on these fields from cpuinfo: |
| 109 unsigned implementer = 0, architecture = 0, variant = 0, part = 0, | 111 unsigned implementer = 0, architecture = 0, variant = 0, part = 0, |
| 110 revision = 0; | 112 revision = 0; |
| 111 const struct { | 113 const struct { |
| 112 const char key[17]; | 114 const char key[17]; |
| 113 unsigned *result; | 115 unsigned int* result; |
| 114 } kUnsignedValues[] = { | 116 } kUnsignedValues[] = { |
| 115 {"CPU implementer", &implementer}, | 117 {"CPU implementer", &implementer}, |
| 116 {"CPU architecture", &architecture}, | 118 {"CPU architecture", &architecture}, |
| 117 {"CPU variant", &variant}, | 119 {"CPU variant", &variant}, |
| 118 {"CPU part", &part}, | 120 {"CPU part", &part}, |
| 119 {"CPU revision", &revision}, | 121 {"CPU revision", &revision}, |
| 120 }; | 122 }; |
| 121 | 123 |
| 122 std::string contents; | 124 std::string contents; |
| 123 ReadFileToString(FilePath("/proc/cpuinfo"), &contents); | 125 ReadFileToString(FilePath("/proc/cpuinfo"), &contents); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 149 | 151 |
| 150 const StringPiece line_sp(line); | 152 const StringPiece line_sp(line); |
| 151 StringPiece value_sp = line_sp.substr(colon_pos + 1); | 153 StringPiece value_sp = line_sp.substr(colon_pos + 1); |
| 152 while (!value_sp.empty() && | 154 while (!value_sp.empty() && |
| 153 (value_sp[0] == ' ' || value_sp[0] == '\t')) { | 155 (value_sp[0] == ' ' || value_sp[0] == '\t')) { |
| 154 value_sp = value_sp.substr(1); | 156 value_sp = value_sp.substr(1); |
| 155 } | 157 } |
| 156 | 158 |
| 157 // The string may have leading "0x" or not, so we use strtoul to | 159 // The string may have leading "0x" or not, so we use strtoul to |
| 158 // handle that. | 160 // handle that. |
| 159 char *endptr; | 161 char* endptr; |
| 160 std::string value(value_sp.as_string()); | 162 std::string value(value_sp.as_string()); |
| 161 unsigned long int result = strtoul(value.c_str(), &endptr, 0); | 163 unsigned long int result = strtoul(value.c_str(), &endptr, 0); |
| 162 if (*endptr == 0 && result <= UINT_MAX) { | 164 if (*endptr == 0 && result <= UINT_MAX) { |
| 163 *kUnsignedValues[i].result = result; | 165 *kUnsignedValues[i].result = result; |
| 164 } | 166 } |
| 165 } | 167 } |
| 166 } | 168 } |
| 167 } | 169 } |
| 168 | 170 |
| 169 has_broken_neon_ = | 171 has_broken_neon_ = |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped | 206 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped |
| 205 // before using memcpy to copy these three array elements to cpu_string. | 207 // before using memcpy to copy these three array elements to cpu_string. |
| 206 __cpuid(cpu_info, 0); | 208 __cpuid(cpu_info, 0); |
| 207 int num_ids = cpu_info[0]; | 209 int num_ids = cpu_info[0]; |
| 208 std::swap(cpu_info[2], cpu_info[3]); | 210 std::swap(cpu_info[2], cpu_info[3]); |
| 209 memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1])); | 211 memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1])); |
| 210 cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1])); | 212 cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1])); |
| 211 | 213 |
| 212 // Interpret CPU feature information. | 214 // Interpret CPU feature information. |
| 213 if (num_ids > 0) { | 215 if (num_ids > 0) { |
| 216 int cpu_info7[4] = {0}; |
| 214 __cpuid(cpu_info, 1); | 217 __cpuid(cpu_info, 1); |
| 218 if (num_ids >= 7) { |
| 219 __cpuid(cpu_info7, 7); |
| 220 } |
| 215 signature_ = cpu_info[0]; | 221 signature_ = cpu_info[0]; |
| 216 stepping_ = cpu_info[0] & 0xf; | 222 stepping_ = cpu_info[0] & 0xf; |
| 217 model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0); | 223 model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0); |
| 218 family_ = (cpu_info[0] >> 8) & 0xf; | 224 family_ = (cpu_info[0] >> 8) & 0xf; |
| 219 type_ = (cpu_info[0] >> 12) & 0x3; | 225 type_ = (cpu_info[0] >> 12) & 0x3; |
| 220 ext_model_ = (cpu_info[0] >> 16) & 0xf; | 226 ext_model_ = (cpu_info[0] >> 16) & 0xf; |
| 221 ext_family_ = (cpu_info[0] >> 20) & 0xff; | 227 ext_family_ = (cpu_info[0] >> 20) & 0xff; |
| 222 has_mmx_ = (cpu_info[3] & 0x00800000) != 0; | 228 has_mmx_ = (cpu_info[3] & 0x00800000) != 0; |
| 223 has_sse_ = (cpu_info[3] & 0x02000000) != 0; | 229 has_sse_ = (cpu_info[3] & 0x02000000) != 0; |
| 224 has_sse2_ = (cpu_info[3] & 0x04000000) != 0; | 230 has_sse2_ = (cpu_info[3] & 0x04000000) != 0; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 237 // In addition, we have observed some crashes with the xgetbv instruction | 243 // In addition, we have observed some crashes with the xgetbv instruction |
| 238 // even after following Intel's example code. (See crbug.com/375968.) | 244 // even after following Intel's example code. (See crbug.com/375968.) |
| 239 // Because of that, we also test the XSAVE bit because its description in | 245 // Because of that, we also test the XSAVE bit because its description in |
| 240 // the CPUID documentation suggests that it signals xgetbv support. | 246 // the CPUID documentation suggests that it signals xgetbv support. |
| 241 has_avx_ = | 247 has_avx_ = |
| 242 has_avx_hardware_ && | 248 has_avx_hardware_ && |
| 243 (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ && | 249 (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ && |
| 244 (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && | 250 (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && |
| 245 (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */; | 251 (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */; |
| 246 has_aesni_ = (cpu_info[2] & 0x02000000) != 0; | 252 has_aesni_ = (cpu_info[2] & 0x02000000) != 0; |
| 253 has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0; |
| 247 } | 254 } |
| 248 | 255 |
| 249 // Get the brand string of the cpu. | 256 // Get the brand string of the cpu. |
| 250 __cpuid(cpu_info, 0x80000000); | 257 __cpuid(cpu_info, 0x80000000); |
| 251 const int parameter_end = 0x80000004; | 258 const int parameter_end = 0x80000004; |
| 252 int max_parameter = cpu_info[0]; | 259 int max_parameter = cpu_info[0]; |
| 253 | 260 |
| 254 if (cpu_info[0] >= parameter_end) { | 261 if (cpu_info[0] >= parameter_end) { |
| 255 char* cpu_string_ptr = cpu_string; | 262 char* cpu_string_ptr = cpu_string; |
| 256 | 263 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 268 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); | 275 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); |
| 269 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; | 276 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; |
| 270 } | 277 } |
| 271 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 278 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
| 272 cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); | 279 cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); |
| 273 has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); | 280 has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); |
| 274 #endif | 281 #endif |
| 275 } | 282 } |
| 276 | 283 |
| 277 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { | 284 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { |
| 285 if (has_avx2()) return AVX2; |
| 278 if (has_avx()) return AVX; | 286 if (has_avx()) return AVX; |
| 279 if (has_sse42()) return SSE42; | 287 if (has_sse42()) return SSE42; |
| 280 if (has_sse41()) return SSE41; | 288 if (has_sse41()) return SSE41; |
| 281 if (has_ssse3()) return SSSE3; | 289 if (has_ssse3()) return SSSE3; |
| 282 if (has_sse3()) return SSE3; | 290 if (has_sse3()) return SSE3; |
| 283 if (has_sse2()) return SSE2; | 291 if (has_sse2()) return SSE2; |
| 284 if (has_sse()) return SSE; | 292 if (has_sse()) return SSE; |
| 285 return PENTIUM; | 293 return PENTIUM; |
| 286 } | 294 } |
| 287 | 295 |
| 288 } // namespace base | 296 } // namespace base |
| OLD | NEW |