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" |
12 #include "build/build_config.h" | 13 #include "build/build_config.h" |
13 | 14 |
14 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 15 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
15 #include "base/file_util.h" | 16 #include "base/file_util.h" |
16 #include "base/lazy_instance.h" | 17 #include "base/lazy_instance.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
37 has_sse_(false), | 38 has_sse_(false), |
38 has_sse2_(false), | 39 has_sse2_(false), |
39 has_sse3_(false), | 40 has_sse3_(false), |
40 has_ssse3_(false), | 41 has_ssse3_(false), |
41 has_sse41_(false), | 42 has_sse41_(false), |
42 has_sse42_(false), | 43 has_sse42_(false), |
43 has_avx_(false), | 44 has_avx_(false), |
44 has_avx_hardware_(false), | 45 has_avx_hardware_(false), |
45 has_aesni_(false), | 46 has_aesni_(false), |
46 has_non_stop_time_stamp_counter_(false), | 47 has_non_stop_time_stamp_counter_(false), |
48 has_broken_neon_(false), | |
47 cpu_vendor_("unknown") { | 49 cpu_vendor_("unknown") { |
48 Initialize(); | 50 Initialize(); |
49 } | 51 } |
50 | 52 |
51 namespace { | 53 namespace { |
52 | 54 |
53 #if defined(ARCH_CPU_X86_FAMILY) | 55 #if defined(ARCH_CPU_X86_FAMILY) |
54 #ifndef _MSC_VER | 56 #ifndef _MSC_VER |
55 | 57 |
56 #if defined(__pic__) && defined(__i386__) | 58 #if defined(__pic__) && defined(__i386__) |
(...skipping 26 matching lines...) Expand all Loading... | |
83 uint32 eax, edx; | 85 uint32 eax, edx; |
84 | 86 |
85 __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); | 87 __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); |
86 return (static_cast<uint64>(edx) << 32) | eax; | 88 return (static_cast<uint64>(edx) << 32) | eax; |
87 } | 89 } |
88 | 90 |
89 #endif // !_MSC_VER | 91 #endif // !_MSC_VER |
90 #endif // ARCH_CPU_X86_FAMILY | 92 #endif // ARCH_CPU_X86_FAMILY |
91 | 93 |
92 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 94 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
95 class LazyCpuInfoValue { | |
96 public: | |
97 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.
| |
98 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 std::string value = line.substr(colon_pos + 1); | |
151 while (!value.empty() && (value[0] == ' ' || value[0] == '\t')) { | |
152 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,
| |
153 } | |
154 | |
155 // The string may have leading "0x" or not, so we use strtoul to | |
156 // handle that. | |
157 char *endptr; | |
158 unsigned long int result = strtoul(value.c_str(), &endptr, 0); | |
159 if (*endptr == 0 && result <= UINT_MAX) { | |
160 *kUnsignedValues[i].result = result; | |
161 } | |
162 } | |
116 } | 163 } |
117 } | 164 } |
165 | |
166 has_broken_neon_ = | |
167 implementer == 0x51 && | |
168 architecture == 7 && | |
169 variant == 1 && | |
170 part == 0x4d && | |
171 revision == 0; | |
118 } | 172 } |
119 return cpu_brand; | |
120 } | |
121 | 173 |
122 class LazyCpuInfoValue { | 174 const std::string& brand() const { return brand_; } |
123 public: | 175 bool has_broken_neon() const { return has_broken_neon_; } |
124 LazyCpuInfoValue() : value_(ParseCpuInfo()) {} | |
125 const std::string& value() { return value_; } | |
126 | 176 |
127 private: | 177 private: |
128 const std::string value_; | 178 std::string brand_; |
179 bool has_broken_neon_; | |
129 DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); | 180 DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); |
130 }; | 181 }; |
131 | 182 |
132 base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand = | 183 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.
| |
133 LAZY_INSTANCE_INITIALIZER; | 184 LAZY_INSTANCE_INITIALIZER; |
134 | 185 |
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) || | 186 #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || |
140 // defined(OS_LINUX)) | 187 // defined(OS_LINUX)) |
141 | 188 |
142 } // anonymous namespace | 189 } // anonymous namespace |
143 | 190 |
144 void CPU::Initialize() { | 191 void CPU::Initialize() { |
145 #if defined(ARCH_CPU_X86_FAMILY) | 192 #if defined(ARCH_CPU_X86_FAMILY) |
146 int cpu_info[4] = {-1}; | 193 int cpu_info[4] = {-1}; |
147 char cpu_string[48]; | 194 char cpu_string[48]; |
148 | 195 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 } | 259 } |
213 cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string); | 260 cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string); |
214 } | 261 } |
215 | 262 |
216 const int parameter_containing_non_stop_time_stamp_counter = 0x80000007; | 263 const int parameter_containing_non_stop_time_stamp_counter = 0x80000007; |
217 if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) { | 264 if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) { |
218 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); | 265 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); |
219 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; | 266 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; |
220 } | 267 } |
221 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) | 268 #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) |
222 cpu_brand_.assign(CpuBrandInfo()); | 269 cpu_brand_.assign(g_lazy_cpuinfo.Get().brand()); |
270 has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon(); | |
223 #endif | 271 #endif |
224 } | 272 } |
225 | 273 |
226 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { | 274 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { |
227 if (has_avx()) return AVX; | 275 if (has_avx()) return AVX; |
228 if (has_sse42()) return SSE42; | 276 if (has_sse42()) return SSE42; |
229 if (has_sse41()) return SSE41; | 277 if (has_sse41()) return SSE41; |
230 if (has_ssse3()) return SSSE3; | 278 if (has_ssse3()) return SSSE3; |
231 if (has_sse3()) return SSE3; | 279 if (has_sse3()) return SSE3; |
232 if (has_sse2()) return SSE2; | 280 if (has_sse2()) return SSE2; |
233 if (has_sse()) return SSE; | 281 if (has_sse()) return SSE; |
234 return PENTIUM; | 282 return PENTIUM; |
235 } | 283 } |
236 | 284 |
237 } // namespace base | 285 } // namespace base |
OLD | NEW |