1 /* 2 * Copyright 2008 The WebRTC Project Authors. All rights reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/base/systeminfo.h" 12 13 #if defined(WEBRTC_WIN) 14 #include <winsock2.h> 15 #include <windows.h> 16 #ifndef EXCLUDE_D3D9 17 #include <d3d9.h> 18 #endif 19 #include <intrin.h> // for __cpuid() 20 #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 21 #include <ApplicationServices/ApplicationServices.h> 22 #include <CoreServices/CoreServices.h> 23 #elif defined(WEBRTC_LINUX) 24 #include <unistd.h> 25 #endif 26 #if defined(WEBRTC_MAC) 27 #include <sys/sysctl.h> 28 #endif 29 30 #include "webrtc/base/common.h" 31 #include "webrtc/base/logging.h" 32 #include "webrtc/base/stringutils.h" 33 34 namespace rtc { 35 36 // See Also: http://msdn.microsoft.com/en-us/library/ms683194(v=vs.85).aspx 37 #if !defined(WEBRTC_WIN) 38 // TODO(fbarchard): Use gcc 4.4 provided cpuid intrinsic 39 // 32 bit fpic requires ebx be preserved 40 #if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__) 41 static inline void __cpuid(int cpu_info[4], int info_type) { 42 __asm__ volatile ( // NOLINT 43 "mov %%ebx, %%edi\n" 44 "cpuid\n" 45 "xchg %%edi, %%ebx\n" 46 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) 47 : "a"(info_type) 48 ); // NOLINT 49 } 50 #elif defined(__i386__) || defined(__x86_64__) 51 static inline void __cpuid(int cpu_info[4], int info_type) { 52 __asm__ volatile ( // NOLINT 53 "cpuid\n" 54 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) 55 : "a"(info_type) 56 ); // NOLINT 57 } 58 #endif 59 #endif // WEBRTC_WIN 60 61 static int DetectNumberOfCores() { 62 // We fall back on assuming a single core in case of errors. 63 int number_of_cores = 1; 64 65 #if defined(WEBRTC_WIN) 66 SYSTEM_INFO si; 67 GetSystemInfo(&si); 68 number_of_cores = static_cast<int>(si.dwNumberOfProcessors); 69 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) 70 number_of_cores = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN)); 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; 77 } 78 #else 79 LOG(LS_ERROR) << "No function to get number of cores"; 80 #endif 81 82 LOG(LS_INFO) << "Available number of cores: " << number_of_cores; 83 84 return number_of_cores; 85 } 86 87 // Statically cache the number of system cores available since if the process 88 // is running in a sandbox, we may only be able to read the value once (before 89 // the sandbox is initialized) and not thereafter. 90 // For more information see crbug.com/176522. 91 int SystemInfo::logical_cpus_ = 0; 92 93 SystemInfo::SystemInfo() { 94 } 95 96 // Return the number of cpu threads available to the system. 97 // static 98 int SystemInfo::GetMaxCpus() { 99 if (!logical_cpus_) 100 logical_cpus_ = DetectNumberOfCores(); 101 return logical_cpus_; 102 } 103 104 // Return the number of cpus available to the process. Since affinity can be 105 // changed on the fly, do not cache this value. 106 // Can be affected by heat. 107 int SystemInfo::GetCurCpus() { 108 int cur_cpus = 0; 109 #if defined(WEBRTC_WIN) 110 DWORD_PTR process_mask = 0; 111 DWORD_PTR system_mask = 0; 112 ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); 113 for (size_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { 114 if (process_mask & 1) 115 ++cur_cpus; 116 process_mask >>= 1; 117 } 118 #elif defined(WEBRTC_MAC) 119 uint32_t sysctl_value; 120 size_t length = sizeof(sysctl_value); 121 int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); 122 cur_cpus = !error ? static_cast<int>(sysctl_value) : 1; 123 #else 124 // Linux, Solaris, WEBRTC_ANDROID 125 cur_cpus = GetMaxCpus(); 126 #endif 127 return cur_cpus; 128 } 129 130 // Return the type of this CPU. 131 SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { 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 141 } 142 143 // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". 144 // See "Intel Processor Identification and the CPUID Instruction" 145 // (Intel document number: 241618) 146 std::string SystemInfo::GetCpuVendor() { 147 #if defined(CPU_X86) 148 int cpu_info[4]; 149 __cpuid(cpu_info, 0); 150 cpu_info[0] = cpu_info[1]; // Reorder output 151 cpu_info[1] = cpu_info[3]; 152 // cpu_info[2] = cpu_info[2]; // Avoid -Werror=self-assign 153 cpu_info[3] = 0; 154 return std::string(reinterpret_cast<char*>(&cpu_info[0])); 155 #elif defined(CPU_ARM) 156 return "ARM"; 157 #else 158 return "Undefined"; 159 #endif 160 } 161 162 // Returns the amount of installed physical memory in Bytes. Cacheable. 163 // Returns -1 on error. 164 int64_t SystemInfo::GetMemorySize() { 165 int64_t memory = -1; 166 167 #if defined(WEBRTC_WIN) 168 MEMORYSTATUSEX status = {0}; 169 status.dwLength = sizeof(status); 170 171 if (GlobalMemoryStatusEx(&status)) { 172 memory = status.ullTotalPhys; 173 } else { 174 LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; 175 } 176 177 #elif defined(WEBRTC_MAC) 178 size_t len = sizeof(memory); 179 int error = sysctlbyname("hw.memsize", &memory, &len, NULL, 0); 180 if (error || memory == 0) 181 memory = -1; 182 #elif defined(WEBRTC_LINUX) 183 memory = static_cast<int64_t>(sysconf(_SC_PHYS_PAGES)) * 184 static_cast<int64_t>(sysconf(_SC_PAGESIZE)); 185 if (memory < 0) { 186 LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." 187 << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) 188 << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); 189 memory = -1; 190 } 191 #endif 192 193 return memory; 194 } 195 196 // Return the name of the machine model we are currently running on. 197 // This is a human readable string that consists of the name and version 198 // number of the hardware, i.e 'MacBookAir1,1'. Returns an empty string if 199 // model can not be determined. 200 std::string SystemInfo::GetMachineModel() { 201 #if defined(WEBRTC_MAC) 202 char buffer[128]; 203 size_t length = sizeof(buffer); 204 int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); 205 if (!error) 206 return std::string(buffer, length - 1); 207 return std::string(); 208 #else 209 return "Not available"; 210 #endif 211 } 212 213 } // namespace rtc 214