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 |