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__)
__cpuid(int cpu_info[4],int info_type)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
DetectNumberOfCores()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
SystemInfo()93 SystemInfo::SystemInfo() {
94 }
95
96 // Return the number of cpu threads available to the system.
97 // static
GetMaxCpus()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.
GetCurCpus()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.
GetCpuArchitecture()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)
GetCpuVendor()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.
GetMemorySize()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.
GetMachineModel()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