OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2008 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2008 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/base/systeminfo.h" | 11 #include "webrtc/base/systeminfo.h" |
12 | 12 |
13 #if defined(WEBRTC_WIN) | 13 #if defined(WEBRTC_WIN) |
14 #include <winsock2.h> | 14 #include <winsock2.h> |
15 #include <windows.h> | |
15 #ifndef EXCLUDE_D3D9 | 16 #ifndef EXCLUDE_D3D9 |
16 #include <d3d9.h> | 17 #include <d3d9.h> |
17 #endif | 18 #endif |
18 #include <intrin.h> // for __cpuid() | 19 #include <intrin.h> // for __cpuid() |
19 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | 20 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) |
20 #include <ApplicationServices/ApplicationServices.h> | 21 #include <ApplicationServices/ApplicationServices.h> |
21 #include <CoreServices/CoreServices.h> | 22 #include <CoreServices/CoreServices.h> |
22 #elif defined(WEBRTC_LINUX) | 23 #elif defined(WEBRTC_LINUX) |
23 #include <unistd.h> | 24 #include <unistd.h> |
24 #endif | 25 #endif |
25 #if defined(WEBRTC_MAC) | 26 #if defined(WEBRTC_MAC) |
26 #include <sys/sysctl.h> | 27 #include <sys/sysctl.h> |
27 #endif | 28 #endif |
28 | 29 |
29 #if defined(WEBRTC_WIN) | |
30 #include "webrtc/base/scoped_ptr.h" | |
31 #include "webrtc/base/win32.h" | |
32 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | |
33 #include "webrtc/base/macconversion.h" | |
34 #elif defined(WEBRTC_LINUX) | |
35 #include "webrtc/base/linux.h" | |
36 #endif | |
37 #include "webrtc/base/common.h" | 30 #include "webrtc/base/common.h" |
38 #include "webrtc/base/logging.h" | 31 #include "webrtc/base/logging.h" |
39 #include "webrtc/base/stringutils.h" | 32 #include "webrtc/base/stringutils.h" |
40 | 33 |
41 namespace rtc { | 34 namespace rtc { |
42 | 35 |
43 // See Also: http://msdn.microsoft.com/en-us/library/ms683194(v=vs.85).aspx | 36 // See Also: http://msdn.microsoft.com/en-us/library/ms683194(v=vs.85).aspx |
44 #if defined(WEBRTC_WIN) | 37 #if !defined(WEBRTC_WIN) |
45 typedef BOOL (WINAPI *LPFN_GLPI)( | |
46 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, | |
47 PDWORD); | |
48 | |
49 static void GetProcessorInformation(int* physical_cpus, int* cache_size) { | |
50 // GetLogicalProcessorInformation() is available on Windows XP SP3 and beyond. | |
51 LPFN_GLPI glpi = reinterpret_cast<LPFN_GLPI>(GetProcAddress( | |
52 GetModuleHandle(L"kernel32"), | |
53 "GetLogicalProcessorInformation")); | |
54 if (NULL == glpi) { | |
55 return; | |
56 } | |
57 // Determine buffer size, allocate and get processor information. | |
58 // Size can change between calls (unlikely), so a loop is done. | |
59 DWORD return_length = 0; | |
60 scoped_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> infos; | |
61 while (!glpi(infos.get(), &return_length)) { | |
62 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | |
63 infos.reset(new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[ | |
64 return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)]); | |
65 } else { | |
66 return; | |
67 } | |
68 } | |
69 *physical_cpus = 0; | |
70 *cache_size = 0; | |
71 for (size_t i = 0; | |
72 i < return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) { | |
73 if (infos[i].Relationship == RelationProcessorCore) { | |
74 ++*physical_cpus; | |
75 } else if (infos[i].Relationship == RelationCache) { | |
76 int next_cache_size = static_cast<int>(infos[i].Cache.Size); | |
77 if (next_cache_size >= *cache_size) { | |
78 *cache_size = next_cache_size; | |
79 } | |
80 } | |
81 } | |
82 return; | |
83 } | |
84 #else | |
85 // TODO(fbarchard): Use gcc 4.4 provided cpuid intrinsic | 38 // TODO(fbarchard): Use gcc 4.4 provided cpuid intrinsic |
86 // 32 bit fpic requires ebx be preserved | 39 // 32 bit fpic requires ebx be preserved |
87 #if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__) | 40 #if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__) |
88 static inline void __cpuid(int cpu_info[4], int info_type) { | 41 static inline void __cpuid(int cpu_info[4], int info_type) { |
89 __asm__ volatile ( // NOLINT | 42 __asm__ volatile ( // NOLINT |
90 "mov %%ebx, %%edi\n" | 43 "mov %%ebx, %%edi\n" |
91 "cpuid\n" | 44 "cpuid\n" |
92 "xchg %%edi, %%ebx\n" | 45 "xchg %%edi, %%ebx\n" |
93 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) | 46 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
94 : "a"(info_type) | 47 : "a"(info_type) |
95 ); // NOLINT | 48 ); // NOLINT |
96 } | 49 } |
97 #elif defined(__i386__) || defined(__x86_64__) | 50 #elif defined(__i386__) || defined(__x86_64__) |
98 static inline void __cpuid(int cpu_info[4], int info_type) { | 51 static inline void __cpuid(int cpu_info[4], int info_type) { |
99 __asm__ volatile ( // NOLINT | 52 __asm__ volatile ( // NOLINT |
100 "cpuid\n" | 53 "cpuid\n" |
101 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) | 54 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
102 : "a"(info_type) | 55 : "a"(info_type) |
103 ); // NOLINT | 56 ); // NOLINT |
104 } | 57 } |
105 #endif | 58 #endif |
106 #endif // WEBRTC_WIN | 59 #endif // WEBRTC_WIN |
107 | 60 |
108 // Note(fbarchard): | 61 static int DetectNumberOfCores() { |
109 // Family and model are extended family and extended model. 8 bits each. | 62 // We fall back on assuming a single core in case of errors. |
110 SystemInfo::SystemInfo() | 63 int number_of_cores = 1; |
111 : physical_cpus_(1), logical_cpus_(1), cache_size_(0), | |
112 cpu_family_(0), cpu_model_(0), cpu_stepping_(0), | |
113 cpu_speed_(0), memory_(0) { | |
114 // Initialize the basic information. | |
115 #if defined(__arm__) || defined(_M_ARM) | |
116 cpu_arch_ = SI_ARCH_ARM; | |
117 #elif defined(__x86_64__) || defined(_M_X64) | |
118 cpu_arch_ = SI_ARCH_X64; | |
119 #elif defined(__i386__) || defined(_M_IX86) | |
120 cpu_arch_ = SI_ARCH_X86; | |
121 #else | |
122 cpu_arch_ = SI_ARCH_UNKNOWN; | |
123 #endif | |
124 | 64 |
125 #if defined(WEBRTC_WIN) | 65 #if defined(WEBRTC_WIN) |
126 SYSTEM_INFO si; | 66 SYSTEM_INFO si; |
127 GetSystemInfo(&si); | 67 GetSystemInfo(&si); |
128 logical_cpus_ = si.dwNumberOfProcessors; | 68 number_of_cores = static_cast<int>(si.dwNumberOfProcessors); |
129 GetProcessorInformation(&physical_cpus_, &cache_size_); | 69 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) |
130 if (physical_cpus_ <= 0) { | 70 number_of_cores = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN)); |
131 physical_cpus_ = logical_cpus_; | 71 #elif defined(WEBRTC_MAC) |
72 int name[] = {CTL_HW, HW_AVAILCPU}; | |
73 size_t size = sizeof(number_of_cores); | |
74 if (0 != sysctl(name, 2, &number_of_cores, &size, NULL, 0)) { | |
75 LOG(LS_ERROR) << "Failed to get number of cores"; | |
76 number_of_cores = 1; | |
132 } | 77 } |
133 cpu_family_ = si.wProcessorLevel; | 78 #else |
134 cpu_model_ = si.wProcessorRevision >> 8; | 79 LOG(LS_ERROR) << "No function to get number of cores"; |
135 cpu_stepping_ = si.wProcessorRevision & 0xFF; | |
136 #elif defined(WEBRTC_MAC) | |
137 uint32_t sysctl_value; | |
138 size_t length = sizeof(sysctl_value); | |
139 if (!sysctlbyname("hw.physicalcpu_max", &sysctl_value, &length, NULL, 0)) { | |
140 physical_cpus_ = static_cast<int>(sysctl_value); | |
141 } | |
142 length = sizeof(sysctl_value); | |
143 if (!sysctlbyname("hw.logicalcpu_max", &sysctl_value, &length, NULL, 0)) { | |
144 logical_cpus_ = static_cast<int>(sysctl_value); | |
145 } | |
146 uint64_t sysctl_value64; | |
147 length = sizeof(sysctl_value64); | |
148 if (!sysctlbyname("hw.l3cachesize", &sysctl_value64, &length, NULL, 0)) { | |
149 cache_size_ = static_cast<int>(sysctl_value64); | |
150 } | |
151 if (!cache_size_) { | |
152 length = sizeof(sysctl_value64); | |
153 if (!sysctlbyname("hw.l2cachesize", &sysctl_value64, &length, NULL, 0)) { | |
154 cache_size_ = static_cast<int>(sysctl_value64); | |
155 } | |
156 } | |
157 length = sizeof(sysctl_value); | |
158 if (!sysctlbyname("machdep.cpu.family", &sysctl_value, &length, NULL, 0)) { | |
159 cpu_family_ = static_cast<int>(sysctl_value); | |
160 } | |
161 length = sizeof(sysctl_value); | |
162 if (!sysctlbyname("machdep.cpu.model", &sysctl_value, &length, NULL, 0)) { | |
163 cpu_model_ = static_cast<int>(sysctl_value); | |
164 } | |
165 length = sizeof(sysctl_value); | |
166 if (!sysctlbyname("machdep.cpu.stepping", &sysctl_value, &length, NULL, 0)) { | |
167 cpu_stepping_ = static_cast<int>(sysctl_value); | |
168 } | |
169 #elif defined(__native_client__) | |
170 // TODO(ryanpetrie): Implement this via PPAPI when it's available. | |
171 #else // WEBRTC_LINUX | |
172 ProcCpuInfo proc_info; | |
173 if (proc_info.LoadFromSystem()) { | |
174 proc_info.GetNumCpus(&logical_cpus_); | |
175 proc_info.GetNumPhysicalCpus(&physical_cpus_); | |
176 proc_info.GetCpuFamily(&cpu_family_); | |
177 #if defined(CPU_X86) | |
178 // These values only apply to x86 systems. | |
179 proc_info.GetSectionIntValue(0, "model", &cpu_model_); | |
180 proc_info.GetSectionIntValue(0, "stepping", &cpu_stepping_); | |
181 proc_info.GetSectionIntValue(0, "cpu MHz", &cpu_speed_); | |
182 proc_info.GetSectionIntValue(0, "cache size", &cache_size_); | |
183 cache_size_ *= 1024; | |
184 #endif | 80 #endif |
185 } | 81 |
186 // ProcCpuInfo reads cpu speed from "cpu MHz" under /proc/cpuinfo. | 82 LOG(LS_INFO) << "Available number of cores: " << number_of_cores; |
187 // But that number is a moving target which can change on-the-fly according to | 83 |
188 // many factors including system workload. | 84 return number_of_cores; |
189 // See /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors. | 85 } |
190 // The one in /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq is more | 86 |
191 // accurate. We use it as our cpu speed when it is available. | 87 // Statically cache the number of system cores available since if the process |
192 // cpuinfo_max_freq is measured in KHz and requires conversion to MHz. | 88 // is running in a sandbox, we may only be able to read the value once (before |
193 int max_freq = rtc::ReadCpuMaxFreq(); | 89 // the sandbox is initialized) and not thereafter. |
194 if (max_freq > 0) { | 90 // For more information see crbug.com/176522. |
195 cpu_speed_ = max_freq / 1000; | 91 int SystemInfo::logical_cpus_ = 0; |
196 } | 92 |
197 #endif | 93 SystemInfo::SystemInfo() { |
198 // For L2 CacheSize see also | |
199 // http://www.flounder.com/cpuid_explorer2.htm#CPUID(0x800000006) | |
200 #ifdef CPU_X86 | |
201 if (cache_size_ == 0) { | |
202 int cpu_info[4]; | |
203 __cpuid(cpu_info, 0x80000000); // query maximum extended cpuid function. | |
204 if (static_cast<uint32>(cpu_info[0]) >= 0x80000006) { | |
205 __cpuid(cpu_info, 0x80000006); | |
206 cache_size_ = (cpu_info[2] >> 16) * 1024; | |
207 } | |
208 } | |
209 #endif | |
210 } | 94 } |
211 | 95 |
212 // Return the number of cpu threads available to the system. | 96 // Return the number of cpu threads available to the system. |
97 // static | |
213 int SystemInfo::GetMaxCpus() { | 98 int SystemInfo::GetMaxCpus() { |
99 if (!logical_cpus_) | |
magjed_webrtc
2015/08/20 08:04:26
thread safe?
tommi (sloooow) - chröme
2015/08/20 08:16:19
No :( But that behavior is not introduced in this
| |
100 logical_cpus_ = DetectNumberOfCores(); | |
214 return logical_cpus_; | 101 return logical_cpus_; |
215 } | 102 } |
216 | 103 |
217 // Return the number of cpu cores available to the system. | |
218 int SystemInfo::GetMaxPhysicalCpus() { | |
219 return physical_cpus_; | |
220 } | |
221 | |
222 // Return the number of cpus available to the process. Since affinity can be | 104 // Return the number of cpus available to the process. Since affinity can be |
223 // changed on the fly, do not cache this value. | 105 // changed on the fly, do not cache this value. |
224 // Can be affected by heat. | 106 // Can be affected by heat. |
225 int SystemInfo::GetCurCpus() { | 107 int SystemInfo::GetCurCpus() { |
226 int cur_cpus; | 108 int cur_cpus = 0; |
227 #if defined(WEBRTC_WIN) | 109 #if defined(WEBRTC_WIN) |
228 DWORD_PTR process_mask, system_mask; | 110 DWORD_PTR process_mask = 0, system_mask = 0; |
magjed_webrtc
2015/08/20 08:04:26
One declaration per line?
tommi (sloooow) - chröme
2015/08/20 08:16:19
Done.
| |
229 ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); | 111 ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); |
230 for (cur_cpus = 0; process_mask; ++cur_cpus) { | 112 for (int i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { |
231 // Sparse-ones algorithm. There are slightly faster methods out there but | 113 if (process_mask & 1) |
232 // they are unintuitive and won't make a difference on a single dword. | 114 ++cur_cpus; |
233 process_mask &= (process_mask - 1); | 115 process_mask >>= 1; |
234 } | 116 } |
235 #elif defined(WEBRTC_MAC) | 117 #elif defined(WEBRTC_MAC) |
236 uint32_t sysctl_value; | 118 uint32_t sysctl_value; |
237 size_t length = sizeof(sysctl_value); | 119 size_t length = sizeof(sysctl_value); |
238 int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); | 120 int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); |
239 cur_cpus = !error ? static_cast<int>(sysctl_value) : 1; | 121 cur_cpus = !error ? static_cast<int>(sysctl_value) : 1; |
240 #else | 122 #else |
241 // Linux, Solaris, WEBRTC_ANDROID | 123 // Linux, Solaris, WEBRTC_ANDROID |
242 cur_cpus = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN)); | 124 cur_cpus = GetMaxCpus(); |
243 #endif | 125 #endif |
244 return cur_cpus; | 126 return cur_cpus; |
245 } | 127 } |
246 | 128 |
247 // Return the type of this CPU. | 129 // Return the type of this CPU. |
248 SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { | 130 SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { |
249 return cpu_arch_; | 131 #if defined(__arm__) || defined(_M_ARM) |
132 return SI_ARCH_ARM; | |
133 #elif defined(__x86_64__) || defined(_M_X64) | |
134 return SI_ARCH_X64; | |
135 #elif defined(__i386__) || defined(_M_IX86) | |
136 return SI_ARCH_X86; | |
137 #else | |
138 return SI_ARCH_UNKNOWN; | |
139 #endif | |
250 } | 140 } |
251 | 141 |
252 // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". | 142 // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". |
253 // See "Intel Processor Identification and the CPUID Instruction" | 143 // See "Intel Processor Identification and the CPUID Instruction" |
254 // (Intel document number: 241618) | 144 // (Intel document number: 241618) |
255 std::string SystemInfo::GetCpuVendor() { | 145 std::string SystemInfo::GetCpuVendor() { |
256 if (cpu_vendor_.empty()) { | 146 std::string cpu_vendor; |
magjed_webrtc
2015/08/20 08:04:26
Remove this and just return the strings directly i
tommi (sloooow) - chröme
2015/08/20 08:16:19
Done.
| |
257 #if defined(CPU_X86) | 147 #if defined(CPU_X86) |
258 int cpu_info[4]; | 148 int cpu_info[4]; |
259 __cpuid(cpu_info, 0); | 149 __cpuid(cpu_info, 0); |
260 cpu_info[0] = cpu_info[1]; // Reorder output | 150 cpu_info[0] = cpu_info[1]; // Reorder output |
261 cpu_info[1] = cpu_info[3]; | 151 cpu_info[1] = cpu_info[3]; |
262 // cpu_info[2] = cpu_info[2]; // Avoid -Werror=self-assign | 152 // cpu_info[2] = cpu_info[2]; // Avoid -Werror=self-assign |
263 cpu_info[3] = 0; | 153 cpu_info[3] = 0; |
264 cpu_vendor_ = std::string(reinterpret_cast<char*>(&cpu_info[0])); | 154 cpu_vendor = reinterpret_cast<char*>(&cpu_info[0]); |
265 #elif defined(CPU_ARM) | 155 #elif defined(CPU_ARM) |
266 cpu_vendor_ = std::string("ARM"); | 156 cpu_vendor = "ARM"; |
267 #else | 157 #else |
268 cpu_vendor_ = std::string("Undefined"); | 158 cpu_vendor = "Undefined"; |
269 #endif | 159 #endif |
270 } | 160 return cpu_vendor; |
271 return cpu_vendor_; | |
272 } | |
273 | |
274 int SystemInfo::GetCpuCacheSize() { | |
275 return cache_size_; | |
276 } | |
277 | |
278 // Return the "family" of this CPU. | |
279 int SystemInfo::GetCpuFamily() { | |
280 return cpu_family_; | |
281 } | |
282 | |
283 // Return the "model" of this CPU. | |
284 int SystemInfo::GetCpuModel() { | |
285 return cpu_model_; | |
286 } | |
287 | |
288 // Return the "stepping" of this CPU. | |
289 int SystemInfo::GetCpuStepping() { | |
290 return cpu_stepping_; | |
291 } | |
292 | |
293 // Return the clockrate of the primary processor in Mhz. This value can be | |
294 // cached. Returns -1 on error. | |
295 int SystemInfo::GetMaxCpuSpeed() { | |
296 if (cpu_speed_) { | |
297 return cpu_speed_; | |
298 } | |
299 #if defined(WEBRTC_WIN) | |
300 HKEY key; | |
301 static const WCHAR keyName[] = | |
302 L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; | |
303 | |
304 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key) | |
305 == ERROR_SUCCESS) { | |
306 DWORD data, len; | |
307 len = sizeof(data); | |
308 | |
309 if (RegQueryValueEx(key, L"~Mhz", 0, 0, reinterpret_cast<LPBYTE>(&data), | |
310 &len) == ERROR_SUCCESS) { | |
311 cpu_speed_ = data; | |
312 } else { | |
313 LOG(LS_WARNING) << "Failed to query registry value HKLM\\" << keyName | |
314 << "\\~Mhz"; | |
315 cpu_speed_ = -1; | |
316 } | |
317 | |
318 RegCloseKey(key); | |
319 } else { | |
320 LOG(LS_WARNING) << "Failed to open registry key HKLM\\" << keyName; | |
321 cpu_speed_ = -1; | |
322 } | |
323 #elif defined(WEBRTC_MAC) | |
324 uint64_t sysctl_value; | |
325 size_t length = sizeof(sysctl_value); | |
326 int error = sysctlbyname("hw.cpufrequency_max", &sysctl_value, &length, | |
327 NULL, 0); | |
328 cpu_speed_ = !error ? static_cast<int>(sysctl_value/1000000) : -1; | |
329 #else | |
330 // TODO(fbarchard): Implement using proc/cpuinfo | |
331 cpu_speed_ = 0; | |
332 #endif | |
333 return cpu_speed_; | |
334 } | |
335 | |
336 // Dynamically check the current clockrate, which could be reduced because of | |
337 // powersaving profiles. Eventually for windows we want to query WMI for | |
338 // root\WMI::ProcessorPerformance.InstanceName="Processor_Number_0".frequency | |
339 int SystemInfo::GetCurCpuSpeed() { | |
340 #if defined(WEBRTC_WIN) | |
341 // TODO(fbarchard): Add WMI check, requires COM initialization | |
342 // NOTE(fbarchard): Testable on Sandy Bridge. | |
343 return GetMaxCpuSpeed(); | |
344 #elif defined(WEBRTC_MAC) | |
345 uint64_t sysctl_value; | |
346 size_t length = sizeof(sysctl_value); | |
347 int error = sysctlbyname("hw.cpufrequency", &sysctl_value, &length, NULL, 0); | |
348 return !error ? static_cast<int>(sysctl_value/1000000) : GetMaxCpuSpeed(); | |
349 #else // WEBRTC_LINUX | |
350 // TODO(fbarchard): Use proc/cpuinfo for Cur speed on Linux. | |
351 return GetMaxCpuSpeed(); | |
352 #endif | |
353 } | 161 } |
354 | 162 |
355 // Returns the amount of installed physical memory in Bytes. Cacheable. | 163 // Returns the amount of installed physical memory in Bytes. Cacheable. |
356 // Returns -1 on error. | 164 // Returns -1 on error. |
357 int64 SystemInfo::GetMemorySize() { | 165 int64 SystemInfo::GetMemorySize() { |
358 if (memory_) { | 166 int64 memory = -1; |
359 return memory_; | |
360 } | |
361 | 167 |
362 #if defined(WEBRTC_WIN) | 168 #if defined(WEBRTC_WIN) |
363 MEMORYSTATUSEX status = {0}; | 169 MEMORYSTATUSEX status = {0}; |
364 status.dwLength = sizeof(status); | 170 status.dwLength = sizeof(status); |
365 | 171 |
366 if (GlobalMemoryStatusEx(&status)) { | 172 if (GlobalMemoryStatusEx(&status)) { |
367 memory_ = status.ullTotalPhys; | 173 memory = status.ullTotalPhys; |
368 } else { | 174 } else { |
369 LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; | 175 LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; |
370 memory_ = -1; | |
371 } | 176 } |
372 | 177 |
373 #elif defined(WEBRTC_MAC) | 178 #elif defined(WEBRTC_MAC) |
374 size_t len = sizeof(memory_); | 179 size_t len = sizeof(memory); |
375 int error = sysctlbyname("hw.memsize", &memory_, &len, NULL, 0); | 180 int error = sysctlbyname("hw.memsize", &memory, &len, NULL, 0); |
376 if (error || memory_ == 0) { | 181 if (error || memory == 0) |
377 memory_ = -1; | 182 memory = -1; |
378 } | |
379 #else // WEBRTC_LINUX | 183 #else // WEBRTC_LINUX |
380 memory_ = static_cast<int64>(sysconf(_SC_PHYS_PAGES)) * | 184 memory = static_cast<int64>(sysconf(_SC_PHYS_PAGES)) * |
381 static_cast<int64>(sysconf(_SC_PAGESIZE)); | 185 static_cast<int64>(sysconf(_SC_PAGESIZE)); |
382 if (memory_ < 0) { | 186 if (memory < 0) { |
383 LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." | 187 LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." |
384 << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) | 188 << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) |
385 << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); | 189 << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); |
386 memory_ = -1; | 190 memory = -1; |
387 } | 191 } |
388 #endif | 192 #endif |
389 | 193 |
390 return memory_; | 194 return memory; |
391 } | 195 } |
392 | 196 |
393 | |
394 // Return the name of the machine model we are currently running on. | 197 // Return the name of the machine model we are currently running on. |
395 // This is a human readable string that consists of the name and version | 198 // This is a human readable string that consists of the name and version |
396 // number of the hardware, i.e 'MacBookAir1,1'. Returns an empty string if | 199 // number of the hardware, i.e 'MacBookAir1,1'. Returns an empty string if |
397 // model can not be determined. The string is cached for subsequent calls. | 200 // model can not be determined. |
398 std::string SystemInfo::GetMachineModel() { | 201 std::string SystemInfo::GetMachineModel() { |
399 if (!machine_model_.empty()) { | |
400 return machine_model_; | |
401 } | |
402 | |
403 #if defined(WEBRTC_MAC) | 202 #if defined(WEBRTC_MAC) |
404 char buffer[128]; | 203 char buffer[128]; |
405 size_t length = sizeof(buffer); | 204 size_t length = sizeof(buffer); |
406 int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); | 205 int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); |
407 if (!error) { | 206 if (!error) |
408 machine_model_.assign(buffer, length - 1); | 207 return std::string(buffer, length - 1); |
409 } else { | 208 return std::string(); |
410 machine_model_.clear(); | |
411 } | |
412 #else | 209 #else |
413 machine_model_ = "Not available"; | 210 return "Not available"; |
414 #endif | 211 #endif |
415 | |
416 return machine_model_; | |
417 } | 212 } |
418 | 213 |
419 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | |
420 // Helper functions to query IOKit for video hardware properties. | |
421 static CFTypeRef SearchForProperty(io_service_t port, CFStringRef name) { | |
422 return IORegistryEntrySearchCFProperty(port, kIOServicePlane, | |
423 name, kCFAllocatorDefault, | |
424 kIORegistryIterateRecursively | kIORegistryIterateParents); | |
425 } | |
426 | |
427 static void GetProperty(io_service_t port, CFStringRef name, int* value) { | |
428 if (!value) return; | |
429 CFTypeRef ref = SearchForProperty(port, name); | |
430 if (ref) { | |
431 CFTypeID refType = CFGetTypeID(ref); | |
432 if (CFNumberGetTypeID() == refType) { | |
433 CFNumberRef number = reinterpret_cast<CFNumberRef>(ref); | |
434 p_convertCFNumberToInt(number, value); | |
435 } else if (CFDataGetTypeID() == refType) { | |
436 CFDataRef data = reinterpret_cast<CFDataRef>(ref); | |
437 if (CFDataGetLength(data) == sizeof(UInt32)) { | |
438 *value = *reinterpret_cast<const UInt32*>(CFDataGetBytePtr(data)); | |
439 } | |
440 } | |
441 CFRelease(ref); | |
442 } | |
443 } | |
444 | |
445 static void GetProperty(io_service_t port, CFStringRef name, | |
446 std::string* value) { | |
447 if (!value) return; | |
448 CFTypeRef ref = SearchForProperty(port, name); | |
449 if (ref) { | |
450 CFTypeID refType = CFGetTypeID(ref); | |
451 if (CFStringGetTypeID() == refType) { | |
452 CFStringRef stringRef = reinterpret_cast<CFStringRef>(ref); | |
453 p_convertHostCFStringRefToCPPString(stringRef, *value); | |
454 } else if (CFDataGetTypeID() == refType) { | |
455 CFDataRef dataRef = reinterpret_cast<CFDataRef>(ref); | |
456 *value = std::string(reinterpret_cast<const char*>( | |
457 CFDataGetBytePtr(dataRef)), CFDataGetLength(dataRef)); | |
458 } | |
459 CFRelease(ref); | |
460 } | |
461 } | |
462 #endif | |
463 | |
464 SystemInfo::GpuInfo::GpuInfo() : vendor_id(0), device_id(0) { | |
465 } | |
466 | |
467 SystemInfo::GpuInfo::~GpuInfo() = default; | |
468 | |
469 // Fills a struct with information on the graphics adapater and returns true | |
470 // iff successful. | |
471 bool SystemInfo::GetGpuInfo(GpuInfo *info) { | |
472 if (!info) return false; | |
473 #if defined(WEBRTC_WIN) && !defined(EXCLUDE_D3D9) | |
474 D3DADAPTER_IDENTIFIER9 identifier; | |
475 HRESULT hr = E_FAIL; | |
476 HINSTANCE d3d_lib = LoadLibrary(L"d3d9.dll"); | |
477 | |
478 if (d3d_lib) { | |
479 typedef IDirect3D9* (WINAPI *D3DCreate9Proc)(UINT); | |
480 D3DCreate9Proc d3d_create_proc = reinterpret_cast<D3DCreate9Proc>( | |
481 GetProcAddress(d3d_lib, "Direct3DCreate9")); | |
482 if (d3d_create_proc) { | |
483 IDirect3D9* d3d = d3d_create_proc(D3D_SDK_VERSION); | |
484 if (d3d) { | |
485 hr = d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); | |
486 d3d->Release(); | |
487 } | |
488 } | |
489 FreeLibrary(d3d_lib); | |
490 } | |
491 | |
492 if (hr != D3D_OK) { | |
493 LOG(LS_ERROR) << "Failed to access Direct3D9 information."; | |
494 return false; | |
495 } | |
496 | |
497 info->device_name = identifier.DeviceName; | |
498 info->description = identifier.Description; | |
499 info->vendor_id = identifier.VendorId; | |
500 info->device_id = identifier.DeviceId; | |
501 info->driver = identifier.Driver; | |
502 // driver_version format: product.version.subversion.build | |
503 std::stringstream ss; | |
504 ss << HIWORD(identifier.DriverVersion.HighPart) << "." | |
505 << LOWORD(identifier.DriverVersion.HighPart) << "." | |
506 << HIWORD(identifier.DriverVersion.LowPart) << "." | |
507 << LOWORD(identifier.DriverVersion.LowPart); | |
508 info->driver_version = ss.str(); | |
509 return true; | |
510 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | |
511 // We'll query the IOKit for the gpu of the main display. | |
512 io_service_t display_service_port = CGDisplayIOServicePort( | |
513 kCGDirectMainDisplay); | |
514 GetProperty(display_service_port, CFSTR("vendor-id"), &info->vendor_id); | |
515 GetProperty(display_service_port, CFSTR("device-id"), &info->device_id); | |
516 GetProperty(display_service_port, CFSTR("model"), &info->description); | |
517 return true; | |
518 #else // WEBRTC_LINUX | |
519 // TODO(fbarchard): Implement this on Linux | |
520 return false; | |
521 #endif | |
522 } | |
523 } // namespace rtc | 214 } // namespace rtc |
OLD | NEW |