Commit b4b52847 authored by David Cole's avatar David Cole
Browse files

Add fallback for detecting CPU speed from Windows registry on builds where...

Add fallback for detecting CPU speed from Windows registry on builds where USE_ASM_INSTRUCTIONS gets defined to 0. (Win64 builds.) Clean up methods to return false when not implemented or when they fail to detect the things they're supposed to detect. This file still needs a lot more work to have a fully working implementation on Win64 builds. Committing it now because it's slightly better than it was, and there is a need for the CPU speed detection code in projects that depend on kwsys. Will file a bug shortly to request that the missing implementations get filled in...
parent da455f09
......@@ -13,6 +13,18 @@
# include <winsock.h> // WSADATA, include before sys/types.h
#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(FundamentalType.h)
#include KWSYS_HEADER(stl/string)
......@@ -22,6 +34,7 @@
#include KWSYS_HEADER(Process.h)
#include KWSYS_HEADER(ios/iostream)
#include KWSYS_HEADER(ios/sstream)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
......@@ -36,7 +49,6 @@
# include "kwsys_ios_iostream.h.in"
#endif
#ifndef WIN32
# include <sys/utsname.h> // int uname(struct utsname *buf);
#endif
......@@ -76,7 +88,6 @@
#include <string.h>
namespace KWSYS_NAMESPACE
{
......@@ -89,12 +100,13 @@ namespace KWSYS_NAMESPACE
# error "No Long Long"
#endif
// Define SystemInformationImplementation class
typedef void (*DELAY_FUNC)(unsigned int uiMS);
class SystemInformationImplementation
{
public:
SystemInformationImplementation ();
~SystemInformationImplementation ();
......@@ -137,6 +149,7 @@ public:
void RunCPUCheck();
void RunOSCheck();
void RunMemoryCheck();
public:
#define VENDOR_STRING_LENGTH (12 + 1)
#define CHIPNAME_STRING_LENGTH (48 + 1)
......@@ -199,10 +212,11 @@ public:
enum Manufacturer
{
AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM, Motorola, UnknownManufacturer
AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM,
Motorola, UnknownManufacturer
};
protected:
protected:
// Functions.
bool RetrieveCPUFeatures();
bool RetrieveCPUIdentity();
......@@ -274,15 +288,12 @@ protected:
};
SystemInformation::SystemInformation()
{
this->Implementation = new SystemInformationImplementation;
}
SystemInformation::~SystemInformation ()
SystemInformation::~SystemInformation()
{
delete this->Implementation;
}
......@@ -291,54 +302,67 @@ const char * SystemInformation::GetVendorString()
{
return this->Implementation->GetVendorString();
}
const char * SystemInformation::GetVendorID()
{
return this->Implementation->GetVendorID();
}
kwsys_stl::string SystemInformation::GetTypeID()
{
return this->Implementation->GetTypeID();
}
kwsys_stl::string SystemInformation::GetFamilyID()
{
return this->Implementation->GetFamilyID();
}
kwsys_stl::string SystemInformation::GetModelID()
{
return this->Implementation->GetModelID();
}
kwsys_stl::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);
......@@ -348,18 +372,22 @@ const char * SystemInformation::GetOSName()
{
return this->Implementation->GetOSName();
}
const char * SystemInformation::GetHostname()
{
return this->Implementation->GetHostname();
}
const char * SystemInformation::GetOSRelease()
{
return this->Implementation->GetOSRelease();
}
const char * SystemInformation::GetOSVersion()
{
return this->Implementation->GetOSVersion();
}
const char * SystemInformation::GetOSPlatform()
{
return this->Implementation->GetOSPlatform();
......@@ -374,6 +402,7 @@ unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
{
return this->Implementation->GetNumberOfLogicalCPU();
}
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
return this->Implementation->GetNumberOfPhysicalCPU();
......@@ -389,10 +418,12 @@ size_t SystemInformation::GetTotalVirtualMemory()
{
return this->Implementation->GetTotalVirtualMemory();
}
size_t SystemInformation::GetAvailableVirtualMemory()
{
return this->Implementation->GetAvailableVirtualMemory();
}
size_t SystemInformation::GetTotalPhysicalMemory()
{
return this->Implementation->GetTotalPhysicalMemory();
......@@ -408,17 +439,18 @@ void SystemInformation::RunCPUCheck()
{
this->Implementation->RunCPUCheck();
}
void SystemInformation::RunOSCheck()
{
this->Implementation->RunOSCheck();
}
void SystemInformation::RunMemoryCheck()
{
this->Implementation->RunMemoryCheck();
}
// --------------------------------------------------------------
// SystemInformationImplementation starts here
......@@ -489,7 +521,6 @@ void SystemInformation::RunMemoryCheck()
// Default value = 0xff if HT is not supported
SystemInformationImplementation::SystemInformationImplementation()
{
this->TotalVirtualMemory = 0;
......@@ -518,32 +549,48 @@ void SystemInformationImplementation::RunCPUCheck()
{
#ifdef WIN32
// Check to see if this processor supports CPUID.
if (DoesCPUSupportCPUID())
bool supportsCPUID = DoesCPUSupportCPUID();
if (supportsCPUID)
{
// Retrieve the CPU details.
RetrieveCPUIdentity();
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();
}
// Attempt to retrieve cache information.
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->CPUCount();
#elif defined(__APPLE__)
this->ParseSysCtl();
#elif defined (__SVR4) && defined (__sun)
......@@ -728,6 +775,7 @@ int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
return -1;
}
bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
{
bool bHasFeature = false;
......@@ -801,6 +849,7 @@ bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
return bHasFeature;
}
void SystemInformationImplementation::Delay(unsigned int uiMS)
{
#ifdef WIN32
......@@ -822,6 +871,7 @@ void SystemInformationImplementation::Delay(unsigned int uiMS)
(void)uiMS;
}
bool SystemInformationImplementation::DoesCPUSupportCPUID()
{
#if USE_ASM_INSTRUCTIONS
......@@ -857,19 +907,20 @@ bool SystemInformationImplementation::DoesCPUSupportCPUID()
// The cpuid instruction succeeded.
return true;
#else
// Assume no cpuid instruction.
return false;
#endif
}
bool SystemInformationImplementation::RetrieveCPUFeatures()
{
#if USE_ASM_INSTRUCTIONS
int localCPUFeatures = 0;
int localCPUAdvanced = 0;
// Use assembly to detect CPUID information...
__try {
_asm {
......@@ -959,8 +1010,12 @@ bool SystemInformationImplementation::RetrieveCPUFeatures()
this->Features.ExtendedFeatures.APIC_ID = ((localCPUAdvanced & 0xFF000000) >> 24);
}
}
#endif
return true;
#else
return false;
#endif
}
......@@ -984,6 +1039,7 @@ void SystemInformationImplementation::FindManufacturer()
else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
}
/** */
bool SystemInformationImplementation::RetrieveCPUIdentity()
{
......@@ -1052,11 +1108,15 @@ bool SystemInformationImplementation::RetrieveCPUIdentity()
this->ChipID.Family = ((localCPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used
this->ChipID.Model = ((localCPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used
this->ChipID.Revision = ((localCPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUCacheDetails()
{
......@@ -1174,6 +1234,7 @@ bool SystemInformationImplementation::RetrieveCPUCacheDetails()
return ((this->Features.L1CacheSize == -1) && (this->Features.L2CacheSize == -1)) ? false : true;
}
/** */
bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
{
......@@ -1370,18 +1431,51 @@ bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
this->Features.L3CacheSize = L3Unified;
}
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUClockSpeed()
{
bool retrieved = false;
#if _WIN32
// First of all we check to see if the RDTSC (0x0F, 0x31) instruction is supported.
// First of all we check to see if the RDTSC (0x0F, 0x31) instruction is
// supported. If not, we fallback to trying to read this value from the
// registry:
//
if (!this->Features.HasTSC)
{
return false;
HKEY hKey = NULL;
LONG err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
KEY_READ, &hKey);
if (ERROR_SUCCESS == err)
{
DWORD dwType = 0;
DWORD data = 0;
DWORD dwSize = sizeof(DWORD);
err = RegQueryValueEx(hKey, "~MHz", 0,
&dwType, (LPBYTE) &data, &dwSize);
if (ERROR_SUCCESS == err)
{
this->CPUSpeedInMHz = (float) data;
retrieved = true;
}
RegCloseKey(hKey);
hKey = NULL;
}
return retrieved;
}
unsigned int uiRepetitions = 1;
......@@ -1407,12 +1501,13 @@ bool SystemInformationImplementation::RetrieveCPUClockSpeed()
// Save the CPU speed.
this->CPUSpeedInMHz = (float) i64Total;
return true;
#else
return false;
retrieved = true;
#endif
return retrieved;
}
/** */
bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
{
......@@ -1466,11 +1561,15 @@ bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
// Save the clock speed.
this->Features.CPUSpeed = (int) dFrequency;
#else
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)
{
......@@ -1564,6 +1663,7 @@ bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULev
return true;
}
/** */
bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
{
......@@ -1579,6 +1679,7 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
{
return false;
}
#if USE_ASM_INSTRUCTIONS
int localCPUExtendedFeatures = 0;
......@@ -1634,11 +1735,15 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
{
this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24
}
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
{
......@@ -1651,7 +1756,6 @@ bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
#if USE_ASM_INSTRUCTIONS
int SerialNumber[3];
// Use assembly to detect CPUID information...
__try {
_asm {
......@@ -1701,11 +1805,15 @@ bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
((SerialNumber[2] & 0x00ff0000) >> 16),
((SerialNumber[2] & 0x0000ff00) >> 8),
((SerialNumber[2] & 0x000000ff) >> 0));
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveCPUPowerManagement()
{
......@@ -1758,11 +1866,14 @@ bool SystemInformationImplementation::RetrieveCPUPowerManagement()
this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement & 0x00000002) != 0);
this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement & 0x00000004) != 0);
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
{
......@@ -1869,11 +1980,15 @@ bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
// Now move the name forward so that there is no white space.
memmove(this->ChipID.ProcessorName, &(this->ChipID.ProcessorName[ProcessorNameStartPos]), (CHIPNAME_STRING_LENGTH - ProcessorNameStartPos));
}
#endif
return true;
#else
return false;
#endif
}
/** */
bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
{
......@@ -2150,6 +2265,7 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
return true;
}
/** Extract a value from the CPUInfo file */
kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,const char* word,size_t init)
{
......@@ -2520,6 +2636,7 @@ LongLong SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayF
#endif
}
/** Compute the delay overhead */
void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
{
......@@ -2549,6 +2666,7 @@ void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
{
unsigned int Regebx = 0;
#if USE_ASM_INSTRUCTIONS
if (!this->IsHyperThreadingSupported())
{
......@@ -2575,9 +2693,11 @@ unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
return static_cast<unsigned char>(cores_per_package);
}
#endif
return static_cast<unsigned char> ((Regebx & NUM_LOGICAL_BITS) >> 16);
}
/** Works only for windows */
unsigned int SystemInformationImplementation::IsHyperThreadingSupported()
{
......@@ -2624,10 +2744,12 @@ unsigned int SystemInformationImplementation::IsHyperThreadingSupported()
return 0; // Not genuine Intel processor
}
/** Return the APIC Id. Works only for windows. */
unsigned char SystemInformationImplementation::GetAPICId()
{
unsigned int Regebx = 0;
#if USE_ASM_INSTRUCTIONS
if (!this->IsHyperThreadingSupported())
{
......@@ -2640,9 +2762,11 @@ unsigned char SystemInformationImplementation::GetAPICId()
mov Regebx, ebx
}
#endif
return static_cast<unsigned char>((Regebx & INITIAL_APIC_ID_BITS) >> 24);
}
/** Count the number of CPUs. Works only on windows. */
int SystemInformationImplementation::CPUCount()
{
......@@ -2756,18 +2880,21 @@ int SystemInformationImplementation::CPUCount()
#endif
}
/** Return the number of logical CPUs on the system */
unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
{
return this->NumberOfLogicalCPU;
}
/** Return the number of physical CPUs on the system */
unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
{
return this->NumberOfPhysicalCPU;
}
/** For Mac use sysctlbyname calls to find system info */
bool SystemInformationImplementation::ParseSysCtl()
{
......@@ -2879,6 +3006,7 @@ bool SystemInformationImplementation::ParseSysCtl()
#endif
}
/** Extract a value from sysctl command */
kwsys_stl::string SystemInformationImplementation::ExtractValueFromSysCtl(const char* word)
{
......@@ -2895,6 +3023,7 @@ kwsys_stl::string SystemInformationImplementation::ExtractValueFromSysCtl(const
return "";
}
/** Run a given process */
kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector<const char*> args)
{
......@@ -3024,6 +3153,7 @@ kwsys_stl::string SystemInformationImplementation::ParseValueFromKStat(const cha
return value;
}
/** Querying for system information from Solaris */
bool SystemInformationImplementation::QuerySolarisInfo()
{
......@@ -3069,6 +3199,7 @@ bool SystemInformationImplementation::QuerySolarisInfo()
return true;
}
/** Querying for system information from Haiku OS */
bool SystemInformationImplementation::QueryHaikuInfo()
{
......@@ -3134,10 +3265,14 @@ bool SystemInformationImplementation::QueryHaikuInfo()
this->Features.L1CacheSize = 0;
this->Features.L2CacheSize = 0;
#endif