Home | History | Annotate | Download | only in base
      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