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