• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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