AuroraRuntime/Source/HWInfo/AuCpuId.cpp

469 lines
11 KiB
C++
Raw Normal View History

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
2022-11-17 07:46:07 +00:00
File: AuCpuId.cpp
Date: 2022-1-25
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
2022-11-17 07:46:07 +00:00
#include "AuHWInfo.hpp"
#include "AuCpuId.hpp"
#if defined(AURORA_COMPILER_CLANG) || defined(AURORA_IS_POSIX_DERIVED)
#include <cpuid.h>
#endif
2022-11-17 07:46:07 +00:00
#include "AuCpuInfo.hpp"
namespace Aurora::HWInfo
{
static AuUInt32 gGuessedCores {};
static AuUInt32 gGuessedThreads {};
union CPUIdContext
{
struct
{
AuUInt32 eax;
AuUInt32 ebx;
AuUInt32 ecx;
AuUInt32 edx;
};
int regs[4];
};
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)
#if defined(AURORA_COMPILER_MSVC)
static CPUIdContext cpuid(AuUInt32 a)
{
CPUIdContext context;
__cpuid(context.regs, a);
return context;
}
#elif defined(AURORA_COMPILER_CLANG) || defined(AURORA_COMPILER_GCC)
static CPUIdContext cpuid(AuUInt32 a)
{
CPUIdContext context;
__get_cpuid(a, &context.eax, &context.ebx, &context.ecx, &context.edx);
return context;
}
#else
static CPUIdContext cpuid(AuUInt32 a)
{
return {};
}
#endif
#else
static CPUIdContext cpuid(AuUInt32 a)
{
return {};
}
#endif
bool CpuId::SSE3() const
{
return AuTestBit(f_1_ECX, 0);
}
bool CpuId::PCLMULQDQ() const
{
return AuTestBit(f_1_ECX, 1);
}
bool CpuId::MONITOR() const
{
return AuTestBit(f_1_ECX, 3);
}
bool CpuId::SSSE3() const
{
return AuTestBit(f_1_ECX, 9);
}
bool CpuId::FMA() const
{
return AuTestBit(f_1_ECX, 12);
}
bool CpuId::CMPXCHG16B() const
{
return AuTestBit(f_1_ECX, 13);
}
bool CpuId::SSE41() const
{
return AuTestBit(f_1_ECX, 19);
}
bool CpuId::SSE42() const
{
return AuTestBit(f_1_ECX, 20);
}
bool CpuId::MOVBE() const
{
return AuTestBit(f_1_ECX, 22);
}
bool CpuId::POPCNT() const
{
return AuTestBit(f_1_ECX, 23);
}
bool CpuId::AES() const
{
return AuTestBit(f_1_ECX, 25);
}
bool CpuId::XSAVE() const
{
return AuTestBit(f_1_ECX, 26);
}
bool CpuId::OSXSAVE() const
{
return AuTestBit(f_1_ECX, 27);
}
bool CpuId::AVX() const
{
return AuTestBit(f_1_ECX, 28);
}
bool CpuId::F16C() const
{
return AuTestBit(f_1_ECX, 29);
}
bool CpuId::RDRAND() const
{
return AuTestBit(f_1_ECX, 30);
}
bool CpuId::MSR() const
{
return AuTestBit(f_1_EDX, 5);
}
bool CpuId::CX8() const
{
return AuTestBit(f_1_EDX, 8);
}
bool CpuId::SEP() const
{
return AuTestBit(f_1_EDX, 11);
}
bool CpuId::CMOV() const
{
return AuTestBit(f_1_EDX, 15);
}
bool CpuId::CLFSH() const
{
return AuTestBit(f_1_EDX, 19);
}
bool CpuId::MMX() const
{
return AuTestBit(f_1_EDX, 23);
}
bool CpuId::FXSR() const
{
return AuTestBit(f_1_EDX, 24);
}
bool CpuId::SSE() const
{
return AuTestBit(f_1_EDX, 25);
}
bool CpuId::SSE2() const
{
return AuTestBit(f_1_EDX, 26);
}
bool CpuId::FSGSBASE() const
{
return AuTestBit(f_7_EBX, 0);
}
bool CpuId::BMI1() const
{
return AuTestBit(f_7_EBX, 3);
}
bool CpuId::HLE() const
{
return isIntel && AuTestBit(f_7_EBX, 4);
}
bool CpuId::AVX2() const
{
return AuTestBit(f_7_EBX, 5);
}
bool CpuId::BMI2() const
{
return AuTestBit(f_7_EBX, 8);
}
bool CpuId::ERMS() const
{
return AuTestBit(f_7_EBX, 9);
}
bool CpuId::INVPCID() const
{
return AuTestBit(f_7_EBX, 10);
}
bool CpuId::RTM() const
{
return isIntel && AuTestBit(f_7_EBX, 11);
}
bool CpuId::AVX512F() const
{
return AuTestBit(f_7_EBX, 16);
}
bool CpuId::RDSEED() const
{
return AuTestBit(f_7_EBX, 18);
}
bool CpuId::ADX() const
{
return AuTestBit(f_7_EBX, 19);
}
bool CpuId::AVX512PF() const
{
return AuTestBit(f_7_EBX, 26);
}
bool CpuId::AVX512ER() const
{
return AuTestBit(f_7_EBX, 27);
}
bool CpuId::AVX512CD() const
{
return AuTestBit(f_7_EBX, 28);
}
bool CpuId::SHA() const
{
return AuTestBit(f_7_EBX, 29);
}
bool CpuId::PREFETCHWT1() const
{
return AuTestBit(f_7_ECX, 0);
}
bool CpuId::LAHF() const
{
return AuTestBit(f_81_ECX, 0);
}
bool CpuId::LZCNT() const
{
return isIntel && AuTestBit(f_81_ECX, 5);
}
bool CpuId::ABM() const
{
return isAMD && AuTestBit(f_81_ECX, 5);
}
bool CpuId::SSE4a() const
{
return isAMD && AuTestBit(f_81_ECX, 6);
}
bool CpuId::XOP() const
{
return isAMD && AuTestBit(f_81_ECX, 11);
}
bool CpuId::TBM() const
{
return isAMD && AuTestBit(f_81_ECX, 21);
}
bool CpuId::SYSCALL() const
{
return isIntel && AuTestBit(f_81_EDX, 11);
}
bool CpuId::MMXEXT() const
{
return isAMD && AuTestBit(f_81_EDX, 22);
}
bool CpuId::RDTSCP() const
{
return isIntel && AuTestBit(f_81_EDX, 27);
}
bool CpuId::_3DNOWEXT() const
{
return isAMD && AuTestBit(f_81_EDX, 30);
}
bool CpuId::_3DNOW() const
{
return isAMD && AuTestBit(f_81_EDX, 31);
}
AuString CpuId::ToString() const
{
return fmt::format(
"FMA {}\t\tFSGSBASE {}\t\tCLFSH {}\t\t\tERMS {}{}"
"CMPXCHG16B {}\t\tAVX512PF {}\t\tMOVBE {}\t\t\tRTM {}{}"
"POPCNT {}\t\tAVX512ER {}\t\tMONITOR {}\t\t\tLAHF {}{}"
"SSE {}\t\tAVX512CD {}\t\tF16C {}\t\t\tABM {}{}"
"SSE2 {}\t\tSYSCALL {}\t\tRDRAND {}\t\t\tXOP {}{}"
"SSE3 {}\t\tAES {}\t\tMSR {}\t\t\tTBM {}{}"
"SSSE3 {}\t\tRDTSCP {}\t\tCX8 {}\t\t\tMMXEXT {}{}"
"SSE41 {}\t\tXSAVE {}\t\tSEP {}\t\t\tRDSEED {}{}"
"SSE42 {}\t\tOSXSAVE {}\t\tCMOV {}\t\t\tPREFETCHWT1 {}{}"
"SSE4a {}\t\tSHA {}\t\tFXSR {}\t\t\tPCLMULQDQ {}{}"
"AVX {}\t\tAVX512F {}\t\tBMI1 {}\t\t\tINVPCID {}{}"
"AVX2 {}\t\tLZCNT {}\t\tHLE {}\t\t\t_3DNOWEXT {}{}"
"MMX {}\t\tADX {}\t\tBMI2 {}\t\t\t_3DNOW {}",
FMA(), FSGSBASE(), CLFSH(), ERMS(), Aurora::Locale::NewLine(),
CMPXCHG16B(), AVX512PF(), MOVBE(), RTM(), Aurora::Locale::NewLine(),
POPCNT(), AVX512ER(), MONITOR(), LAHF(), Aurora::Locale::NewLine(),
SSE(), AVX512CD(), F16C(), ABM(), Aurora::Locale::NewLine(),
SSE2(), SYSCALL(), RDRAND(), XOP(), Aurora::Locale::NewLine(),
SSE3(), AES(), MSR(), TBM(), Aurora::Locale::NewLine(),
SSSE3(), RDTSCP(), CX8(), MMXEXT(), Aurora::Locale::NewLine(),
SSE41(), XSAVE(), SEP(), RDSEED(), Aurora::Locale::NewLine(),
SSE42(), OSXSAVE(), CMOV(), PREFETCHWT1(), Aurora::Locale::NewLine(),
SSE4a(), SHA(), FXSR(), PCLMULQDQ(), Aurora::Locale::NewLine(),
AVX(), AVX512F(), BMI1(), INVPCID(), Aurora::Locale::NewLine(),
AVX2(), LZCNT(), HLE(), _3DNOWEXT(), Aurora::Locale::NewLine(),
MMX(), ADX(), BMI2(), _3DNOW()
);
}
AuUInt32 GetCPUIDAPICDCores()
{
return gGuessedCores;
}
AuUInt32 GetCPUIDAPICDThreads()
{
return gGuessedThreads;
}
void SetCpuId()
{
// Credit: https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=msvc-160
#if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86)
AuList<CPUIdContext> data;
AuList<CPUIdContext> extdata;
auto cpuInfo = cpuid(0);
auto nIds = cpuInfo.eax;
for (AuUInt i = 0; i <= nIds; ++i)
{
data.push_back(cpuid(i));
}
char vendor[0x20];
AuMemset(vendor, 0, sizeof(vendor));
*reinterpret_cast<AuUInt32 *>(vendor) = cpuInfo.ebx;
*reinterpret_cast<AuUInt32 *>(vendor + 4) = cpuInfo.edx;
*reinterpret_cast<AuUInt32 *>(vendor + 8) = cpuInfo.ecx;
gCpuInfo.cpuId.vendor = vendor;
{
auto regs = cpuid(1);
gGuessedThreads = (regs.ebx >> 16) & 0xff;
}
if (gCpuInfo.cpuId.vendor == "GenuineIntel")
{
gCpuInfo.cpuId.isIntel = true;
auto regs = cpuid(4);
gGuessedCores = ((regs.eax >> 26) & 0x3f) + 1; // DCP cache
if (!gGuessedThreads)
{
gGuessedThreads = gGuessedCores;
}
}
else if (gCpuInfo.cpuId.vendor == "AuthenticAMD")
{
gCpuInfo.cpuId.isAMD = true;
if (!gGuessedCores)
{
auto regs = cpuid(0x80000008);
gGuessedCores = (AuUInt32(regs.ecx) & 0xfful) + 1;
if (!gGuessedThreads)
{
gGuessedThreads = gGuessedCores;
}
}
}
if (!gGuessedThreads && gGuessedCores)
{
gGuessedThreads = gGuessedCores;
}
// load bitset with flags for function 0x00000001
if (nIds >= 1)
{
gCpuInfo.cpuId.f_1_ECX = data[1].ecx;
gCpuInfo.cpuId.f_1_EDX = data[1].edx;
}
// load bitset with flags for function 0x00000007
if (nIds >= 7)
{
gCpuInfo.cpuId.f_7_EBX = data[7].ebx;
gCpuInfo.cpuId.f_7_ECX = data[7].ecx;
}
// gets the number of the highest valid extended ID.
auto cpui = cpuid(0x80000000);
auto nExIds = cpui.eax;
char brand[0x40];
AuMemset(brand, 0, sizeof(brand));
for (AuUInt i = 0x80000000u; i <= nExIds; ++i)
{
extdata.push_back(cpuid(i));
}
// load bitset with flags for function 0x80000001
if (nExIds >= 0x80000001)
{
gCpuInfo.cpuId.f_81_ECX = extdata[1].ecx;
gCpuInfo.cpuId.f_81_EDX = extdata[1].edx;
}
// Interpret CPU brand string if reported
if (nExIds >= 0x80000004)
{
AuMemcpy(brand, &extdata[2], sizeof(cpui));
AuMemcpy(brand + 16, &extdata[3], sizeof(cpui));
AuMemcpy(brand + 32, &extdata[4], sizeof(cpui));
gCpuInfo.cpuId.brand = brand;
}
#endif
}
}