755 lines
26 KiB
C++
755 lines
26 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// File : gearcpu.cpp - GEAR cpu detection
|
|
// Copyright (c) Ubisoft Entertainment. All rights reserved.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "gearcpu.h"
|
|
#include "gearhardware.h"
|
|
#include "systeminc.h"
|
|
|
|
#include <gear_core/base/str.h>
|
|
|
|
namespace G4 {
|
|
|
|
namespace SystemDetection
|
|
{
|
|
namespace Private
|
|
{
|
|
class CPUInfo
|
|
{
|
|
public:
|
|
|
|
CPUInfo();
|
|
|
|
U32 MaxNumberOfThread() const
|
|
{
|
|
return (function1.edx.bits.HTT == 0 ? 1 : function1.ebx.bits.LogicalProcessorCount);
|
|
}
|
|
|
|
U32 MaxNumberOfCore() const
|
|
{
|
|
return (function1.edx.bits.HTT == 0 ? 1 : 1 + function4.eax.bits.CorePerPackage);
|
|
}
|
|
|
|
// Function 0
|
|
struct Function0
|
|
{
|
|
union EaxRegister
|
|
{
|
|
struct EaxBits {
|
|
U32 LARGEST_STD_FUNCTION;
|
|
} bits;
|
|
U32 raw;
|
|
} eax;
|
|
} function0;
|
|
|
|
// Function 1
|
|
struct Function1
|
|
{
|
|
union EaxRegister
|
|
{
|
|
struct EaxBits
|
|
{
|
|
U32 STEPPING_ID : 4;
|
|
U32 MODEL : 4;
|
|
U32 FAMILY : 4;
|
|
U32 TYPE : 2;
|
|
U32 : 2;
|
|
U32 EXT_MODEL : 4;
|
|
U32 EXT_FAMILY : 8;
|
|
U32 : 4;
|
|
} bits;
|
|
U32 raw;
|
|
} eax;
|
|
|
|
union EbxRegister
|
|
{
|
|
struct EbxBits
|
|
{
|
|
U32 BrandId : 8;
|
|
U32 CLFlush : 8;
|
|
U32 LogicalProcessorCount : 8;
|
|
U32 LocalApicId : 8;
|
|
} bits;
|
|
U32 raw;
|
|
} ebx;
|
|
|
|
union EcxRegister
|
|
{
|
|
struct EcxBits
|
|
{
|
|
U32 SSE3 : 1;
|
|
U32 : 1;
|
|
U32 DTES64 : 1;
|
|
U32 MONITOR : 1;
|
|
U32 DS_CPL : 1;
|
|
U32 VMX : 1;
|
|
U32 SMX : 1;
|
|
U32 EST : 1;
|
|
U32 TM2 : 1;
|
|
U32 SSSE3 : 1;
|
|
U32 CNXTID : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 CX16 : 1;
|
|
U32 xTPR : 1;
|
|
U32 PDCM : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 DCA : 1;
|
|
U32 SSE41 : 1;
|
|
U32 SSE42 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
U32 : 1;
|
|
} bits;
|
|
U32 raw;
|
|
} ecx;
|
|
|
|
union EdxRegister
|
|
{
|
|
struct EdxBits
|
|
{
|
|
U32 FPU : 1;
|
|
U32 VME : 1;
|
|
U32 DE : 1;
|
|
U32 PSE : 1;
|
|
U32 TSC : 1;
|
|
U32 MSR : 1;
|
|
U32 PAE : 1;
|
|
U32 MCE : 1;
|
|
U32 CX8 : 1;
|
|
U32 APIC : 1;
|
|
U32 : 1;
|
|
U32 SEP : 1;
|
|
U32 MTRR : 1;
|
|
U32 PGE : 1;
|
|
U32 MCA : 1;
|
|
U32 CMOV : 1;
|
|
U32 PAT : 1;
|
|
U32 PSE36 : 1;
|
|
U32 PSN : 1;
|
|
U32 CLFSH : 1;
|
|
U32 : 1;
|
|
U32 DS : 1;
|
|
U32 ACPI : 1;
|
|
U32 MMX : 1;
|
|
U32 FXSR : 1;
|
|
U32 SSE : 1;
|
|
U32 SSE2 : 1;
|
|
U32 SS : 1;
|
|
U32 HTT : 1;
|
|
U32 TM : 1;
|
|
U32 IA64 : 1;
|
|
U32 PBE : 1;
|
|
} bits;
|
|
U32 raw;
|
|
} edx;
|
|
} function1;
|
|
|
|
struct Function4
|
|
{
|
|
union EaxRegister
|
|
{
|
|
struct EaxBits
|
|
{
|
|
U32 : 26;
|
|
U32 CorePerPackage : 6;
|
|
} bits;
|
|
U32 raw;
|
|
} eax;
|
|
} function4;
|
|
|
|
Char vendorName[16];
|
|
Char processorName[48];
|
|
};
|
|
|
|
CPUInfo::CPUInfo()
|
|
{
|
|
int info[4] = { 0, 0, 0, 0 };
|
|
|
|
// Reset the members
|
|
System::memzero(&function0, sizeof(function0));
|
|
System::memzero(&function1, sizeof(function1));
|
|
System::memzero(&function4, sizeof(function4));
|
|
|
|
int* vendorNamePtr = (int*)vendorName;
|
|
System::memzero(vendorNamePtr, sizeof(vendorName));
|
|
|
|
int* processorNamePtr = (int*)processorName;
|
|
System::memzero(processorNamePtr, sizeof(processorName));
|
|
|
|
// Fetch the function 0 values
|
|
__cpuid(info, 0);
|
|
function0.eax.raw = info[0]; // largest standard function supported
|
|
vendorNamePtr[0] = info[1];
|
|
vendorNamePtr[1] = info[3]; // Not a mistake. Order is 1, 3, 2!
|
|
vendorNamePtr[2] = info[2];
|
|
|
|
// Fetch the function 1 values
|
|
__cpuid(info, 1);
|
|
function1.eax.raw = info[0];
|
|
function1.ebx.raw = info[1];
|
|
function1.ecx.raw = info[2];
|
|
function1.edx.raw = info[3];
|
|
|
|
// Fetch the function 0x80000000 values
|
|
__cpuid(info, 0x80000000);
|
|
if (info[0] > 0x80000004) // info[0] indicate the supported function of cpuid for brand name and others
|
|
{
|
|
__cpuid(processorNamePtr + 0, 0x80000002); // first 16 bytes
|
|
__cpuid(processorNamePtr + 4, 0x80000003); // second 16 bytes
|
|
__cpuid(processorNamePtr + 8, 0x80000004); // last 16 bytes
|
|
}
|
|
|
|
// Fetch the function 4 values, if function 4 is supported
|
|
if (function0.eax.bits.LARGEST_STD_FUNCTION >= 4)
|
|
{
|
|
// We must reset ECX to ensure cpuid returns the expected values
|
|
ResetECX();
|
|
__cpuid(info, 4);
|
|
function4.eax.raw = info[0];
|
|
}
|
|
}
|
|
|
|
// Determine the width of the bit field that can represent the value count_item.
|
|
U32 FindMaskWidth(U32 CountItem)
|
|
{
|
|
U32 index = 0;
|
|
U32 current = CountItem - 1;
|
|
|
|
while (current > 0)
|
|
{
|
|
current >>= 1;
|
|
index++;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
// Extract the subset of bit field from the 8-bit value fullId. It returns the 8-bit sub ID value
|
|
U8 GetNzbSubID(U8 fullId, U32 maxSubIdValue, U8 shiftCount)
|
|
{
|
|
U32 maskWidth;
|
|
U8 maskBits;
|
|
|
|
maskWidth = FindMaskWidth(maxSubIdValue);
|
|
maskBits = (0xff << shiftCount) ^ ((U8) (0xff << (shiftCount + maskWidth)));
|
|
|
|
return (fullId & maskBits);
|
|
}
|
|
|
|
bool CPUCount(U32 *numberOfLogicalProcessors,
|
|
U32 *numberOfCores,
|
|
U32 *numberOfPhysicalProcessors)
|
|
{
|
|
U32 availableLogicalProcessors;
|
|
|
|
// The following variables are parameters to Win32 API calls
|
|
DWORD_PTR dwAffinityMask;
|
|
DWORD_PTR dwProcessAffinity;
|
|
DWORD_PTR dwSystemAffinity;
|
|
|
|
U32 cpuIndex, maximumLogicalProcessorPerCore;
|
|
U8 apicID, packageIdMask;
|
|
U8 packageIdTable[256];
|
|
U8 coreIdTable[256] = {0};
|
|
|
|
CPUInfo defaultCpu;
|
|
|
|
// Set the values we know, based on the freshly created CPUInfo object
|
|
*numberOfPhysicalProcessors = 1; // Best guess
|
|
*numberOfCores = defaultCpu.MaxNumberOfCore();
|
|
*numberOfLogicalProcessors = defaultCpu.MaxNumberOfThread();
|
|
|
|
HANDLE hCurrentProcess = GetCurrentProcess();
|
|
|
|
GetProcessAffinityMask(
|
|
hCurrentProcess,
|
|
&dwProcessAffinity,
|
|
&dwSystemAffinity);
|
|
|
|
if (dwProcessAffinity != dwSystemAffinity)
|
|
{
|
|
// Not all CPUs are enabled
|
|
return false;
|
|
}
|
|
|
|
// Assume that cores within a package have the SAME number of logical processors.
|
|
// Also, values returned by MaxNumberOfThread and MaxNumberOfCore do not have to be power of 2.
|
|
maximumLogicalProcessorPerCore = defaultCpu.MaxNumberOfThread() / defaultCpu.MaxNumberOfCore();
|
|
availableLogicalProcessors = 0;
|
|
dwAffinityMask = 1;
|
|
cpuIndex = 0;
|
|
|
|
HANDLE hCurrentThread = GetCurrentThread();
|
|
|
|
while (dwAffinityMask && dwAffinityMask <= dwSystemAffinity)
|
|
{
|
|
if (SetThreadAffinityMask(hCurrentThread, dwAffinityMask))
|
|
{
|
|
Sleep(0); // Ensure system to switch to the right CPUInfo
|
|
|
|
CPUInfo currentCpu; // Object is created on a specific CPU
|
|
|
|
apicID = currentCpu.function1.ebx.bits.LocalApicId;
|
|
|
|
coreIdTable[cpuIndex] = GetNzbSubID(
|
|
apicID,
|
|
currentCpu.MaxNumberOfCore(),
|
|
(U8)FindMaskWidth(maximumLogicalProcessorPerCore));
|
|
|
|
// Extract package ID, assume single cluster.
|
|
// Shift value is the mask width for max Logical per package
|
|
|
|
packageIdMask = (U8) (0xff <<
|
|
FindMaskWidth(currentCpu.MaxNumberOfThread()));
|
|
|
|
packageIdTable[cpuIndex] = apicID & packageIdMask;
|
|
|
|
availableLogicalProcessors++; // Number of available logical processors in the system.
|
|
|
|
} // if
|
|
|
|
cpuIndex++;
|
|
dwAffinityMask = (DWORD_PTR)(1 << cpuIndex);
|
|
} // while
|
|
|
|
// Important: restore the affinity setting to its original state
|
|
SetThreadAffinityMask(hCurrentThread, dwProcessAffinity);
|
|
Sleep(0);
|
|
|
|
*numberOfLogicalProcessors = availableLogicalProcessors;
|
|
|
|
//
|
|
// Count available cores (numberOfCores) in the system
|
|
//
|
|
U8 CoreIDBucket[256];
|
|
DWORD processorMask, pCoreMask[256];
|
|
U32 i, processorNumber;
|
|
|
|
CoreIDBucket[0] = packageIdTable[0] | coreIdTable[0];
|
|
processorMask = 1;
|
|
pCoreMask[0] = processorMask;
|
|
*numberOfCores = 1;
|
|
|
|
for (processorNumber = 1; processorNumber < availableLogicalProcessors; processorNumber++)
|
|
{
|
|
processorMask <<= 1;
|
|
for (i = 0; i < *numberOfCores; i++)
|
|
{
|
|
// Comparing bit-fields of logical processors residing in different packages
|
|
// Assuming the bit-masks are the same on all processors in the system.
|
|
if ((packageIdTable[processorNumber] | coreIdTable[processorNumber]) == CoreIDBucket[i])
|
|
{
|
|
pCoreMask[i] |= processorMask;
|
|
break;
|
|
}
|
|
|
|
} // for i
|
|
|
|
if (i == *numberOfCores) // did not match any bucket. Start a new one.
|
|
{
|
|
CoreIDBucket[i] = packageIdTable[processorNumber] | coreIdTable[processorNumber];
|
|
pCoreMask[i] = processorMask;
|
|
|
|
(*numberOfCores)++; // Number of available cores in the system
|
|
|
|
}
|
|
|
|
} // for processorNumber
|
|
|
|
//
|
|
// Count physical processor (numberOfPhysicalProcessors) in the system
|
|
//
|
|
U8 packageIdBucket[256];
|
|
DWORD pPackageMask[256];
|
|
|
|
packageIdBucket[0] = packageIdTable[0];
|
|
processorMask = 1;
|
|
pPackageMask[0] = processorMask;
|
|
|
|
for (processorNumber = 1; processorNumber < availableLogicalProcessors; processorNumber++)
|
|
{
|
|
processorMask <<= 1;
|
|
for (i = 0; i < *numberOfPhysicalProcessors; i++)
|
|
{
|
|
// Comparing bit-fields of logical processors residing in different packages
|
|
// Assuming the bit-masks are the same on all processors in the system.
|
|
if (packageIdTable[processorNumber]== packageIdBucket[i])
|
|
{
|
|
pPackageMask[i] |= processorMask;
|
|
break;
|
|
}
|
|
|
|
} // for i
|
|
|
|
if (i == *numberOfPhysicalProcessors) // did not match any bucket. Start a new one.
|
|
{
|
|
packageIdBucket[i] = packageIdTable[processorNumber];
|
|
pPackageMask[i] = processorMask;
|
|
|
|
(*numberOfPhysicalProcessors)++; // Total number of physical processors in the system
|
|
}
|
|
} // for processorNumber
|
|
|
|
return true;
|
|
}
|
|
|
|
typedef struct _LOGICALPROCESSORDATA
|
|
{
|
|
unsigned int nLargestStandardFunctionNumber;
|
|
unsigned int nLargestExtendedFunctionNumber;
|
|
int nLogicalProcessorCount;
|
|
int nLocalApicId;
|
|
int nCPUcore;
|
|
int nProcessorId;
|
|
int nApicIdCoreIdSize;
|
|
int nNC;
|
|
int nMNC;
|
|
int nCPUCoresperProcessor;
|
|
int nThreadsperCPUCore;
|
|
int nProcId;
|
|
int nCoreId;
|
|
bool CmpLegacy;
|
|
bool HTT;
|
|
} LOGICALPROCESSORDATA, *PLOGICALPROCESSORDATA;
|
|
|
|
const U32 MAX_NUMBER_OF_LOGICAL_PROCESSORS = 96;
|
|
const U32 MAX_NUMBER_OF_PHYSICAL_PROCESSORS = 8;
|
|
const U32 MAX_NUMBER_OF_IOAPICS = 16;
|
|
|
|
int QueryNumLogicalProcessors( void )
|
|
{
|
|
SYSTEM_INFO siSysInfo;
|
|
GetSystemInfo( &siSysInfo );
|
|
return( siSysInfo.dwNumberOfProcessors );
|
|
}
|
|
|
|
int whichcpu( void )
|
|
{
|
|
int CPUInfo[4] = {0,0,0,0};
|
|
__cpuid( CPUInfo, 1 );
|
|
return ((CPUInfo[1] >> 24) & 0xff);
|
|
}
|
|
|
|
Bool GetProcessAffinity(DWORD& process, DWORD& system)
|
|
{
|
|
#if defined(WIN64)
|
|
DWORD_PTR ProcessAffinityMask;
|
|
DWORD_PTR SystemAffinityMask;
|
|
#else
|
|
DWORD ProcessAffinityMask;
|
|
DWORD SystemAffinityMask;
|
|
#endif
|
|
|
|
BOOL rc = GetProcessAffinityMask( GetCurrentProcess(), &ProcessAffinityMask, &SystemAffinityMask );
|
|
|
|
if(rc)
|
|
{
|
|
process = (DWORD)ProcessAffinityMask;
|
|
system = (DWORD)SystemAffinityMask;
|
|
}
|
|
|
|
return (rc == TRUE);
|
|
}
|
|
|
|
Bool SetProcessAffinity(DWORD process)
|
|
{
|
|
#if defined(WIN64)
|
|
DWORD_PTR ProcessAffinityMask;
|
|
#else
|
|
DWORD ProcessAffinityMask;
|
|
#endif
|
|
|
|
ProcessAffinityMask = process;
|
|
|
|
return (SetProcessAffinityMask( GetCurrentProcess(), ProcessAffinityMask) == TRUE);
|
|
}
|
|
|
|
Bool LockToLogicalProcessor( int n ) /* I want to just stick onto one particular core */
|
|
{
|
|
DWORD ProcessAffinityMask;
|
|
DWORD SystemAffinityMask;
|
|
|
|
Bool rc = GetProcessAffinity(ProcessAffinityMask, SystemAffinityMask);
|
|
if(rc)
|
|
{
|
|
DWORD pm, pmm;
|
|
pm = (DWORD)SystemAffinityMask;
|
|
pmm = 1;
|
|
while (n)
|
|
{
|
|
pmm = pmm << 1;
|
|
n--;
|
|
}
|
|
rc = SetProcessAffinity(pmm);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void cpuid( int whichlp, LOGICALPROCESSORDATA *LogicalProcessorMap )
|
|
{
|
|
unsigned int i, j, mask, numbits;
|
|
PLOGICALPROCESSORDATA p;
|
|
int CPUInfo[4] = {0,0,0,0};
|
|
p = &LogicalProcessorMap[whichlp];
|
|
LockToLogicalProcessor( whichlp );
|
|
|
|
__cpuid(CPUInfo, 0);
|
|
p->nLargestStandardFunctionNumber = CPUInfo[0];
|
|
|
|
// Get the information associated with each valid Id
|
|
for (i=0; i <= p->nLargestStandardFunctionNumber; ++i)
|
|
{
|
|
__cpuid( CPUInfo, i );
|
|
// Interpret CPU feature information.
|
|
if (i == 1)
|
|
{
|
|
// Some of the bits of LocalApicId represent the CPU core
|
|
// within a processor and other bits represent the processor ID.
|
|
p->nLocalApicId = (CPUInfo[1] >> 24) & 0xff;
|
|
p->HTT = (CPUInfo[3] >> 28) & 0x1;
|
|
// recalculate later after 0x80000008
|
|
p->nLogicalProcessorCount = (CPUInfo[1] >> 16) & 0x0FF;
|
|
}
|
|
}
|
|
|
|
// Calling __cpuid with 0x80000000 as the InfoType argument
|
|
// gets the number of valid extended IDs.
|
|
__cpuid( CPUInfo, 0x80000000 );
|
|
p->nLargestExtendedFunctionNumber = CPUInfo[0];
|
|
|
|
// Get the information associated with each extended ID.
|
|
for (i=0x80000000; i<=p->nLargestExtendedFunctionNumber; ++i)
|
|
{
|
|
__cpuid( CPUInfo, i );
|
|
if (i == 0x80000008)
|
|
{
|
|
p->nApicIdCoreIdSize = (CPUInfo[2] >> 12) & 0xF;
|
|
p->nNC = (CPUInfo[2]) & 0x0FF;
|
|
}
|
|
}
|
|
// MNC
|
|
// A value of zero for ApicIdCoreIdSize indicates that MNC is derived by this
|
|
// legacy formula: MNC = NC + 1
|
|
// A non-zero value of ApicIdCoreIdSize means that MNC is 2^ApicIdCoreIdSize
|
|
|
|
if (p->nApicIdCoreIdSize)
|
|
{
|
|
p->nMNC = 2;
|
|
for (j = p->nApicIdCoreIdSize-1; j>0; j--)
|
|
p->nMNC = p->nMNC * 2;
|
|
}
|
|
else
|
|
{
|
|
p->nMNC = p->nNC + 1;
|
|
}
|
|
// If HTT==0, then LogicalProcessorCount is reserved, and the CPU contains
|
|
// one CPU core and the CPU core is single-threaded.
|
|
// If HTT==1 and CmpLegacy==1, LogicalProcessorCount represents the number of
|
|
// CPU cores per processor, where each CPU core is single-threaded. If HTT==1
|
|
// and CmpLegacy==0, then LogicalProcessorCount is the number of threads per
|
|
// processor, which is the number of cores times the number of threads per core.
|
|
// The number of cores is NC+1.
|
|
|
|
p->nCPUCoresperProcessor = p->nNC + 1;
|
|
p->nThreadsperCPUCore = ( p->HTT==0 ? 1 :
|
|
( p->CmpLegacy==1 ? 1 :
|
|
p->nLogicalProcessorCount / p->nCPUCoresperProcessor
|
|
)
|
|
);
|
|
|
|
// Calculate a mask for the core IDs
|
|
mask = 1;
|
|
numbits = 1;
|
|
if (p->nApicIdCoreIdSize)
|
|
{
|
|
numbits = p->nApicIdCoreIdSize;
|
|
for (j = p->nApicIdCoreIdSize; j>1; j--)
|
|
mask = (mask << 1) + 1;
|
|
}
|
|
p->nProcId = p->nLocalApicId & ~mask;
|
|
p->nProcId = p->nProcId >> (numbits);
|
|
p->nCoreId = p->nLocalApicId & mask;
|
|
}
|
|
|
|
Bool AMDCPUCount(U32 *numberOfLogicalProcessors,
|
|
U32 *numberOfCores,
|
|
U32 *numberOfPhysicalProcessors)
|
|
{
|
|
int nlp, num_processors, i;
|
|
|
|
LOGICALPROCESSORDATA LogicalProcessorMap[MAX_NUMBER_OF_LOGICAL_PROCESSORS] = {0};
|
|
int PhysProcIds[MAX_NUMBER_OF_PHYSICAL_PROCESSORS+MAX_NUMBER_OF_IOAPICS] = {0};
|
|
|
|
// Save the process affinity since it gets changed in cpuid()
|
|
DWORD process, system;
|
|
Bool rc = GetProcessAffinity(process, system);
|
|
|
|
if(rc)
|
|
{
|
|
nlp = QueryNumLogicalProcessors();
|
|
for ( i = 0; i < nlp; i++ )
|
|
cpuid( i, LogicalProcessorMap );
|
|
|
|
// Restore the saved process affinity because we like it when our games run on all the
|
|
// available cores!
|
|
rc = SetProcessAffinity(process);
|
|
|
|
if(rc)
|
|
{
|
|
num_processors = 0;
|
|
for ( i = 0; i < nlp; i++ )
|
|
PhysProcIds[LogicalProcessorMap[i].nProcId]++;
|
|
for ( i = 0; i < (MAX_NUMBER_OF_PHYSICAL_PROCESSORS+MAX_NUMBER_OF_IOAPICS); i++ )
|
|
if (PhysProcIds[i])
|
|
num_processors++;
|
|
|
|
*numberOfLogicalProcessors = nlp;
|
|
*numberOfCores = LogicalProcessorMap[0].nCPUCoresperProcessor * num_processors;
|
|
*numberOfPhysicalProcessors = num_processors;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
} // namespace Private
|
|
|
|
GearCPU::GearCPU()
|
|
{
|
|
FillInformation();
|
|
}
|
|
|
|
GearCPU::~GearCPU()
|
|
{
|
|
}
|
|
|
|
void GearCPU::FillInformation()
|
|
{
|
|
// The object cpuInfo will contain all the information we need to fill up the client structure
|
|
Private::CPUInfo cpuInfo;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Processor name
|
|
///////////////////////////////////////////////////////////////////
|
|
if (cpuInfo.processorName[0] != 0)
|
|
{
|
|
m_name = cpuInfo.processorName;
|
|
}
|
|
else
|
|
{
|
|
m_name = "Unknown Processor";
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Frequency
|
|
// Here we basically query the registry to get the frequency computed
|
|
// by Windows, at boot time
|
|
///////////////////////////////////////////////////////////////////
|
|
clockFrequencyHz = 0;
|
|
HKEY hKey;
|
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) == 0)
|
|
{
|
|
DWORD mhz, dwType;
|
|
DWORD bufSize = sizeof(mhz);
|
|
if (RegQueryValueExA(hKey, "~MHz", NULL, &dwType, (LPBYTE)&mhz, &bufSize) == 0)
|
|
{
|
|
clockFrequencyHz = mhz * 1000000;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// CPU Vendor
|
|
// We retrieve the manufacturer ID from the vendor name
|
|
///////////////////////////////////////////////////////////////////
|
|
if (Str::StringCompare(cpuInfo.vendorName, "GenuineIntel") == 0)
|
|
vendor = CPU::VENDOR_INTEL;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "AuthenticAMD") == 0)
|
|
vendor = CPU::VENDOR_AMD;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "UMC UMC UMC ") == 0)
|
|
vendor = CPU::VENDOR_UMC;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "AMD ISBETTER") == 0)
|
|
vendor = CPU::VENDOR_AMD;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "CyrixInstead") == 0)
|
|
vendor = CPU::VENDOR_CYRIX;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "NexGenDriven") == 0)
|
|
vendor = CPU::VENDOR_NEXGEN;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "CentaurHauls") == 0)
|
|
vendor = CPU::VENDOR_CENTAUR;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "RiseRiseRise") == 0)
|
|
vendor = CPU::VENDOR_RISE;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "GenuineTMx86") == 0)
|
|
vendor = CPU::VENDOR_TRANSMETA;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "TransmetaCPU") == 0)
|
|
vendor = CPU::VENDOR_TRANSMETA;
|
|
else if (Str::StringCompare(cpuInfo.vendorName, "Geode By NSC") == 0)
|
|
vendor = CPU::VENDOR_NATIONALSEMICONDUCTOR;
|
|
else
|
|
vendor = CPU::VENDOR_UNKNOWN;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// The function CPUCount() computes the following parameters
|
|
// - nbHardwareThreads
|
|
// - nbCores
|
|
// - nbCPUs
|
|
///////////////////////////////////////////////////////////////////
|
|
if (vendor == CPU::VENDOR_AMD)
|
|
{
|
|
Bool rc = Private::AMDCPUCount(&nbHardwareThreads, &nbCores, &nbCPUs);
|
|
|
|
// If something failed, set everything to a safe value of 1
|
|
if(!rc)
|
|
nbHardwareThreads = nbCores = nbCPUs = 1;
|
|
}
|
|
else
|
|
{
|
|
Private::CPUCount(&nbHardwareThreads, &nbCores, &nbCPUs);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Here we decode the feature flag values reported in ECX and EDX.
|
|
// We assume that each instruction set extends the previous version,
|
|
// i.e. a processor featuring SSE3 also features SSE2, SSE and MMX.
|
|
///////////////////////////////////////////////////////////////////
|
|
if (cpuInfo.function1.ecx.bits.SSE42 == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSE42;
|
|
else if (cpuInfo.function1.ecx.bits.SSE41 == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSE41;
|
|
else if (cpuInfo.function1.ecx.bits.SSSE3 == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSSE3;
|
|
else if (cpuInfo.function1.ecx.bits.SSE3 == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSE3;
|
|
else if (cpuInfo.function1.edx.bits.SSE2 == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSE2;
|
|
else if (cpuInfo.function1.edx.bits.SSE == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_SSE;
|
|
else if (cpuInfo.function1.edx.bits.MMX == 1)
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_MMX;
|
|
else
|
|
supportedInstructionSet = CPU::INSTRUCTIONSET_NONE;
|
|
}
|
|
|
|
const char* GearCPU::GetName() const
|
|
{
|
|
return m_name.CStr();
|
|
}
|
|
} //namespace SystemDetection
|
|
} // namespace G4()
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|