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
3 // found in the LICENSE file.
4
5 #include "base/cpu.h"
6
7 #include <limits.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <algorithm>
14
15 #include "base/macros.h"
16 #include "base/strings/string_piece.h"
17 #include "build/build_config.h"
18
19 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
20 #include "base/files/file_util.h"
21 #include "base/lazy_instance.h"
22 #endif
23
24 #if defined(ARCH_CPU_X86_FAMILY)
25 #if defined(_MSC_VER)
26 #include <intrin.h>
27 #include <immintrin.h> // For _xgetbv()
28 #endif
29 #endif
30
31 namespace base {
32
CPU()33 CPU::CPU()
34 : signature_(0),
35 type_(0),
36 family_(0),
37 model_(0),
38 stepping_(0),
39 ext_model_(0),
40 ext_family_(0),
41 has_mmx_(false),
42 has_sse_(false),
43 has_sse2_(false),
44 has_sse3_(false),
45 has_ssse3_(false),
46 has_sse41_(false),
47 has_sse42_(false),
48 has_avx_(false),
49 has_avx2_(false),
50 has_aesni_(false),
51 has_non_stop_time_stamp_counter_(false),
52 has_broken_neon_(false),
53 cpu_vendor_("unknown") {
54 Initialize();
55 }
56
57 namespace {
58
59 #if defined(ARCH_CPU_X86_FAMILY)
60 #ifndef _MSC_VER
61
62 #if defined(__pic__) && defined(__i386__)
63
__cpuid(int cpu_info[4],int info_type)64 void __cpuid(int cpu_info[4], int info_type) {
65 __asm__ volatile (
66 "mov %%ebx, %%edi\n"
67 "cpuid\n"
68 "xchg %%edi, %%ebx\n"
69 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
70 : "a"(info_type)
71 );
72 }
73
74 #else
75
76 void __cpuid(int cpu_info[4], int info_type) {
77 __asm__ volatile (
78 "cpuid\n"
79 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
80 : "a"(info_type)
81 );
82 }
83
84 #endif
85
86 // _xgetbv returns the value of an Intel Extended Control Register (XCR).
87 // Currently only XCR0 is defined by Intel so |xcr| should always be zero.
_xgetbv(uint32_t xcr)88 uint64_t _xgetbv(uint32_t xcr) {
89 uint32_t eax, edx;
90
91 __asm__ volatile (
92 "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
93 return (static_cast<uint64_t>(edx) << 32) | eax;
94 }
95
96 #endif // !_MSC_VER
97 #endif // ARCH_CPU_X86_FAMILY
98
99 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
100 class LazyCpuInfoValue {
101 public:
LazyCpuInfoValue()102 LazyCpuInfoValue() : has_broken_neon_(false) {
103 // This function finds the value from /proc/cpuinfo under the key "model
104 // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
105 // and later for arm64) and is shown once per CPU. "Processor" is used in
106 // earler versions and is shown only once at the top of /proc/cpuinfo
107 // regardless of the number CPUs.
108 const char kModelNamePrefix[] = "model name\t: ";
109 const char kProcessorPrefix[] = "Processor\t: ";
110
111 // This function also calculates whether we believe that this CPU has a
112 // broken NEON unit based on these fields from cpuinfo:
113 unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
114 revision = 0;
115 const struct {
116 const char key[17];
117 unsigned int* result;
118 } kUnsignedValues[] = {
119 {"CPU implementer", &implementer},
120 {"CPU architecture", &architecture},
121 {"CPU variant", &variant},
122 {"CPU part", &part},
123 {"CPU revision", &revision},
124 };
125
126 std::string contents;
127 ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
128 DCHECK(!contents.empty());
129 if (contents.empty()) {
130 return;
131 }
132
133 std::istringstream iss(contents);
134 std::string line;
135 while (std::getline(iss, line)) {
136 if (brand_.empty() &&
137 (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 ||
138 line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
139 brand_.assign(line.substr(strlen(kModelNamePrefix)));
140 }
141
142 for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
143 const char *key = kUnsignedValues[i].key;
144 const size_t len = strlen(key);
145
146 if (line.compare(0, len, key) == 0 &&
147 line.size() >= len + 1 &&
148 (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
149 size_t colon_pos = line.find(':', len);
150 if (colon_pos == std::string::npos) {
151 continue;
152 }
153
154 const StringPiece line_sp(line);
155 StringPiece value_sp = line_sp.substr(colon_pos + 1);
156 while (!value_sp.empty() &&
157 (value_sp[0] == ' ' || value_sp[0] == '\t')) {
158 value_sp = value_sp.substr(1);
159 }
160
161 // The string may have leading "0x" or not, so we use strtoul to
162 // handle that.
163 char* endptr;
164 std::string value(value_sp.as_string());
165 unsigned long int result = strtoul(value.c_str(), &endptr, 0);
166 if (*endptr == 0 && result <= UINT_MAX) {
167 *kUnsignedValues[i].result = result;
168 }
169 }
170 }
171 }
172
173 has_broken_neon_ =
174 implementer == 0x51 &&
175 architecture == 7 &&
176 variant == 1 &&
177 part == 0x4d &&
178 revision == 0;
179 }
180
brand() const181 const std::string& brand() const { return brand_; }
has_broken_neon() const182 bool has_broken_neon() const { return has_broken_neon_; }
183
184 private:
185 std::string brand_;
186 bool has_broken_neon_;
187 DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
188 };
189
190 base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo =
191 LAZY_INSTANCE_INITIALIZER;
192
193 #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
194 // defined(OS_LINUX))
195
196 } // anonymous namespace
197
Initialize()198 void CPU::Initialize() {
199 #if defined(ARCH_CPU_X86_FAMILY)
200 int cpu_info[4] = {-1};
201 char cpu_string[48];
202
203 // __cpuid with an InfoType argument of 0 returns the number of
204 // valid Ids in CPUInfo[0] and the CPU identification string in
205 // the other three array elements. The CPU identification string is
206 // not in linear order. The code below arranges the information
207 // in a human readable form. The human readable order is CPUInfo[1] |
208 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
209 // before using memcpy to copy these three array elements to cpu_string.
210 __cpuid(cpu_info, 0);
211 int num_ids = cpu_info[0];
212 std::swap(cpu_info[2], cpu_info[3]);
213 memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1]));
214 cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1]));
215
216 // Interpret CPU feature information.
217 if (num_ids > 0) {
218 int cpu_info7[4] = {0};
219 __cpuid(cpu_info, 1);
220 if (num_ids >= 7) {
221 __cpuid(cpu_info7, 7);
222 }
223 signature_ = cpu_info[0];
224 stepping_ = cpu_info[0] & 0xf;
225 model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
226 family_ = (cpu_info[0] >> 8) & 0xf;
227 type_ = (cpu_info[0] >> 12) & 0x3;
228 ext_model_ = (cpu_info[0] >> 16) & 0xf;
229 ext_family_ = (cpu_info[0] >> 20) & 0xff;
230 has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
231 has_sse_ = (cpu_info[3] & 0x02000000) != 0;
232 has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
233 has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
234 has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
235 has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
236 has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
237 // AVX instructions will generate an illegal instruction exception unless
238 // a) they are supported by the CPU,
239 // b) XSAVE is supported by the CPU and
240 // c) XSAVE is enabled by the kernel.
241 // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
242 //
243 // In addition, we have observed some crashes with the xgetbv instruction
244 // even after following Intel's example code. (See crbug.com/375968.)
245 // Because of that, we also test the XSAVE bit because its description in
246 // the CPUID documentation suggests that it signals xgetbv support.
247 has_avx_ =
248 (cpu_info[2] & 0x10000000) != 0 &&
249 (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
250 (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
251 (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
252 has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
253 has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
254 }
255
256 // Get the brand string of the cpu.
257 __cpuid(cpu_info, 0x80000000);
258 const int parameter_end = 0x80000004;
259 int max_parameter = cpu_info[0];
260
261 if (cpu_info[0] >= parameter_end) {
262 char* cpu_string_ptr = cpu_string;
263
264 for (int parameter = 0x80000002; parameter <= parameter_end &&
265 cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) {
266 __cpuid(cpu_info, parameter);
267 memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info));
268 cpu_string_ptr += sizeof(cpu_info);
269 }
270 cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string);
271 }
272
273 const int parameter_containing_non_stop_time_stamp_counter = 0x80000007;
274 if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) {
275 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
276 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
277 }
278 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
279 cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
280 has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
281 #endif
282 }
283
GetIntelMicroArchitecture() const284 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
285 if (has_avx2()) return AVX2;
286 if (has_avx()) return AVX;
287 if (has_sse42()) return SSE42;
288 if (has_sse41()) return SSE41;
289 if (has_ssse3()) return SSSE3;
290 if (has_sse3()) return SSE3;
291 if (has_sse2()) return SSE2;
292 if (has_sse()) return SSE;
293 return PENTIUM;
294 }
295
296 } // namespace base
297