| 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_) |
| 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; |
| 111 DWORD_PTR system_mask = 0; |
| 229 ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); | 112 ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); |
| 230 for (cur_cpus = 0; process_mask; ++cur_cpus) { | 113 for (int i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { |
| 231 // Sparse-ones algorithm. There are slightly faster methods out there but | 114 if (process_mask & 1) |
| 232 // they are unintuitive and won't make a difference on a single dword. | 115 ++cur_cpus; |
| 233 process_mask &= (process_mask - 1); | 116 process_mask >>= 1; |
| 234 } | 117 } |
| 235 #elif defined(WEBRTC_MAC) | 118 #elif defined(WEBRTC_MAC) |
| 236 uint32_t sysctl_value; | 119 uint32_t sysctl_value; |
| 237 size_t length = sizeof(sysctl_value); | 120 size_t length = sizeof(sysctl_value); |
| 238 int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); | 121 int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); |
| 239 cur_cpus = !error ? static_cast<int>(sysctl_value) : 1; | 122 cur_cpus = !error ? static_cast<int>(sysctl_value) : 1; |
| 240 #else | 123 #else |
| 241 // Linux, Solaris, WEBRTC_ANDROID | 124 // Linux, Solaris, WEBRTC_ANDROID |
| 242 cur_cpus = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN)); | 125 cur_cpus = GetMaxCpus(); |
| 243 #endif | 126 #endif |
| 244 return cur_cpus; | 127 return cur_cpus; |
| 245 } | 128 } |
| 246 | 129 |
| 247 // Return the type of this CPU. | 130 // Return the type of this CPU. |
| 248 SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { | 131 SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { |
| 249 return cpu_arch_; | 132 #if defined(__arm__) || defined(_M_ARM) |
| 133 return SI_ARCH_ARM; |
| 134 #elif defined(__x86_64__) || defined(_M_X64) |
| 135 return SI_ARCH_X64; |
| 136 #elif defined(__i386__) || defined(_M_IX86) |
| 137 return SI_ARCH_X86; |
| 138 #else |
| 139 return SI_ARCH_UNKNOWN; |
| 140 #endif |
| 250 } | 141 } |
| 251 | 142 |
| 252 // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". | 143 // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". |
| 253 // See "Intel Processor Identification and the CPUID Instruction" | 144 // See "Intel Processor Identification and the CPUID Instruction" |
| 254 // (Intel document number: 241618) | 145 // (Intel document number: 241618) |
| 255 std::string SystemInfo::GetCpuVendor() { | 146 std::string SystemInfo::GetCpuVendor() { |
| 256 if (cpu_vendor_.empty()) { | |
| 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 return std::string(reinterpret_cast<char*>(&cpu_info[0])); |
| 265 #elif defined(CPU_ARM) | 155 #elif defined(CPU_ARM) |
| 266 cpu_vendor_ = std::string("ARM"); | 156 return "ARM"; |
| 267 #else | 157 #else |
| 268 cpu_vendor_ = std::string("Undefined"); | 158 return "Undefined"; |
| 269 #endif | |
| 270 } | |
| 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 | 159 #endif |
| 353 } | 160 } |
| 354 | 161 |
| 355 // Returns the amount of installed physical memory in Bytes. Cacheable. | 162 // Returns the amount of installed physical memory in Bytes. Cacheable. |
| 356 // Returns -1 on error. | 163 // Returns -1 on error. |
| 357 int64 SystemInfo::GetMemorySize() { | 164 int64 SystemInfo::GetMemorySize() { |
| 358 if (memory_) { | 165 int64 memory = -1; |
| 359 return memory_; | |
| 360 } | |
| 361 | 166 |
| 362 #if defined(WEBRTC_WIN) | 167 #if defined(WEBRTC_WIN) |
| 363 MEMORYSTATUSEX status = {0}; | 168 MEMORYSTATUSEX status = {0}; |
| 364 status.dwLength = sizeof(status); | 169 status.dwLength = sizeof(status); |
| 365 | 170 |
| 366 if (GlobalMemoryStatusEx(&status)) { | 171 if (GlobalMemoryStatusEx(&status)) { |
| 367 memory_ = status.ullTotalPhys; | 172 memory = status.ullTotalPhys; |
| 368 } else { | 173 } else { |
| 369 LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; | 174 LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; |
| 370 memory_ = -1; | |
| 371 } | 175 } |
| 372 | 176 |
| 373 #elif defined(WEBRTC_MAC) | 177 #elif defined(WEBRTC_MAC) |
| 374 size_t len = sizeof(memory_); | 178 size_t len = sizeof(memory); |
| 375 int error = sysctlbyname("hw.memsize", &memory_, &len, NULL, 0); | 179 int error = sysctlbyname("hw.memsize", &memory, &len, NULL, 0); |
| 376 if (error || memory_ == 0) { | 180 if (error || memory == 0) |
| 377 memory_ = -1; | 181 memory = -1; |
| 378 } | |
| 379 #else // WEBRTC_LINUX | 182 #else // WEBRTC_LINUX |
| 380 memory_ = static_cast<int64>(sysconf(_SC_PHYS_PAGES)) * | 183 memory = static_cast<int64>(sysconf(_SC_PHYS_PAGES)) * |
| 381 static_cast<int64>(sysconf(_SC_PAGESIZE)); | 184 static_cast<int64>(sysconf(_SC_PAGESIZE)); |
| 382 if (memory_ < 0) { | 185 if (memory < 0) { |
| 383 LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." | 186 LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." |
| 384 << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) | 187 << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) |
| 385 << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); | 188 << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); |
| 386 memory_ = -1; | 189 memory = -1; |
| 387 } | 190 } |
| 388 #endif | 191 #endif |
| 389 | 192 |
| 390 return memory_; | 193 return memory; |
| 391 } | 194 } |
| 392 | 195 |
| 393 | |
| 394 // Return the name of the machine model we are currently running on. | 196 // 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 | 197 // 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 | 198 // 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. | 199 // model can not be determined. |
| 398 std::string SystemInfo::GetMachineModel() { | 200 std::string SystemInfo::GetMachineModel() { |
| 399 if (!machine_model_.empty()) { | |
| 400 return machine_model_; | |
| 401 } | |
| 402 | |
| 403 #if defined(WEBRTC_MAC) | 201 #if defined(WEBRTC_MAC) |
| 404 char buffer[128]; | 202 char buffer[128]; |
| 405 size_t length = sizeof(buffer); | 203 size_t length = sizeof(buffer); |
| 406 int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); | 204 int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); |
| 407 if (!error) { | 205 if (!error) |
| 408 machine_model_.assign(buffer, length - 1); | 206 return std::string(buffer, length - 1); |
| 409 } else { | 207 return std::string(); |
| 410 machine_model_.clear(); | |
| 411 } | |
| 412 #else | 208 #else |
| 413 machine_model_ = "Not available"; | 209 return "Not available"; |
| 414 #endif | 210 #endif |
| 415 | |
| 416 return machine_model_; | |
| 417 } | 211 } |
| 418 | 212 |
| 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 | 213 } // namespace rtc |
| OLD | NEW |