Implement better CPU Detection

This commit is contained in:
Jeff Hutchinson 2021-09-15 00:02:50 -04:00
parent 328319b853
commit 433d32f237
3 changed files with 88 additions and 274 deletions

View file

@ -55,50 +55,11 @@
/// @note These enums must be globally scoped so that they work with the inline assembly
enum ProcessorType
{
// x86
CPU_X86Compatible,
CPU_Intel_Unknown,
CPU_Intel_486,
CPU_Intel_Pentium,
CPU_Intel_PentiumMMX,
CPU_Intel_PentiumPro,
CPU_Intel_PentiumII,
CPU_Intel_PentiumCeleron,
CPU_Intel_PentiumIII,
CPU_Intel_Pentium4,
CPU_Intel_PentiumM,
CPU_Intel_Core,
CPU_Intel_Core2,
CPU_Intel_Corei7Xeon, // Core i7 or Xeon
CPU_AMD_K6,
CPU_AMD_K6_2,
CPU_AMD_K6_3,
CPU_AMD_Athlon,
CPU_AMD_Phenom,
CPU_AMD_PhenomII,
CPU_AMD_Bulldozer,
CPU_AMD_Unknown,
CPU_Cyrix_6x86,
CPU_Cyrix_MediaGX,
CPU_Cyrix_6x86MX,
CPU_Cyrix_GXm, ///< Media GX w/ MMX
CPU_Cyrix_Unknown,
// PowerPC
CPU_PowerPC_Unknown,
CPU_PowerPC_601,
CPU_PowerPC_603,
CPU_PowerPC_603e,
CPU_PowerPC_603ev,
CPU_PowerPC_604,
CPU_PowerPC_604e,
CPU_PowerPC_604ev,
CPU_PowerPC_G3,
CPU_PowerPC_G4,
CPU_PowerPC_G4_7450,
CPU_PowerPC_G4_7455,
CPU_PowerPC_G4_7447,
CPU_PowerPC_G5,
CPU_ArmCompatible,
CPU_Intel,
CPU_AMD,
CPU_Apple
};
/// Properties for CPU.

View file

@ -31,12 +31,11 @@ Signal<void(void)> Platform::SystemInfoReady;
enum CPUFlags
{
// EDX Register flags
BIT_FPU = BIT(0),
BIT_RDTSC = BIT(4),
BIT_MMX = BIT(23),
BIT_SSE = BIT(25),
BIT_SSE2 = BIT(26),
BIT_3DNOW = BIT(31),
BIT_3DNOW = BIT(31), // only available for amd cpus in x86
// These use a different value for comparison than the above flags (ECX Register)
BIT_SSE3 = BIT(0),
@ -47,241 +46,63 @@ enum CPUFlags
// fill the specified structure with information obtained from asm code
void SetProcessorInfo(Platform::SystemInfo_struct::Processor& pInfo,
char* vendor, U32 processor, U32 properties, U32 properties2)
char* vendor, char* brand, U32 processor, U32 properties, U32 properties2)
{
Platform::SystemInfo.processor.properties |= (properties & BIT_FPU) ? CPU_PROP_FPU : 0;
Platform::SystemInfo.processor.properties |= (properties & BIT_RDTSC) ? CPU_PROP_RDTSC : 0;
Platform::SystemInfo.processor.properties |= (properties & BIT_MMX) ? CPU_PROP_MMX : 0;
// always assume FPU is available in 2021...
pInfo.properties |= CPU_PROP_FPU;
#if defined(TORQUE_CPU_X86) || defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
pInfo.properties |= CPU_PROP_LE;
#endif
#if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
pInfo.properties |= CPU_PROP_64bit;
#endif
#if defined(TORQUE_CPU_X86) || defined(TORQUE_CPU_X64)
pInfo.properties |= (properties & BIT_RDTSC) ? CPU_PROP_RDTSC : 0;
pInfo.properties |= (properties & BIT_MMX) ? CPU_PROP_MMX : 0;
pInfo.properties |= (properties & BIT_SSE) ? CPU_PROP_SSE : 0;
pInfo.properties |= (properties & BIT_SSE2) ? CPU_PROP_SSE2 : 0;
pInfo.properties |= (properties2 & BIT_SSE3) ? CPU_PROP_SSE3 : 0;
pInfo.properties |= (properties2 & BIT_SSE3xt) ? CPU_PROP_SSE3xt : 0;
pInfo.properties |= (properties2 & BIT_SSE4_1) ? CPU_PROP_SSE4_1 : 0;
pInfo.properties |= (properties2 & BIT_SSE4_2) ? CPU_PROP_SSE4_2 : 0;
#endif
if (dStricmp(vendor, "GenuineIntel") == 0)
{
pInfo.properties |= (properties & BIT_SSE) ? CPU_PROP_SSE : 0;
pInfo.properties |= (properties & BIT_SSE2) ? CPU_PROP_SSE2 : 0;
pInfo.properties |= (properties2 & BIT_SSE3) ? CPU_PROP_SSE3 : 0;
pInfo.properties |= (properties2 & BIT_SSE3xt) ? CPU_PROP_SSE3xt : 0;
pInfo.properties |= (properties2 & BIT_SSE4_1) ? CPU_PROP_SSE4_1 : 0;
pInfo.properties |= (properties2 & BIT_SSE4_2) ? CPU_PROP_SSE4_2 : 0;
pInfo.type = CPU_Intel_Unknown;
// switch on processor family code
switch ((processor >> 8) & 0x0f)
{
case 4:
pInfo.type = CPU_Intel_486;
pInfo.name = StringTable->insert("Intel 486 class");
break;
// Pentium Family
case 5:
// switch on processor model code
switch ((processor >> 4) & 0xf)
{
case 1:
case 2:
case 3:
pInfo.type = CPU_Intel_Pentium;
pInfo.name = StringTable->insert("Intel Pentium");
break;
case 4:
pInfo.type = CPU_Intel_PentiumMMX;
pInfo.name = StringTable->insert("Intel Pentium MMX");
break;
default:
pInfo.type = CPU_Intel_Pentium;
pInfo.name = StringTable->insert( "Intel (unknown)" );
break;
}
break;
// Pentium Pro/II/II family
case 6:
{
U32 extendedModel = ( processor & 0xf0000 ) >> 16;
// switch on processor model code
switch ((processor >> 4) & 0xf)
{
case 1:
pInfo.type = CPU_Intel_PentiumPro;
pInfo.name = StringTable->insert("Intel Pentium Pro");
break;
case 3:
case 5:
pInfo.type = CPU_Intel_PentiumII;
pInfo.name = StringTable->insert("Intel Pentium II");
break;
case 6:
pInfo.type = CPU_Intel_PentiumCeleron;
pInfo.name = StringTable->insert("Intel Pentium Celeron");
break;
case 7:
case 8:
case 11:
pInfo.type = CPU_Intel_PentiumIII;
pInfo.name = StringTable->insert("Intel Pentium III");
break;
case 0xA:
if( extendedModel == 1)
{
pInfo.type = CPU_Intel_Corei7Xeon;
pInfo.name = StringTable->insert( "Intel Core i7 / Xeon" );
}
else
{
pInfo.type = CPU_Intel_PentiumIII;
pInfo.name = StringTable->insert( "Intel Pentium III Xeon" );
}
break;
case 0xD:
if( extendedModel == 1 )
{
pInfo.type = CPU_Intel_Corei7Xeon;
pInfo.name = StringTable->insert( "Intel Core i7 / Xeon" );
}
else
{
pInfo.type = CPU_Intel_PentiumM;
pInfo.name = StringTable->insert( "Intel Pentium/Celeron M" );
}
break;
case 0xE:
pInfo.type = CPU_Intel_Core;
pInfo.name = StringTable->insert( "Intel Core" );
break;
case 0xF:
pInfo.type = CPU_Intel_Core2;
pInfo.name = StringTable->insert( "Intel Core 2" );
break;
default:
pInfo.type = CPU_Intel_PentiumPro;
pInfo.name = StringTable->insert( "Intel (unknown)" );
break;
}
break;
}
// Pentium4 Family
case 0xf:
pInfo.type = CPU_Intel_Pentium4;
pInfo.name = StringTable->insert( "Intel Pentium 4" );
break;
default:
pInfo.type = CPU_Intel_Unknown;
pInfo.name = StringTable->insert( "Intel (unknown)" );
break;
}
pInfo.type = CPU_Intel;
pInfo.name = StringTable->insert(brand ? brand : "Intel (Unknown)");
}
//--------------------------------------
else if (dStricmp(vendor, "AuthenticAMD") == 0)
{
pInfo.name = StringTable->insert(brand ? brand : "AMD (unknown)");
pInfo.type = CPU_AMD;
// 3dnow! is only available in AMD cpus on x86. Otherwise its not reliably set.
pInfo.properties |= (properties & BIT_3DNOW) ? CPU_PROP_3DNOW : 0;
}
else if (dStricmp(vendor, "Apple") == 0)
{
pInfo.name = StringTable->insert(brand ? brand : "Apple (unknown)");
pInfo.type = CPU_Apple;
}
else
if (dStricmp(vendor, "AuthenticAMD") == 0)
{
// AthlonXP processors support SSE
pInfo.properties |= (properties & BIT_SSE) ? CPU_PROP_SSE : 0;
pInfo.properties |= ( properties & BIT_SSE2 ) ? CPU_PROP_SSE2 : 0;
pInfo.properties |= (properties & BIT_3DNOW) ? CPU_PROP_3DNOW : 0;
// Phenom and PhenomII support SSE3, SSE4a
pInfo.properties |= ( properties2 & BIT_SSE3 ) ? CPU_PROP_SSE3 : 0;
pInfo.properties |= ( properties2 & BIT_SSE4_1 ) ? CPU_PROP_SSE4_1 : 0;
// switch on processor family code
switch ((processor >> 8) & 0xf)
{
// K6 Family
case 5:
// switch on processor model code
switch ((processor >> 4) & 0xf)
{
case 0:
case 1:
case 2:
case 3:
pInfo.type = CPU_AMD_K6_3;
pInfo.name = StringTable->insert("AMD K5");
break;
case 4:
case 5:
case 6:
case 7:
pInfo.type = CPU_AMD_K6;
pInfo.name = StringTable->insert("AMD K6");
break;
case 8:
pInfo.type = CPU_AMD_K6_2;
pInfo.name = StringTable->insert("AMD K6-2");
break;
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
pInfo.type = CPU_AMD_K6_3;
pInfo.name = StringTable->insert("AMD K6-3");
break;
}
break;
// Athlon Family
case 6:
pInfo.type = CPU_AMD_Athlon;
pInfo.name = StringTable->insert("AMD Athlon");
break;
// Phenom Family
case 15:
pInfo.type = CPU_AMD_Phenom;
pInfo.name = StringTable->insert("AMD Phenom");
break;
// Phenom II Family
case 16:
pInfo.type = CPU_AMD_PhenomII;
pInfo.name = StringTable->insert("AMD Phenom II");
break;
// Bulldozer Family
case 17:
pInfo.type = CPU_AMD_Bulldozer;
pInfo.name = StringTable->insert("AMD Bulldozer");
break;
default:
pInfo.type = CPU_AMD_Unknown;
pInfo.name = StringTable->insert("AMD (unknown)");
break;
}
}
//--------------------------------------
else
if (dStricmp(vendor, "CyrixInstead") == 0)
{
switch (processor)
{
case 0x520:
pInfo.type = CPU_Cyrix_6x86;
pInfo.name = StringTable->insert("Cyrix 6x86");
break;
case 0x440:
pInfo.type = CPU_Cyrix_MediaGX;
pInfo.name = StringTable->insert("Cyrix Media GX");
break;
case 0x600:
pInfo.type = CPU_Cyrix_6x86MX;
pInfo.name = StringTable->insert("Cyrix 6x86mx/MII");
break;
case 0x540:
pInfo.type = CPU_Cyrix_GXm;
pInfo.name = StringTable->insert("Cyrix GXm");
break;
default:
pInfo.type = CPU_Cyrix_Unknown;
pInfo.name = StringTable->insert("Cyrix (unknown)");
break;
}
}
{
#if defined(TORQUE_CPU_X86) || defined(TORQUE_CPU_X64)
pInfo.name = StringTable->insert(brand ? brand : "x86 Compatible (unknown)");
pInfo.type = CPU_X86Compatible;
#elif defined(TORQUE_CPU_ARM64)
pInfo.name = StringTable->insert(brand ? brand : "Arm Compatible (unknown)");
pInfo.type = CPU_ArmCompatible;
#else
#error "Unknown CPU Architecture"
#endif
}
// Get multithreading caps.
CPUInfo::EConfig config = CPUInfo::CPUCount( pInfo.numLogicalProcessors, pInfo.numAvailableCores, pInfo.numPhysicalProcessors );
pInfo.isHyperThreaded = CPUInfo::isHyperThreaded( config );
pInfo.isMultiCore = CPUInfo::isMultiCore( config );

View file

@ -30,7 +30,7 @@
Platform::SystemInfo_struct Platform::SystemInfo;
extern void PlatformBlitInit();
extern void SetProcessorInfo(Platform::SystemInfo_struct::Processor& pInfo,
char* vendor, U32 processor, U32 properties, U32 properties2); // platform/platformCPU.cc
char* vendor, char* brand, U32 processor, U32 properties, U32 properties2); // platform/platformCPU.cc
void Processor::init()
{
@ -45,7 +45,7 @@ void Processor::init()
Platform::SystemInfo.processor.type = CPU_X86Compatible;
Platform::SystemInfo.processor.name = StringTable->insert("Unknown x86 Compatible");
Platform::SystemInfo.processor.mhz = 0;
Platform::SystemInfo.processor.properties = CPU_PROP_C | CPU_PROP_LE;
Platform::SystemInfo.processor.properties = CPU_PROP_C;
char vendor[0x20];
dMemset(vendor, 0, sizeof(vendor));
@ -65,7 +65,31 @@ void Processor::init()
properties = cpuInfo[3]; // edx
properties2 = cpuInfo[2]; // ecx
SetProcessorInfo(Platform::SystemInfo.processor, vendor, processor, properties, properties2);
char brand[0x40];
dMemset(brand, 0, sizeof(brand));
S32 extendedInfo[4];
__cpuid(extendedInfo, 0x80000000);
S32 numberExtendedIds = extendedInfo[0];
// Sets brand
if (numberExtendedIds >= 0x80000004)
{
int offset = 0;
for (int i = 0; i < 3; ++i)
{
S32 brandInfo[4];
__cpuidex(brandInfo, 0x80000002 + i, 0);
*reinterpret_cast<int*>(brand + offset + 0) = brandInfo[0];
*reinterpret_cast<int*>(brand + offset + 4) = brandInfo[1];
*reinterpret_cast<int*>(brand + offset + 8) = brandInfo[2];
*reinterpret_cast<int*>(brand + offset + 12) = brandInfo[3];
offset += sizeof(S32) * 4;
}
}
SetProcessorInfo(Platform::SystemInfo.processor, vendor, brand, processor, properties, properties2);
// now calculate speed of processor...
U32 nearmhz = 0; // nearest rounded mhz
@ -126,6 +150,14 @@ void Processor::init()
Con::printf( " SSE detected" );
if( Platform::SystemInfo.processor.properties & CPU_PROP_SSE2 )
Con::printf( " SSE2 detected" );
if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3)
Con::printf( " SSE3 detected" );
if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3xt)
Con::printf( " SSE3ex detected ");
if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_1)
Con::printf( " SSE4.1 detected" );
if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_2)
Con::printf( " SSE4.2 detected" );
if( Platform::SystemInfo.processor.isHyperThreaded )
Con::printf( " HT detected" );
if( Platform::SystemInfo.processor.properties & CPU_PROP_MP )