/* * Copyright 2008 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/base/systeminfo.h" #if defined(WEBRTC_WIN) #include #include #ifndef EXCLUDE_D3D9 #include #endif #include // for __cpuid() #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include #include #elif defined(WEBRTC_LINUX) #include #endif #if defined(WEBRTC_MAC) #include #endif #include "webrtc/base/common.h" #include "webrtc/base/logging.h" #include "webrtc/base/stringutils.h" namespace rtc { // See Also: http://msdn.microsoft.com/en-us/library/ms683194(v=vs.85).aspx #if !defined(WEBRTC_WIN) // TODO(fbarchard): Use gcc 4.4 provided cpuid intrinsic // 32 bit fpic requires ebx be preserved #if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__) static inline void __cpuid(int cpu_info[4], int info_type) { __asm__ volatile ( // NOLINT "mov %%ebx, %%edi\n" "cpuid\n" "xchg %%edi, %%ebx\n" : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "a"(info_type) ); // NOLINT } #elif defined(__i386__) || defined(__x86_64__) static inline void __cpuid(int cpu_info[4], int info_type) { __asm__ volatile ( // NOLINT "cpuid\n" : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "a"(info_type) ); // NOLINT } #endif #endif // WEBRTC_WIN static int DetectNumberOfCores() { // We fall back on assuming a single core in case of errors. int number_of_cores = 1; #if defined(WEBRTC_WIN) SYSTEM_INFO si; GetSystemInfo(&si); number_of_cores = static_cast(si.dwNumberOfProcessors); #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) number_of_cores = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #elif defined(WEBRTC_MAC) int name[] = {CTL_HW, HW_AVAILCPU}; size_t size = sizeof(number_of_cores); if (0 != sysctl(name, 2, &number_of_cores, &size, NULL, 0)) { LOG(LS_ERROR) << "Failed to get number of cores"; number_of_cores = 1; } #else LOG(LS_ERROR) << "No function to get number of cores"; #endif LOG(LS_INFO) << "Available number of cores: " << number_of_cores; return number_of_cores; } // Statically cache the number of system cores available since if the process // is running in a sandbox, we may only be able to read the value once (before // the sandbox is initialized) and not thereafter. // For more information see crbug.com/176522. int SystemInfo::logical_cpus_ = 0; SystemInfo::SystemInfo() { } // Return the number of cpu threads available to the system. // static int SystemInfo::GetMaxCpus() { if (!logical_cpus_) logical_cpus_ = DetectNumberOfCores(); return logical_cpus_; } // Return the number of cpus available to the process. Since affinity can be // changed on the fly, do not cache this value. // Can be affected by heat. int SystemInfo::GetCurCpus() { int cur_cpus = 0; #if defined(WEBRTC_WIN) DWORD_PTR process_mask = 0; DWORD_PTR system_mask = 0; ::GetProcessAffinityMask(::GetCurrentProcess(), &process_mask, &system_mask); for (int i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { if (process_mask & 1) ++cur_cpus; process_mask >>= 1; } #elif defined(WEBRTC_MAC) uint32_t sysctl_value; size_t length = sizeof(sysctl_value); int error = sysctlbyname("hw.ncpu", &sysctl_value, &length, NULL, 0); cur_cpus = !error ? static_cast(sysctl_value) : 1; #else // Linux, Solaris, WEBRTC_ANDROID cur_cpus = GetMaxCpus(); #endif return cur_cpus; } // Return the type of this CPU. SystemInfo::Architecture SystemInfo::GetCpuArchitecture() { #if defined(__arm__) || defined(_M_ARM) return SI_ARCH_ARM; #elif defined(__x86_64__) || defined(_M_X64) return SI_ARCH_X64; #elif defined(__i386__) || defined(_M_IX86) return SI_ARCH_X86; #else return SI_ARCH_UNKNOWN; #endif } // Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD". // See "Intel Processor Identification and the CPUID Instruction" // (Intel document number: 241618) std::string SystemInfo::GetCpuVendor() { #if defined(CPU_X86) int cpu_info[4]; __cpuid(cpu_info, 0); cpu_info[0] = cpu_info[1]; // Reorder output cpu_info[1] = cpu_info[3]; // cpu_info[2] = cpu_info[2]; // Avoid -Werror=self-assign cpu_info[3] = 0; return std::string(reinterpret_cast(&cpu_info[0])); #elif defined(CPU_ARM) return "ARM"; #else return "Undefined"; #endif } // Returns the amount of installed physical memory in Bytes. Cacheable. // Returns -1 on error. int64_t SystemInfo::GetMemorySize() { int64_t memory = -1; #if defined(WEBRTC_WIN) MEMORYSTATUSEX status = {0}; status.dwLength = sizeof(status); if (GlobalMemoryStatusEx(&status)) { memory = status.ullTotalPhys; } else { LOG_GLE(LS_WARNING) << "GlobalMemoryStatusEx failed."; } #elif defined(WEBRTC_MAC) size_t len = sizeof(memory); int error = sysctlbyname("hw.memsize", &memory, &len, NULL, 0); if (error || memory == 0) memory = -1; #elif defined(WEBRTC_LINUX) memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); if (memory < 0) { LOG(LS_WARNING) << "sysconf(_SC_PHYS_PAGES) failed." << "sysconf(_SC_PHYS_PAGES) " << sysconf(_SC_PHYS_PAGES) << "sysconf(_SC_PAGESIZE) " << sysconf(_SC_PAGESIZE); memory = -1; } #endif return memory; } // Return the name of the machine model we are currently running on. // This is a human readable string that consists of the name and version // number of the hardware, i.e 'MacBookAir1,1'. Returns an empty string if // model can not be determined. std::string SystemInfo::GetMachineModel() { #if defined(WEBRTC_MAC) char buffer[128]; size_t length = sizeof(buffer); int error = sysctlbyname("hw.model", buffer, &length, NULL, 0); if (!error) return std::string(buffer, length - 1); return std::string(); #else return "Not available"; #endif } } // namespace rtc