blob: 2b9d7b174136f4962d5da5498e4f47d5f152554a [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#if defined(_WIN32)
#define NOMINMAX // use our min,max
#if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
#define _WIN32_WINNT 0x0501
#endif
#include <winsock.h> // WSADATA, include before sys/types.h
#endif
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
// TODO:
// We need an alternative implementation for many functions in this file
// when USE_ASM_INSTRUCTIONS gets defined as 0.
//
// Consider using these on Win32/Win64 for some of them:
//
// IsProcessorFeaturePresent
// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
//
// GetProcessMemoryInfo
// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
#include "kwsysPrivate.h"
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
#include "Process.h.in"
#include "SystemInformation.hxx.in"
#endif
#include <algorithm>
#include <bitset>
#include <cassert>
#include <fstream>
#include <iostream>
#include <limits>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#if defined(_WIN32)
#include <windows.h>
#if defined(_MSC_VER) && _MSC_VER >= 1800
#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
#endif
#include <errno.h>
#if defined(KWSYS_SYS_HAS_PSAPI)
#include <psapi.h>
#endif
#if !defined(siginfo_t)
typedef int siginfo_t;
#endif
#else
#include <sys/types.h>
#include <errno.h> // extern int errno;
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h> // getrlimit
#include <sys/time.h>
#include <sys/utsname.h> // int uname(struct utsname *buf);
#include <unistd.h>
#endif
#if defined(__CYGWIN__) && !defined(_WIN32)
#include <windows.h>
#undef _WIN32
#endif
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__DragonFly__)
#include <netdb.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
#include <net/if.h>
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
#endif
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
#include <machine/cpu.h>
#endif
#ifdef __APPLE__
#include <fenv.h>
#include <mach/host_info.h>
#include <mach/mach.h>
#include <mach/mach_types.h>
#include <mach/vm_statistics.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
#include <net/if.h>
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
#if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050)
#undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
#endif
#endif
#if defined(__linux) || defined(__sun) || defined(_SCO_DS)
#include <fenv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
#include <net/if.h>
#if defined(__LSB_VERSION__)
/* LSB has no getifaddrs */
#elif defined(__ANDROID_API__) && __ANDROID_API__ < 24
/* Android has no getifaddrs prior to API 24. */
#else
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
#endif
#if defined(KWSYS_CXX_HAS_RLIMIT64)
typedef struct rlimit64 ResourceLimitType;
#define GetResourceLimit getrlimit64
#else
typedef struct rlimit ResourceLimitType;
#define GetResourceLimit getrlimit
#endif
#elif defined(__hpux)
#include <sys/param.h>
#include <sys/pstat.h>
#if defined(KWSYS_SYS_HAS_MPCTL_H)
#include <sys/mpctl.h>
#endif
#endif
#ifdef __HAIKU__
#include <OS.h>
#endif
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
#include <execinfo.h>
#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
#include <cxxabi.h>
#endif
#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
#include <dlfcn.h>
#endif
#else
#undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
#undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
#endif
#include <ctype.h> // int isdigit(int c);
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(KWSYS_USE_LONG_LONG)
#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
#define iostreamLongLong(x) (x)
#else
#define iostreamLongLong(x) ((long)(x))
#endif
#elif defined(KWSYS_USE___INT64)
#if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
#define iostreamLongLong(x) (x)
#else
#define iostreamLongLong(x) ((long)(x))
#endif
#else
#error "No Long Long"
#endif
#if defined(KWSYS_CXX_HAS_ATOLL)
#define atoLongLong atoll
#else
#if defined(KWSYS_CXX_HAS__ATOI64)
#define atoLongLong _atoi64
#elif defined(KWSYS_CXX_HAS_ATOL)
#define atoLongLong atol
#else
#define atoLongLong atoi
#endif
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \
!defined(__clang__)
#define USE_ASM_INSTRUCTIONS 1
#else
#define USE_ASM_INSTRUCTIONS 0
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
#include <intrin.h>
#define USE_CPUID_INTRINSICS 1
#else
#define USE_CPUID_INTRINSICS 0
#endif
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || \
defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
#define USE_CPUID 1
#else
#define USE_CPUID 0
#endif
#if USE_CPUID
#define CPUID_AWARE_COMPILER
/**
* call CPUID instruction
*
* Will return false if the instruction failed.
*/
static bool call_cpuid(int select, int result[4])
{
#if USE_CPUID_INTRINSICS
__cpuid(result, select);
return true;
#else
int tmp[4];
#if defined(_MSC_VER)
// Use SEH to determine CPUID presence
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser does not know about <<CPUID>>, and so does not expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
mov eax, select
#ifdef CPUID_AWARE_COMPILER
cpuid
#else
_asm _emit 0x0f
_asm _emit 0xa2
#endif
mov tmp[0 * TYPE int], eax
mov tmp[1 * TYPE int], ebx
mov tmp[2 * TYPE int], ecx
mov tmp[3 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
} __except (1) {
return false;
}
memcpy(result, tmp, sizeof(tmp));
#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
unsigned int a, b, c, d;
__asm {
mov EAX, select;
cpuid
mov a, EAX;
mov b, EBX;
mov c, ECX;
mov d, EDX;
}
result[0] = a;
result[1] = b;
result[2] = c;
result[3] = d;
#endif
// The cpuid instruction succeeded.
return true;
#endif
}
#endif
namespace KWSYS_NAMESPACE {
template <typename T>
T min(T a, T b)
{
return a < b ? a : b;
}
extern "C" {
typedef void (*SigAction)(int, siginfo_t*, void*);
}
// Define SystemInformationImplementation class
typedef void (*DELAY_FUNC)(unsigned int uiMS);
class SystemInformationImplementation
{
public:
typedef SystemInformation::LongLong LongLong;
SystemInformationImplementation();
~SystemInformationImplementation();
const char* GetVendorString();
const char* GetVendorID();
std::string GetTypeID();
std::string GetFamilyID();
std::string GetModelID();
std::string GetModelName();
std::string GetSteppingCode();
const char* GetExtendedProcessorName();
const char* GetProcessorSerialNumber();
int GetProcessorCacheSize();
unsigned int GetLogicalProcessorsPerPhysical();
float GetProcessorClockFrequency();
int GetProcessorAPICID();
int GetProcessorCacheXSize(long int);
bool DoesCPUSupportFeature(long int);
const char* GetOSName();
const char* GetHostname();
int GetFullyQualifiedDomainName(std::string& fqdn);
const char* GetOSRelease();
const char* GetOSVersion();
const char* GetOSPlatform();
bool Is64Bits();
unsigned int GetNumberOfLogicalCPU(); // per physical cpu
unsigned int GetNumberOfPhysicalCPU();
bool DoesCPUSupportCPUID();
// Retrieve memory information in MiB.
size_t GetTotalVirtualMemory();
size_t GetAvailableVirtualMemory();
size_t GetTotalPhysicalMemory();
size_t GetAvailablePhysicalMemory();
LongLong GetProcessId();
// Retrieve memory information in KiB.
LongLong GetHostMemoryTotal();
LongLong GetHostMemoryAvailable(const char* envVarName);
LongLong GetHostMemoryUsed();
LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName,
const char* procLimitEnvVarName);
LongLong GetProcMemoryUsed();
double GetLoadAverage();
// enable/disable stack trace signal handler.
static void SetStackTraceOnError(int enable);
// get current stack
static std::string GetProgramStack(int firstFrame, int wholePath);
/** Run the different checks */
void RunCPUCheck();
void RunOSCheck();
void RunMemoryCheck();
public:
typedef struct tagID
{
int Type;
int Family;
int Model;
int Revision;
int ExtendedFamily;
int ExtendedModel;
std::string ProcessorName;
std::string Vendor;
std::string SerialNumber;
std::string ModelName;
} ID;
typedef struct tagCPUPowerManagement
{
bool HasVoltageID;
bool HasFrequencyID;
bool HasTempSenseDiode;
} CPUPowerManagement;
typedef struct tagCPUExtendedFeatures
{
bool Has3DNow;
bool Has3DNowPlus;
bool SupportsMP;
bool HasMMXPlus;
bool HasSSEMMX;
unsigned int LogicalProcessorsPerPhysical;
int APIC_ID;
CPUPowerManagement PowerManagement;
} CPUExtendedFeatures;
typedef struct CPUtagFeatures
{
bool HasFPU;
bool HasTSC;
bool HasMMX;
bool HasSSE;
bool HasSSEFP;
bool HasSSE2;
bool HasIA64;
bool HasAPIC;
bool HasCMOV;
bool HasMTRR;
bool HasACPI;
bool HasSerial;
bool HasThermal;
int CPUSpeed;
int L1CacheSize;
int L2CacheSize;
int L3CacheSize;
CPUExtendedFeatures ExtendedFeatures;
} CPUFeatures;
enum Manufacturer
{
AMD,
Intel,
NSC,
UMC,
Cyrix,
NexGen,
IDT,
Rise,
Transmeta,
Sun,
IBM,
Motorola,
HP,
UnknownManufacturer
};
protected:
// For windows
bool RetrieveCPUFeatures();
bool RetrieveCPUIdentity();
bool RetrieveCPUCacheDetails();
bool RetrieveClassicalCPUCacheDetails();
bool RetrieveCPUClockSpeed();
bool RetrieveClassicalCPUClockSpeed();
bool RetrieveCPUExtendedLevelSupport(int);
bool RetrieveExtendedCPUFeatures();
bool RetrieveProcessorSerialNumber();
bool RetrieveCPUPowerManagement();
bool RetrieveClassicalCPUIdentity();
bool RetrieveExtendedCPUIdentity();
// Processor information
Manufacturer ChipManufacturer;
CPUFeatures Features;
ID ChipID;
float CPUSpeedInMHz;
unsigned int NumberOfLogicalCPU;
unsigned int NumberOfPhysicalCPU;
void CPUCountWindows(); // For windows
unsigned char GetAPICId(); // For windows
bool IsSMTSupported();
static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows
// For Linux and Cygwin, /proc/cpuinfo formats are slightly different
bool RetreiveInformationFromCpuInfoFile();
std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
size_t init = 0);
bool QueryLinuxMemory();
bool QueryCygwinMemory();
static void Delay(unsigned int);
static void DelayOverhead(unsigned int);
void FindManufacturer(const std::string& family = "");
// For Mac
bool ParseSysCtl();
int CallSwVers(const char* arg, std::string& ver);
void TrimNewline(std::string&);
std::string ExtractValueFromSysCtl(const char* word);
std::string SysCtlBuffer;
// For Solaris
bool QuerySolarisMemory();
bool QuerySolarisProcessor();
std::string ParseValueFromKStat(const char* arguments);
std::string RunProcess(std::vector<const char*> args);
// For Haiku OS
bool QueryHaikuInfo();
// For QNX
bool QueryQNXMemory();
bool QueryQNXProcessor();
// For OpenBSD, FreeBSD, NetBSD, DragonFly
bool QueryBSDMemory();
bool QueryBSDProcessor();
// For HP-UX
bool QueryHPUXMemory();
bool QueryHPUXProcessor();
// For Microsoft Windows
bool QueryWindowsMemory();
// For AIX
bool QueryAIXMemory();
bool QueryProcessorBySysconf();
bool QueryProcessor();
// Evaluate the memory information.
bool QueryMemoryBySysconf();
bool QueryMemory();
size_t TotalVirtualMemory;
size_t AvailableVirtualMemory;
size_t TotalPhysicalMemory;
size_t AvailablePhysicalMemory;
size_t CurrentPositionInFile;
// Operating System information
bool QueryOSInformation();
std::string OSName;
std::string Hostname;
std::string OSRelease;
std::string OSVersion;
std::string OSPlatform;
bool OSIs64Bit;
};
SystemInformation::SystemInformation()
{
this->Implementation = new SystemInformationImplementation;
}
SystemInformation::~SystemInformation()
{
delete this->Implementation;
}
const char* SystemInformation::GetVendorString()
{
return this->Implementation->GetVendorString();
}
const char* SystemInformation::GetVendorID()
{
return this->Implementation->GetVendorID();
}
std::string SystemInformation::GetTypeID()
{
return this->Implementation->GetTypeID();
}
std::string SystemInformation::GetFamilyID()
{
return this->Implementation->GetFamilyID();
}
std::string SystemInformation::GetModelID()
{
return this->Implementation->GetModelID();
}
std::string SystemInformation::GetModelName()
{
return this->Implementation->GetModelName();
}
std::string SystemInformation::GetSteppingCode()
{
return this->Implementation->GetSteppingCode();
}
const char* SystemInformation::GetExtendedProcessorName()
{
return this->Implementation->GetExtendedProcessorName();
}
const char* SystemInformation::GetProcessorSerialNumber()
{
return this->Implementation->GetProcessorSerialNumber();
}
int SystemInformation::GetProcessorCacheSize()
{
return this->Implementation->GetProcessorCacheSize();
}
unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
{
return this->Implementation->GetLogicalProcessorsPerPhysical();
}
float SystemInformation::GetProcessorClockFrequency()
{
return this->Implementation->GetProcessorClockFrequency();
}
int SystemInformation::GetProcessorAPICID()
{
return this->Implementation->GetProcessorAPICID();
}
int SystemInformation::GetProcessorCacheXSize(long int l)
{
return this->Implementation->GetProcessorCacheXSize(l);
}
bool SystemInformation::DoesCPUSupportFeature(long int i)
{
return this->Implementation->DoesCPUSupportFeature(i);
}
std::string SystemInformation::GetCPUDescription()
{
std::ostringstream oss;
oss << this->GetNumberOfPhysicalCPU() << " core ";
if (this->GetModelName().empty()) {
oss << this->GetProcessorClockFrequency() << " MHz "
<< this->GetVendorString() << " " << this->GetExtendedProcessorName();
} else {
oss << this->GetModelName();
}
// remove extra spaces
std::string tmp = oss.str();
size_t pos;
while ((pos = tmp.find(" ")) != std::string::npos) {
tmp.replace(pos, 2, " ");
}
return tmp;
}
const char* SystemInformation::GetOSName()
{
return this->Implementation->GetOSName();
}
const char* SystemInformation::GetHostname()
{
return this->Implementation->GetHostname();
}
std::string SystemInformation::GetFullyQualifiedDomainName()
{
std::string fqdn;
this->Implementation->GetFullyQualifiedDomainName(fqdn);
return fqdn;
}
const char* SystemInformation::GetOSRelease()
{
return this->Implementation->GetOSRelease();
}
const char* SystemInformation::GetOSVersion()
{
return this->Implementation->GetOSVersion();
}
const char* SystemInformation::GetOSPlatform()
{
return this->Implementation->GetOSPlatform();
}
int SystemInformation::GetOSIsWindows()
{
#if defined(_WIN32)
return 1;
#else
return 0;
#endif
}
int SystemInformation::GetOSIsLinux()
{
#if defined(__linux)
return 1;
#else
return 0;
#endif
}
int SystemInformation::GetOSIsApple()
{
#if defined(__APPLE__)
return 1;
#else
return 0;
#endif
}
std::string SystemInformation::GetOSDescription()
{
std::ostringstream oss;
oss << this->GetOSName() << " " << this->GetOSRelease() << " "
<< this->GetOSVersion();
return oss.str();
}
bool SystemInformation::Is64Bits()
{
return this->Implementation->Is64Bits();
}
unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
{
return this->Implementation->GetNumberOfLogicalCPU();
}
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
return this->Implementation->GetNumberOfPhysicalCPU();
}
bool SystemInformation::DoesCPUSupportCPUID()
{
return this->Implementation->DoesCPUSupportCPUID();
}
// Retrieve memory information in MiB.
size_t SystemInformation::GetTotalVirtualMemory()
{
return this->Implementation->GetTotalVirtualMemory();
}
size_t SystemInformation::GetAvailableVirtualMemory()
{
return this->Implementation->GetAvailableVirtualMemory();
}
size_t SystemInformation::GetTotalPhysicalMemory()
{
return this->Implementation->GetTotalPhysicalMemory();
}
size_t SystemInformation::GetAvailablePhysicalMemory()
{
return this->Implementation->GetAvailablePhysicalMemory();
}
std::string SystemInformation::GetMemoryDescription(
const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
{
std::ostringstream oss;
oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal())
<< " KiB, Host Available: "
<< iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
<< " KiB, Process Available: "
<< iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName,
procLimitEnvVarName))
<< " KiB";
return oss.str();
}
// host memory info in units of KiB.
SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
{
return this->Implementation->GetHostMemoryTotal();
}
SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable(
const char* hostLimitEnvVarName)
{
return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
}
SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
{
return this->Implementation->GetHostMemoryUsed();
}
// process memory info in units of KiB.
SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable(
const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
{
return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName,
procLimitEnvVarName);
}
SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
{
return this->Implementation->GetProcMemoryUsed();
}
double SystemInformation::GetLoadAverage()
{
return this->Implementation->GetLoadAverage();
}
SystemInformation::LongLong SystemInformation::GetProcessId()
{
return this->Implementation->GetProcessId();
}
void SystemInformation::SetStackTraceOnError(int enable)
{
SystemInformationImplementation::SetStackTraceOnError(enable);
}
std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
{
return SystemInformationImplementation::GetProgramStack(firstFrame,
wholePath);
}
/** Run the different checks */
void SystemInformation::RunCPUCheck()
{
this->Implementation->RunCPUCheck();
}
void SystemInformation::RunOSCheck()
{
this->Implementation->RunOSCheck();
}
void SystemInformation::RunMemoryCheck()
{
this->Implementation->RunMemoryCheck();
}
// SystemInformationImplementation starts here
#define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x
#define TLBCACHE_INFO_UNITS (15)
#define CLASSICAL_CPU_FREQ_LOOP 10000000
#define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
// Status Flag
#define HT_NOT_CAPABLE 0
#define HT_ENABLED 1
#define HT_DISABLED 2
#define HT_SUPPORTED_NOT_ENABLED 3
#define HT_CANNOT_DETECT 4
// EDX[28] Bit 28 is set if HT is supported
#define HT_BIT 0x10000000
// EAX[11:8] Bit 8-11 contains family processor ID.
#define FAMILY_ID 0x0F00
#define PENTIUM4_ID 0x0F00
// EAX[23:20] Bit 20-23 contains extended family processor ID
#define EXT_FAMILY_ID 0x0F00000
// EBX[23:16] Bit 16-23 in ebx contains the number of logical
#define NUM_LOGICAL_BITS 0x00FF0000
// processors per physical processor when execute cpuid with
// eax set to 1
// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
#define INITIAL_APIC_ID_BITS 0xFF000000
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported
// Hide implementation details in an anonymous namespace.
namespace {
// *****************************************************************************
#if defined(__linux) || defined(__APPLE__)
int LoadLines(FILE* file, std::vector<std::string>& lines)
{
// Load each line in the given file into a the vector.
int nRead = 0;
const int bufSize = 1024;
char buf[bufSize] = { '\0' };
while (!feof(file) && !ferror(file)) {
errno = 0;
if (fgets(buf, bufSize, file) == KWSYS_NULLPTR) {
if (ferror(file) && (errno == EINTR)) {
clearerr(file);
}
continue;
}
char* pBuf = buf;
while (*pBuf) {
if (*pBuf == '\n')
*pBuf = '\0';
pBuf += 1;
}
lines.push_back(buf);
++nRead;
}
if (ferror(file)) {
return 0;
}
return nRead;
}
#if defined(__linux)
// *****************************************************************************
int LoadLines(const char* fileName, std::vector<std::string>& lines)
{
FILE* file = fopen(fileName, "r");
if (file == 0) {
return 0;
}
int nRead = LoadLines(file, lines);
fclose(file);
return nRead;
}
#endif
// ****************************************************************************
template <typename T>
int NameValue(std::vector<std::string> const& lines, std::string const& name,
T& value)
{
size_t nLines = lines.size();
for (size_t i = 0; i < nLines; ++i) {
size_t at = lines[i].find(name);
if (at == std::string::npos) {
continue;
}
std::istringstream is(lines[i].substr(at + name.size()));
is >> value;
return 0;
}
return -1;
}
#endif
#if defined(__linux)
// ****************************************************************************
template <typename T>
int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values)
{
std::vector<std::string> fields;
if (!LoadLines(fileName, fields)) {
return -1;
}
int i = 0;
while (fieldNames[i] != NULL) {
int ierr = NameValue(fields, fieldNames[i], values[i]);
if (ierr) {
return -(i + 2);
}
i += 1;
}
return 0;
}
// ****************************************************************************
template <typename T>
int GetFieldFromFile(const char* fileName, const char* fieldName, T& value)
{
const char* fieldNames[2] = { fieldName, NULL };
T values[1] = { T(0) };
int ierr = GetFieldsFromFile(fileName, fieldNames, values);
if (ierr) {
return ierr;
}
value = values[0];
return 0;
}
#endif
// ****************************************************************************
#if defined(__APPLE__)
template <typename T>
int GetFieldsFromCommand(const char* command, const char** fieldNames,
T* values)
{
FILE* file = popen(command, "r");
if (file == KWSYS_NULLPTR) {
return -1;
}
std::vector<std::string> fields;
int nl = LoadLines(file, fields);
pclose(file);
if (nl == 0) {
return -1;
}
int i = 0;
while (fieldNames[i] != KWSYS_NULLPTR) {
int ierr = NameValue(fields, fieldNames[i], values[i]);
if (ierr) {
return -(i + 2);
}
i += 1;
}
return 0;
}
#endif
// ****************************************************************************
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo,
void* /*sigContext*/)
{
#if defined(__linux) || defined(__APPLE__)
std::ostringstream oss;
oss << std::endl
<< "========================================================="
<< std::endl
<< "Process id " << getpid() << " ";
switch (sigNo) {
case SIGINT:
oss << "Caught SIGINT";
break;
case SIGTERM:
oss << "Caught SIGTERM";
break;
case SIGABRT:
oss << "Caught SIGABRT";
break;
case SIGFPE:
oss << "Caught SIGFPE at "
<< (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "")
<< sigInfo->si_addr << " ";
switch (sigInfo->si_code) {
#if defined(FPE_INTDIV)
case FPE_INTDIV:
oss << "integer division by zero";
break;
#endif
#if defined(FPE_INTOVF)
case FPE_INTOVF:
oss << "integer overflow";
break;
#endif
case FPE_FLTDIV:
oss << "floating point divide by zero";
break;
case FPE_FLTOVF:
oss << "floating point overflow";
break;
case FPE_FLTUND:
oss << "floating point underflow";
break;
case FPE_FLTRES:
oss << "floating point inexact result";
break;
case FPE_FLTINV:
oss << "floating point invalid operation";
break;
#if defined(FPE_FLTSUB)
case FPE_FLTSUB:
oss << "floating point subscript out of range";
break;
#endif
default:
oss << "code " << sigInfo->si_code;
break;
}
break;
case SIGSEGV:
oss << "Caught SIGSEGV at "
<< (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "")
<< sigInfo->si_addr << " ";
switch (sigInfo->si_code) {
case SEGV_MAPERR:
oss << "address not mapped to object";
break;
case SEGV_ACCERR:
oss << "invalid permission for mapped object";
break;
default:
oss << "code " << sigInfo->si_code;
break;
}
break;
case SIGBUS:
oss << "Caught SIGBUS at "
<< (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "")
<< sigInfo->si_addr << " ";
switch (sigInfo->si_code) {
case BUS_ADRALN:
oss << "invalid address alignment";
break;
#if defined(BUS_ADRERR)
case BUS_ADRERR:
oss << "nonexistent physical address";
break;
#endif
#if defined(BUS_OBJERR)
case BUS_OBJERR:
oss << "object-specific hardware error";
break;
#endif
#if defined(BUS_MCEERR_AR)
case BUS_MCEERR_AR:
oss << "Hardware memory error consumed on a machine check; action "
"required.";
break;
#endif
#if defined(BUS_MCEERR_AO)
case BUS_MCEERR_AO:
oss << "Hardware memory error detected in process but not consumed; "
"action optional.";
break;
#endif
default:
oss << "code " << sigInfo->si_code;
break;
}
break;
case SIGILL:
oss << "Caught SIGILL at "
<< (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "")
<< sigInfo->si_addr << " ";
switch (sigInfo->si_code) {
case ILL_ILLOPC:
oss << "illegal opcode";
break;
#if defined(ILL_ILLOPN)
case ILL_ILLOPN:
oss << "illegal operand";
break;
#endif
#if defined(ILL_ILLADR)
case ILL_ILLADR:
oss << "illegal addressing mode.";
break;
#endif
case ILL_ILLTRP:
oss << "illegal trap";
break;
case ILL_PRVOPC:
oss << "privileged opcode";
break;
#if defined(ILL_PRVREG)
case ILL_PRVREG:
oss << "privileged register";
break;
#endif
#if defined(ILL_COPROC)
case ILL_COPROC:
oss << "co-processor error";
break;
#endif
#if defined(ILL_BADSTK)
case ILL_BADSTK:
oss << "internal stack error";
break;
#endif
default:
oss << "code " << sigInfo->si_code;
break;
}
break;
default:
oss << "Caught " << sigNo << " code " << sigInfo->si_code;
break;
}
oss << std::endl
<< "Program Stack:" << std::endl
<< SystemInformationImplementation::GetProgramStack(2, 0)
<< "========================================================="
<< std::endl;
std::cerr << oss.str() << std::endl;
// restore the previously registered handlers
// and abort
SystemInformationImplementation::SetStackTraceOnError(0);
abort();
#else
// avoid warning C4100
(void)sigNo;
(void)sigInfo;
#endif
}
#endif
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
#define safes(_arg) ((_arg) ? (_arg) : "???")
// Description:
// A container for symbol properties. Each instance
// must be Initialized.
class SymbolProperties
{
public:
SymbolProperties();
// Description:
// The SymbolProperties instance must be initialized by
// passing a stack address.
void Initialize(void* address);
// Description:
// Get the symbol's stack address.
void* GetAddress() const { return this->Address; }
// Description:
// If not set paths will be removed. eg, from a binary
// or source file.
void SetReportPath(int rp) { this->ReportPath = rp; }
// Description:
// Set/Get the name of the binary file that the symbol
// is found in.
void SetBinary(const char* binary) { this->Binary = safes(binary); }
std::string GetBinary() const;
// Description:
// Set the name of the function that the symbol is found in.
// If c++ demangling is supported it will be demangled.
void SetFunction(const char* function)
{
this->Function = this->Demangle(function);
}
std::string GetFunction() const { return this->Function; }
// Description:
// Set/Get the name of the source file where the symbol
// is defined.
void SetSourceFile(const char* sourcefile)
{
this->SourceFile = safes(sourcefile);
}
std::string GetSourceFile() const
{
return this->GetFileName(this->SourceFile);
}
// Description:
// Set/Get the line number where the symbol is defined
void SetLineNumber(long linenumber) { this->LineNumber = linenumber; }
long GetLineNumber() const { return this->LineNumber; }
// Description:
// Set the address where the biinary image is mapped
// into memory.
void SetBinaryBaseAddress(void* address)
{
this->BinaryBaseAddress = address;
}
private:
void* GetRealAddress() const
{
return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress);
}
std::string GetFileName(const std::string& path) const;
std::string Demangle(const char* symbol) const;
private:
std::string Binary;
void* BinaryBaseAddress;
void* Address;
std::string SourceFile;
std::string Function;
long LineNumber;
int ReportPath;
};
std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp)
{
#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [("
<< sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec
<< sp.GetLineNumber() << "]";
#elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
void* addr = sp.GetAddress();
char** syminfo = backtrace_symbols(&addr, 1);
os << safes(syminfo[0]);
free(syminfo);
#else
(void)os;
(void)sp;
#endif
return os;
}
SymbolProperties::SymbolProperties()
{
// not using an initializer list
// to avoid some PGI compiler warnings
this->SetBinary("???");
this->SetBinaryBaseAddress(KWSYS_NULLPTR);
this->Address = KWSYS_NULLPTR;
this->SetSourceFile("???");
this->SetFunction("???");
this->SetLineNumber(-1);
this->SetReportPath(0);
// avoid PGI compiler warnings
this->GetRealAddress();
this->GetFunction();
this->GetSourceFile();
this->GetLineNumber();
}
std::string SymbolProperties::GetFileName(const std::string& path) const
{
std::string file(path);
if (!this->ReportPath) {
size_t at = file.rfind("/");
if (at != std::string::npos) {
file = file.substr(at + 1);
}
}
return file;
}
std::string SymbolProperties::GetBinary() const
{
// only linux has proc fs
#if defined(__linux__)
if (this->Binary == "/proc/self/exe") {
std::string binary;
char buf[1024] = { '\0' };
ssize_t ll = 0;
if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) {
buf[ll] = '\0';
binary = buf;
} else {
binary = "/proc/self/exe";
}
return this->GetFileName(binary);
}
#endif
return this->GetFileName(this->Binary);
}
std::string SymbolProperties::Demangle(const char* symbol) const
{
std::string result = safes(symbol);
#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
int status = 0;
size_t bufferLen = 1024;
char* buffer = (char*)malloc(1024);
char* demangledSymbol =
abi::__cxa_demangle(symbol, buffer, &bufferLen, &status);
if (!status) {
result = demangledSymbol;
}
free(buffer);
#else
(void)symbol;
#endif
return result;
}
void SymbolProperties::Initialize(void* address)
{
this->Address = address;
#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
// first fallback option can demangle c++ functions
Dl_info info;
int ierr = dladdr(this->Address, &info);
if (ierr && info.dli_sname && info.dli_saddr) {
this->SetBinary(info.dli_fname);
this->SetFunction(info.dli_sname);
}
#else
// second fallback use builtin backtrace_symbols
// to decode the bactrace.
#endif
}
#endif // don't define this class if we're not using it
#if defined(_WIN32) || defined(__CYGWIN__)
#define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
#endif
#if defined(_MSC_VER) && _MSC_VER < 1310
#undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
#endif
#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
double calculateCPULoad(unsigned __int64 idleTicks,
unsigned __int64 totalTicks)
{
static double previousLoad = -0.0;
static unsigned __int64 previousIdleTicks = 0;
static unsigned __int64 previousTotalTicks = 0;
unsigned __int64 const idleTicksSinceLastTime =
idleTicks - previousIdleTicks;
unsigned __int64 const totalTicksSinceLastTime =
totalTicks - previousTotalTicks;
double load;
if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) {
// No new information. Use previous result.
load = previousLoad;
} else {
// Calculate load since last time.
load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime;
// Smooth if possible.
if (previousLoad > 0) {
load = 0.25 * load + 0.75 * previousLoad;
}
}
previousLoad = load;
previousIdleTicks = idleTicks;
previousTotalTicks = totalTicks;
return load;
}
unsigned __int64 fileTimeToUInt64(FILETIME const& ft)
{
LARGE_INTEGER out;
out.HighPart = ft.dwHighDateTime;
out.LowPart = ft.dwLowDateTime;
return out.QuadPart;
}
#endif
} // anonymous namespace
SystemInformationImplementation::SystemInformationImplementation()
{
this->TotalVirtualMemory = 0;
this->AvailableVirtualMemory = 0;
this->TotalPhysicalMemory = 0;
this->AvailablePhysicalMemory = 0;
this->CurrentPositionInFile = 0;
this->ChipManufacturer = UnknownManufacturer;
memset(&this->Features, 0, sizeof(CPUFeatures));
this->ChipID.Type = 0;
this->ChipID.Family = 0;
this->ChipID.Model = 0;
this->ChipID.Revision = 0;
this->ChipID.ExtendedFamily = 0;
this->ChipID.ExtendedModel = 0;
this->CPUSpeedInMHz = 0;
this->NumberOfLogicalCPU = 0;
this->NumberOfPhysicalCPU = 0;
this->OSName = "";
this->Hostname = "";
this->OSRelease = "";
this->OSVersion = "";
this->OSPlatform = "";
this->OSIs64Bit = (sizeof(void*) == 8);
}
SystemInformationImplementation::~SystemInformationImplementation()
{
}
void SystemInformationImplementation::RunCPUCheck()
{
#ifdef _WIN32
// Check to see if this processor supports CPUID.
bool supportsCPUID = DoesCPUSupportCPUID();
if (supportsCPUID) {
// Retrieve the CPU details.
RetrieveCPUIdentity();
this->FindManufacturer();
RetrieveCPUFeatures();
}
// These two may be called without support for the CPUID instruction.
// (But if the instruction is there, they should be called *after*
// the above call to RetrieveCPUIdentity... that's why the two if
// blocks exist with the same "if (supportsCPUID)" logic...
//
if (!RetrieveCPUClockSpeed()) {
RetrieveClassicalCPUClockSpeed();
}
if (supportsCPUID) {
// Retrieve cache information.
if (!RetrieveCPUCacheDetails()) {
RetrieveClassicalCPUCacheDetails();
}
// Retrieve the extended CPU details.
if (!RetrieveExtendedCPUIdentity()) {
RetrieveClassicalCPUIdentity();
}
RetrieveExtendedCPUFeatures();
RetrieveCPUPowerManagement();
// Now attempt to retrieve the serial number (if possible).
RetrieveProcessorSerialNumber();
}
this->CPUCountWindows();
#elif defined(__APPLE__)
this->ParseSysCtl();
#elif defined(__SVR4) && defined(__sun)
this->QuerySolarisProcessor();
#elif defined(__HAIKU__)
this->QueryHaikuInfo();
#elif defined(__QNX__)
this->QueryQNXProcessor();
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__DragonFly__)
this->QueryBSDProcessor();
#elif defined(__hpux)
this->QueryHPUXProcessor();
#elif defined(__linux) || defined(__CYGWIN__)
this->RetreiveInformationFromCpuInfoFile();
#else
this->QueryProcessor();
#endif
}
void SystemInformationImplementation::RunOSCheck()
{
this->QueryOSInformation();
}
void SystemInformationImplementation::RunMemoryCheck()
{
#if defined(__APPLE__)
this->ParseSysCtl();
#elif defined(__SVR4) && defined(__sun)
this->QuerySolarisMemory();
#elif defined(__HAIKU__)
this->QueryHaikuInfo();
#elif defined(__QNX__)
this->QueryQNXMemory();
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__DragonFly__)
this->QueryBSDMemory();
#elif defined(__CYGWIN__)
this->QueryCygwinMemory();
#elif defined(_WIN32)
this->QueryWindowsMemory();
#elif defined(__hpux)
this->QueryHPUXMemory();
#elif defined(__linux)
this->QueryLinuxMemory();
#elif defined(_AIX)
this->QueryAIXMemory();
#else
this->QueryMemory();
#endif
}
/** Get the vendor string */
const char* SystemInformationImplementation::GetVendorString()
{
return this->ChipID.Vendor.c_str();
}
/** Get the OS Name */
const char* SystemInformationImplementation::GetOSName()
{
return this->OSName.c_str();
}
/** Get the hostname */
const char* SystemInformationImplementation::GetHostname()
{
if (this->Hostname.empty()) {
this->Hostname = "localhost";
#if defined(_WIN32)
WORD wVersionRequested;
WSADATA wsaData;
char name[255];
wVersionRequested = MAKEWORD(2, 0);
if (WSAStartup(wVersionRequested, &wsaData) == 0) {
gethostname(name, sizeof(name));
WSACleanup();
}
this->Hostname = name;
#else
struct utsname unameInfo;
int errorFlag = uname(&unameInfo);
if (errorFlag == 0) {
this->Hostname = unameInfo.nodename;
}
#endif
}
return this->Hostname.c_str();
}
/** Get the FQDN */
int SystemInformationImplementation::GetFullyQualifiedDomainName(
std::string& fqdn)
{
// in the event of absolute failure return localhost.
fqdn = "localhost";
#if defined(_WIN32)
int ierr;
// TODO - a more robust implementation for windows, see comments
// in unix implementation.
WSADATA wsaData;
WORD ver = MAKEWORD(2, 0);
ierr = WSAStartup(ver, &wsaData);
if (ierr) {
return -1;
}
char base[256] = { '\0' };
ierr = gethostname(base, 256);
if (ierr) {
WSACleanup();
return -2;
}
fqdn = base;
HOSTENT* hent = gethostbyname(base);
if (hent) {
fqdn = hent->h_name;
}
WSACleanup();
return 0;
#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN)
// gethostname typical returns an alias for loopback interface
// we want the fully qualified domain name. Because there are
// any number of interfaces on this system we look for the
// first of these that contains the name returned by gethostname
// and is longer. failing that we return gethostname and indicate
// with a failure code. Return of a failure code is not necessarily
// an indication of an error. for instance gethostname may return
// the fully qualified domain name, or there may not be one if the
// system lives on a private network such as in the case of a cluster
// node.
int ierr = 0;
char base[NI_MAXHOST];
ierr = gethostname(base, NI_MAXHOST);
if (ierr) {
return -1;
}
size_t baseSize = strlen(base);
fqdn = base;
struct ifaddrs* ifas;
struct ifaddrs* ifa;
ierr = getifaddrs(&ifas);
if (ierr) {
return -2;
}
for (ifa = ifas; ifa != KWSYS_NULLPTR; ifa = ifa->ifa_next) {
int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1;
// Skip Loopback interfaces
if (((fam == AF_INET) || (fam == AF_INET6)) &&
!(ifa->ifa_flags & IFF_LOOPBACK)) {
char host[NI_MAXHOST] = { '\0' };
const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6));
ierr = getnameinfo(ifa->ifa_addr, static_cast<socklen_t>(addrlen), host,
NI_MAXHOST, KWSYS_NULLPTR, 0, NI_NAMEREQD);
if (ierr) {
// don't report the failure now since we may succeed on another
// interface. If all attempts fail then return the failure code.
ierr = -3;
continue;
}
std::string candidate = host;
if ((candidate.find(base) != std::string::npos) &&
baseSize < candidate.size()) {
// success, stop now.
ierr = 0;
fqdn = candidate;
break;
}
}
}
freeifaddrs(ifas);
return ierr;
#else
/* TODO: Implement on more platforms. */
fqdn = this->GetHostname();
return -1;
#endif
}
/** Get the OS release */
const char* SystemInformationImplementation::GetOSRelease()
{
return this->OSRelease.c_str();
}
/** Get the OS version */
const char* SystemInformationImplementation::GetOSVersion()
{
return this->OSVersion.c_str();
}
/** Get the OS platform */
const char* SystemInformationImplementation::GetOSPlatform()
{
return this->OSPlatform.c_str();
}
/** Get the vendor ID */
const char* SystemInformationImplementation::GetVendorID()
{
// Return the vendor ID.
switch (this->ChipManufacturer) {
case Intel:
return "Intel Corporation";
case AMD:
return "Advanced Micro Devices";
case NSC:
return "National Semiconductor";
case Cyrix:
return "Cyrix Corp., VIA Inc.";
case NexGen:
return "NexGen Inc., Advanced Micro Devices";
case IDT:
return "IDT\\Centaur, Via Inc.";
case UMC:
return "United Microelectronics Corp.";
case Rise:
return "Rise";
case Transmeta:
return "Transmeta";
case Sun:
return "Sun Microelectronics";
case IBM:
return "IBM";
case Motorola:
return "Motorola";
case HP:
return "Hewlett-Packard";
case UnknownManufacturer:
default:
return "Unknown Manufacturer";
}
}
/** Return the type ID of the CPU */
std::string SystemInformationImplementation::GetTypeID()
{
std::ostringstream str;
str << this->ChipID.Type;
return str.str();
}
/** Return the family of the CPU present */
std::string SystemInformationImplementation::GetFamilyID()
{
std::ostringstream str;
str << this->ChipID.Family;
return str.str();
}
// Return the model of CPU present */
std::string SystemInformationImplementation::GetModelID()
{
std::ostringstream str;
str << this->ChipID.Model;
return str.str();
}
// Return the model name of CPU present */
std::string SystemInformationImplementation::GetModelName()
{
return this->ChipID.ModelName;
}
/** Return the stepping code of the CPU present. */
std::string SystemInformationImplementation::GetSteppingCode()
{
std::ostringstream str;
str << this->ChipID.Revision;
return str.str();
}
/** Return the stepping code of the CPU present. */
const char* SystemInformationImplementation::GetExtendedProcessorName()
{
return this->ChipID.ProcessorName.c_str();
}
/** Return the serial number of the processor
* in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
const char* SystemInformationImplementation::GetProcessorSerialNumber()
{
return this->ChipID.SerialNumber.c_str();
}
/** Return the logical processors per physical */
unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
{
return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
}
/** Return the processor clock frequency. */
float SystemInformationImplementation::GetProcessorClockFrequency()
{
return this->CPUSpeedInMHz;
}
/** Return the APIC ID. */
int SystemInformationImplementation::GetProcessorAPICID()
{
return this->Features.ExtendedFeatures.APIC_ID;
}
/** Return the L1 cache size. */
int SystemInformationImplementation::GetProcessorCacheSize()
{
return this->Features.L1CacheSize;
}
/** Return the chosen cache size. */
int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
{
switch (dwCacheID) {
case SystemInformation::CPU_FEATURE_L1CACHE:
return this->Features.L1CacheSize;
case SystemInformation::CPU_FEATURE_L2CACHE:
return this->Features.L2CacheSize;
case SystemInformation::CPU_FEATURE_L3CACHE:
return this->Features.L3CacheSize;
}
return -1;
}
bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
{
bool bHasFeature = false;
// Check for MMX instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) &&
this->Features.HasMMX)
bHasFeature = true;
// Check for MMX+ instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) &&
this->Features.ExtendedFeatures.HasMMXPlus)
bHasFeature = true;
// Check for SSE FP instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) &&
this->Features.HasSSE)
bHasFeature = true;
// Check for SSE FP instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) &&
this->Features.HasSSEFP)
bHasFeature = true;
// Check for SSE MMX instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) &&
this->Features.ExtendedFeatures.HasSSEMMX)
bHasFeature = true;
// Check for SSE2 instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) &&
this->Features.HasSSE2)
bHasFeature = true;
// Check for 3DNow! instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) &&
this->Features.ExtendedFeatures.Has3DNow)
bHasFeature = true;
// Check for 3DNow+ instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) &&
this->Features.ExtendedFeatures.Has3DNowPlus)
bHasFeature = true;
// Check for IA64 instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) &&
this->Features.HasIA64)
bHasFeature = true;
// Check for MP capable.
if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) &&
this->Features.ExtendedFeatures.SupportsMP)
bHasFeature = true;
// Check for a serial number for the processor.
if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) &&
this->Features.HasSerial)
bHasFeature = true;
// Check for a local APIC in the processor.
if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) &&
this->Features.HasAPIC)
bHasFeature = true;
// Check for CMOV instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) &&
this->Features.HasCMOV)
bHasFeature = true;
// Check for MTRR instructions.
if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) &&
this->Features.HasMTRR)
bHasFeature = true;
// Check for L1 cache size.
if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) &&
(this->Features.L1CacheSize != -1))
bHasFeature = true;
// Check for L2 cache size.
if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) &&
(this->Features.L2CacheSize != -1))
bHasFeature = true;
// Check for L3 cache size.
if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) &&
(this->Features.L3CacheSize != -1))
bHasFeature = true;
// Check for ACPI capability.
if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) &&
this->Features.HasACPI)
bHasFeature = true;
// Check for thermal monitor support.
if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) &&
this->Features.HasThermal)
bHasFeature = true;
// Check for temperature sensing diode support.
if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) &&
this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode)
bHasFeature = true;
// Check for frequency ID support.
if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) &&
this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID)
bHasFeature = true;
// Check for voltage ID support.
if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) !=
0) &&
this->Features.ExtendedFeatures.PowerManagement.HasVoltageID)
bHasFeature = true;
// Check for FPU support.
if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) &&
this->Features.HasFPU)
bHasFeature = true;
return bHasFeature;
}
void SystemInformationImplementation::Delay(unsigned int uiMS)
{
#ifdef _WIN32
LARGE_INTEGER Frequency, StartCounter, EndCounter;
__int64 x;
// Get the frequency of the high performance counter.
if (!QueryPerformanceFrequency(&Frequency))
return;
x = Frequency.QuadPart / 1000 * uiMS;
// Get the starting position of the counter.
QueryPerformanceCounter(&StartCounter);
do {
// Get the ending position of the counter.
QueryPerformanceCounter(&EndCounter);
} while (EndCounter.QuadPart - StartCounter.QuadPart < x);
#endif
(void)uiMS;
}
bool SystemInformationImplementation::DoesCPUSupportCPUID()
{
#if USE_CPUID
int dummy[4] = { 0, 0, 0, 0 };
#if USE_ASM_INSTRUCTIONS
return call_cpuid(0, dummy);
#else
call_cpuid(0, dummy);
return dummy[0] || dummy[1] || dummy[2] || dummy[3];
#endif
#else
// Assume no cpuid instruction.
return false;
#endif
}
bool SystemInformationImplementation::RetrieveCPUFeatures()
{
#if USE_CPUID
int cpuinfo[4] = { 0, 0, 0, 0 };
if (!call_cpuid(1, cpuinfo)) {
return false;
}
// Retrieve the features of CPU present.
this->Features.HasFPU =
((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0
this->Features.HasTSC =
((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4
this->Features.HasAPIC =
((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9
this->Features.HasMTRR =
((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12
this->Features.HasCMOV =
((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15
this->Features.HasSerial =
((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18
this->Features.HasACPI =
((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22
this->Features.HasMMX =
((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23
this->Features.HasSSE =
((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25
this->Features.HasSSE2 =
((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26
this->Features.HasThermal =
((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
this->Features.HasIA64 =
((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30
#if USE_ASM_INSTRUCTIONS
// Retrieve extended SSE capabilities if SSE is available.
if (this->Features.HasSSE) {
// Attempt to __try some SSE FP instructions.
__try {
// Perform: orps xmm0, xmm0
_asm
{
_emit 0x0f
_emit 0x56
_emit 0xc0
}
// SSE FP capable processor.
this->Features.HasSSEFP = true;
} __except (1) {
// bad instruction - processor or OS cannot handle SSE FP.
this->Features.HasSSEFP = false;
}
} else {
// Set the advanced SSE capabilities to not available.
this->Features.HasSSEFP = false;
}
#else
this->Features.HasSSEFP = false;
#endif
// Retrieve Intel specific extended features.
if (this->ChipManufacturer == Intel) {
bool SupportsSMT =
((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28
if ((SupportsSMT) && (this->Features.HasAPIC)) {
// Retrieve APIC information if there is one present.
this->Features.ExtendedFeatures.APIC_ID =
((cpuinfo[1] & 0xFF000000) >> 24);
}
}
return true;
#else
return false;
#endif
}
/** Find the manufacturer given the vendor id */
void SystemInformationImplementation::FindManufacturer(
const std::string& family)
{
if (this->ChipID.Vendor == "GenuineIntel")
this->ChipManufacturer = Intel; // Intel Corp.
else if (this->ChipID.Vendor == "UMC UMC UMC ")
this->ChipManufacturer = UMC; // United Microelectronics Corp.
else if (this->ChipID.Vendor == "AuthenticAMD")
this->ChipManufacturer = AMD; // Advanced Micro Devices
else if (this->ChipID.Vendor == "AMD ISBETTER")
this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
else if (this->ChipID.Vendor == "CyrixInstead")
this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
else if (this->ChipID.Vendor == "NexGenDriven")
this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
else if (this->ChipID.Vendor == "CentaurHauls")
this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
else if (this->ChipID.Vendor == "RiseRiseRise")
this->ChipManufacturer = Rise; // Rise
else if (this->ChipID.Vendor == "GenuineTMx86")
this->ChipManufacturer = Transmeta; // Transmeta
else if (this->ChipID.Vendor == "TransmetaCPU")
this->ChipManufacturer = Transmeta; // Transmeta
else if (this->ChipID.Vendor == "Geode By NSC")
this->ChipManufacturer = NSC; // National Semiconductor
else if (this->ChipID.Vendor == "Sun")
this->ChipManufacturer = Sun; // Sun Microelectronics
else if (this->ChipID.Vendor == "IBM")
this->ChipManufacturer = IBM; // IBM Microelectronics
else if (this->ChipID.Vendor == "Hewlett-Packard")
this->ChipManufacturer = HP; // Hewlett-Packard
else if (this->ChipID.Vendor == "Motorola")
this->ChipManufacturer = Motorola; // Motorola Microelectronics
else if (family.substr(0, 7) == "PA-RISC")
this->ChipManufacturer = HP; // Hewlett-Packard
else
this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
}
/** */
bool SystemInformationImplementation::RetrieveCPUIdentity()
{
#if USE_CPUID
int localCPUVendor[4];
int localCPUSignature[4];
if (!call_cpuid(0, localCPUVendor)) {
return false;
}
if (!call_cpuid(1, localCPUSignature)) {
return false;
}
// Process the returned information.
// ; eax = 0 --> eax: maximum value of CPUID instruction.
// ; ebx: part 1 of 3; CPU signature.
// ; edx: part 2 of 3; CPU signature.
// ; ecx: part 3 of 3; CPU signature.
char vbuf[13];
memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int));
memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int));
memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int));
vbuf[12] = '\0';
this->ChipID.Vendor = vbuf;
// Retrieve the family of CPU present.
// ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type,
// bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
// ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID,
// 15..8 - CFLUSH chunk size , 7..0 - brand ID
// ; edx: CPU feature flags
this->ChipID.ExtendedFamily =
((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used
this->ChipID.ExtendedModel =
((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used
this->ChipID.Type =
((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used
this->ChipID.Family =
((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used
this->ChipID.Model =
((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used
this->ChipID.Revision =
((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUCacheDetails()
{
#if USE_CPUID
int L1Cache[4] = { 0, 0, 0, 0 };
int L2Cache[4] = { 0, 0, 0, 0 };
// Check to see if what we are about to do is supported...
if (RetrieveCPUExtendedLevelSupport(0x80000005)) {
if (!call_cpuid(0x80000005, L1Cache)) {
return false;
}
// Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as
// data cache size from edx: bits 31..24.
this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
} else {
// Store -1 to indicate the cache could not be queried.
this->Features.L1CacheSize = -1;
}
// Check to see if what we are about to do is supported...
if (RetrieveCPUExtendedLevelSupport(0x80000006)) {
if (!call_cpuid(0x80000006, L2Cache)) {
return false;
}
// Save the L2 unified cache size (in KB) from ecx: bits 31..16.
this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
} else {
// Store -1 to indicate the cache could not be queried.
this->Features.L2CacheSize = -1;
}
// Define L3 as being not present as we cannot test for it.
this->Features.L3CacheSize = -1;
#endif
// Return failure if we cannot detect either cache with this method.
return ((this->Features.L1CacheSize == -1) &&
(this->Features.L2CacheSize == -1))
? false
: true;
}
/** */
bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
{
#if USE_CPUID
int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1,
L2Unified = -1, L3Unified = -1;
int TLBCacheData[4] = { 0, 0, 0, 0 };
int TLBPassCounter = 0;
int TLBCacheUnit = 0;
do {
if (!call_cpuid(2, TLBCacheData)) {
return false;
}
int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
(void)bob;
// Process the returned TLB and cache information.
for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) {
// First of all - decide which unit we are dealing with.
switch (nCounter) {
// eax: bits 8..15 : bits 16..23 : bits 24..31
case 0:
TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8);
break;
case 1:
TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16);
break;
case 2:
TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24);
break;
// ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 3:
TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0);
break;
case 4:
TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8);
break;
case 5:
TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16);
break;
case 6:
TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24);
break;
// ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 7:
TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0);
break;
case 8:
TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8);
break;
case 9:
TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16);
break;
case 10:
TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24);
break;
// edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 11:
TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0);
break;
case 12:
TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8);
break;
case 13:
TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16);
break;
case 14:
TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24);
break;
// Default case - an error has occurred.
default:
return false;
}
// Now process the resulting unit to see what it means....
switch (TLBCacheUnit) {
case 0x00:
break;
case 0x01:
STORE_TLBCACHE_INFO(TLBCode, 4);
break;
case 0x02:
STORE_TLBCACHE_INFO(TLBCode, 4096);
break;
case 0x03:
STORE_TLBCACHE_INFO(TLBData, 4);
break;
case 0x04:
STORE_TLBCACHE_INFO(TLBData, 4096);
break;
case 0x06:
STORE_TLBCACHE_INFO(L1Code, 8);
break;
case 0x08:
STORE_TLBCACHE_INFO(L1Code, 16);
break;
case 0x0a:
STORE_TLBCACHE_INFO(L1Data, 8);
break;
case 0x0c:
STORE_TLBCACHE_INFO(L1Data, 16);
break;
case 0x10:
STORE_TLBCACHE_INFO(L1Data, 16);
break; // <-- FIXME: IA-64 Only
case 0x15:
STORE_TLBCACHE_INFO(L1Code, 16);
break; // <-- FIXME: IA-64 Only
case 0x1a:
STORE_TLBCACHE_INFO(L2Unified, 96);
break; // <-- FIXME: IA-64 Only
case 0x22:
STORE_TLBCACHE_INFO(L3Unified, 512);
break;
case 0x23:
STORE_TLBCACHE_INFO(L3Unified, 1024);
break;
case 0x25:
STORE_TLBCACHE_INFO(L3Unified, 2048);
break;
case 0x29:
STORE_TLBCACHE_INFO(L3Unified, 4096);
break;
case 0x39:
STORE_TLBCACHE_INFO(L2Unified, 128);
break;
case 0x3c:
STORE_TLBCACHE_INFO(L2Unified, 256);
break;
case 0x40:
STORE_TLBCACHE_INFO(L2Unified, 0);
break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4
// core).
case 0x41:
STORE_TLBCACHE_INFO(L2Unified, 128);
break;
case 0x42:
STORE_TLBCACHE_INFO(L2Unified, 256);
break;
case 0x43:
STORE_TLBCACHE_INFO(L2Unified, 512);
break;
case 0x44:
STORE_TLBCACHE_INFO(L2Unified, 1024);
break;
case 0x45:
STORE_TLBCACHE_INFO(L2Unified, 2048);
break;
case 0x50:
STORE_TLBCACHE_INFO(TLBCode, 4096);
break;
case 0x51:
STORE_TLBCACHE_INFO(TLBCode, 4096);
break;
case 0x52:
STORE_TLBCACHE_INFO(TLBCode, 4096);
break;
case 0x5b:
STORE_TLBCACHE_INFO(TLBData, 4096);
break;
case 0x5c:
STORE_TLBCACHE_INFO(TLBData, 4096);
break;
case 0x5d:
STORE_TLBCACHE_INFO(TLBData, 4096);
break;
case 0x66:
STORE_TLBCACHE_INFO(L1Data, 8);
break;
case 0x67:
STORE_TLBCACHE_INFO(L1Data, 16);
break;
case 0x68:
STORE_TLBCACHE_INFO(L1Data, 32);
break;
case 0x70:
STORE_TLBCACHE_INFO(L1Trace, 12);
break;
case 0x71:
STORE_TLBCACHE_INFO(L1Trace, 16);
break;
case 0x72:
STORE_TLBCACHE_INFO(L1Trace, 32);
break;
case 0x77:
STORE_TLBCACHE_INFO(L1Code, 16);
break; // <-- FIXME: IA-64 Only
case 0x79:
STORE_TLBCACHE_INFO(L2Unified, 128);
break;
case 0x7a:
STORE_TLBCACHE_INFO(L2Unified, 256);
break;
case 0x7b:
STORE_TLBCACHE_INFO(L2Unified, 512);
break;
case 0x7c:
STORE_TLBCACHE_INFO(L2Unified, 1024);
break;
case 0x7e:
STORE_TLBCACHE_INFO(L2Unified, 256);
break;
case 0x81:
STORE_TLBCACHE_INFO(L2Unified, 128);
break;
case 0x82:
STORE_TLBCACHE_INFO(L2Unified, 256);
break;
case 0x83:
STORE_TLBCACHE_INFO(L2Unified, 512);
break;
case 0x84:
STORE_TLBCACHE_INFO(L2Unified, 1024);
break;
case 0x85:
STORE_TLBCACHE_INFO(L2Unified, 2048);
break;
case 0x88:
STORE_TLBCACHE_INFO(L3Unified, 2048);
break; // <-- FIXME: IA-64 Only
case 0x89:
STORE_TLBCACHE_INFO(L3Unified, 4096);
break; // <-- FIXME: IA-64 Only
case 0x8a:
STORE_TLBCACHE_INFO(L3Unified, 8192);
break; // <-- FIXME: IA-64 Only
case 0x8d:
STORE_TLBCACHE_INFO(L3Unified, 3096);
break; // <-- FIXME: IA-64 Only
case 0x90:
STORE_TLBCACHE_INFO(TLBCode, 262144);
break; // <-- FIXME: IA-64 Only
case 0x96:
STORE_TLBCACHE_INFO(TLBCode, 262144);
break; // <-- FIXME: IA-64 Only
case 0x9b:
STORE_TLBCACHE_INFO(TLBCode, 262144);
break; // <-- FIXME: IA-64 Only
// Default case - an error has occurred.
default:
return false;
}
}
// Increment the TLB pass counter.
TLBPassCounter++;
} while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) {
this->Features.L1CacheSize = -1;
} else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) {
this->Features.L1CacheSize = L1Trace;
} else if ((L1Code != -1) && (L1Data == -1)) {
this->Features.L1CacheSize = L1Code;
} else if ((L1Code == -1) && (L1Data != -1)) {
this->Features.L1CacheSize = L1Data;
} else if ((L1Code != -1) && (L1Data != -1)) {
this->Features.L1CacheSize = L1Code + L1Data;
} else {
this->Features.L1CacheSize = -1;
}
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if (L2Unified == -1) {
this->Features.L2CacheSize = -1;
} else {
this->Features.L2CacheSize = L2Unified;
}
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if (L3Unified == -1) {
this->Features.L3CacheSize = -1;
} else {
this->Features.L3CacheSize = L3Unified;
}
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUClockSpeed()
{
bool retrieved = false;
#if defined(_WIN32)
unsigned int uiRepetitions = 1;
unsigned int uiMSecPerRepetition = 50;
__int64 i64Total = 0;
__int64 i64Overhead = 0;
// Check if the TSC implementation works at all
if (this->Features.HasTSC &&
GetCyclesDifference(SystemInformationImplementation::Delay,
uiMSecPerRepetition) > 0) {
for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) {
i64Total += GetCyclesDifference(SystemInformationImplementation::Delay,
uiMSecPerRepetition);
i64Overhead += GetCyclesDifference(
SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition);
}
// Calculate the MHz speed.
i64Total -= i64Overhead;
i64Total /= uiRepetitions;
i64Total /= uiMSecPerRepetition;
i64Total /= 1000;
// Save the CPU speed.
this->CPUSpeedInMHz = (float)i64Total;
retrieved = true;
}
// If RDTSC is not supported, we fallback to trying to read this value
// from the registry:
if (!retrieved) {
HKEY hKey = NULL;
LONG err =
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
KEY_READ, &hKey);
if (ERROR_SUCCESS == err) {
DWORD dwType = 0;
DWORD data = 0;
DWORD dwSize = sizeof(DWORD);
err =
RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize);
if (ERROR_SUCCESS == err) {
this->CPUSpeedInMHz = (float)data;
retrieved = true;
}
RegCloseKey(hKey);
hKey = NULL;
}
}
#endif
return retrieved;
}
/** */
bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
{
#if USE_ASM_INSTRUCTIONS
LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
double dFrequency, dDifference;
// Attempt to get a starting tick count.
QueryPerformanceCounter(&liStart);
__try {
_asm {
mov eax, 0x80000000
mov ebx, CLASSICAL_CPU_FREQ_LOOP
Timer_Loop:
bsf ecx,eax
dec ebx
jnz Timer_Loop
}
} __except (1) {
return false;
}
// Attempt to get a starting tick count.
QueryPerformanceCounter(&liEnd);
// Get the difference... NB: This is in seconds....
QueryPerformanceFrequency(&liCountsPerSecond);
dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) /
(double)liCountsPerSecond.QuadPart);
// Calculate the clock speed.
if (this->ChipID.Family == 3) {
// 80386 processors.... Loop time is 115 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000);
} else if (this->ChipID.Family == 4) {
// 80486 processors.... Loop time is 47 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000);
} else if (this->ChipID.Family == 5) {
// Pentium processors.... Loop time is 43 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000);
}
// Save the clock speed.
this->Features.CPUSpeed = (int)dFrequency;
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(
int CPULevelToCheck)
{
int cpuinfo[4] = { 0, 0, 0, 0 };
// The extended CPUID is supported by various vendors starting with the
// following CPU models:
//
// Manufacturer & Chip Name | Family Model Revision
//
// AMD K6, K6-2 | 5 6 x
// Cyrix GXm, Cyrix III "Joshua" | 5 4 x
// IDT C6-2 | 5 8 x
// VIA Cyrix III | 6 5 x
// Transmeta Crusoe | 5 x x
// Intel Pentium 4 | f x x
//
// We check to see if a supported processor is present...
if (this->ChipManufacturer == AMD) {
if (this->ChipID.Family < 5)
return false;
if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6))
return false;
} else if (this->ChipManufacturer == Cyrix) {
if (this->ChipID.Family < 5)
return false;
if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4))
return false;
if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5))
return false;
} else if (this->ChipManufacturer == IDT) {
if (this->ChipID.Family < 5)
return false;
if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8))
return false;
} else if (this->ChipManufacturer == Transmeta) {
if (this->ChipID.Family < 5)
return false;
} else if (this->ChipManufacturer == Intel) {
if (this->ChipID.Family < 0xf) {
return false;
}
}
#if USE_CPUID
if (!call_cpuid(0x80000000, cpuinfo)) {
return false;
}
#endif
// Now we have to check the level wanted vs level returned...
int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF);
// Check to see if the level provided is supported...
if (nLevelWanted > nLevelReturn) {
return false;
}
return true;
}
/** */
bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
{
// Check that we are not using an Intel processor as it does not support
// this.
if (this->ChipManufacturer == Intel) {
return false;
}
// Check to see if what we are about to do is supported...
if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000001))) {
return false;
}
#if USE_CPUID
int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 };
if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) {
return false;
}
// Retrieve the extended features of CPU present.
this->Features.ExtendedFeatures.Has3DNow =
((localCPUExtendedFeatures[3] & 0x80000000) !=
0); // 3DNow Present --> Bit 31.
this->Features.ExtendedFeatures.Has3DNowPlus =
((localCPUExtendedFeatures[3] & 0x40000000) !=
0); // 3DNow+ Present -- > Bit 30.
this->Features.ExtendedFeatures.HasSSEMMX =
((localCPUExtendedFeatures[3] & 0x00400000) !=
0); // SSE MMX Present --> Bit 22.
this->Features.ExtendedFeatures.SupportsMP =
((localCPUExtendedFeatures[3] & 0x00080000) !=
0); // MP Capable -- > Bit 19.
// Retrieve AMD specific extended features.
if (this->ChipManufacturer == AMD) {
this->Features.ExtendedFeatures.HasMMXPlus =
((localCPUExtendedFeatures[3] & 0x00400000) !=
0); // AMD specific: MMX-SSE --> Bit 22
}
// Retrieve Cyrix specific extended features.
if (this->ChipManufacturer == Cyrix) {
this->Features.ExtendedFeatures.HasMMXPlus =
((localCPUExtendedFeatures[3] & 0x01000000) !=
0); // Cyrix specific: Extended MMX --> Bit 24
}
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
{
// Check to see if the processor supports the processor serial number.
if (!this->Features.HasSerial) {
return false;
}
#if USE_CPUID
int SerialNumber[4];
if (!call_cpuid(3, SerialNumber)) {