EHS/src/system/CPU.cpp
Karutoh bcd71cf2b5
All checks were successful
Build & Release / Windows-AMD64-Build (push) Successful in 1m8s
Build & Release / Linux-AMD64-Build (push) Successful in 1m30s
Build & Release / Linux-AARCH64-Build (push) Successful in 3m21s
Adjusted workflow.
2024-02-05 22:25:30 -08:00

561 lines
13 KiB
C++

#include "ehs/system/CPU.h"
#include "ehs/Log.h"
#include "ehs/io/File.h"
#include "ehs/json/Json.h"
#include "ehs/system/Thread.h"
namespace ehs
{
#ifdef EHS_OS_LINUX
UInt_64 CPU::TSC_Freq = 0;
#endif
Architecture CPU::GetArchitecture()
{
#if defined(EHS_ARCH_X64)
return Architecture::X64;
#elif defined(EHS_ARCH_ARM64)
return Architecture::ARM64;
#else
return Architecture::UNKNOWN;
#endif
}
UInt_8 CPU::PointerSize()
{
return sizeof(void*);
}
Endianness CPU::GetEndianness()
{
#if defined(EHS_LITTLE_ENDIAN)
return Endianness::LE;
#elif defined(EHS_BIG_ENDIAN)
return Endianness::BE;
#else
UInt_16 tmp = 1;
if (((Byte*)&tmp)[0] == 1)
return Endianness::LE;
return Endianness::BE;
#endif
}
UInt_64 CPU::GetTSC_Freq()
{
#if defined(EHS_OS_WINDOWS)
LARGE_INTEGER frequency = {};
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
#elif defined(EHS_OS_LINUX)
if (!TSC_Freq)
TSC_Freq = RetrieveTSC_Freq();
return TSC_Freq;
#endif
return 0;
}
UInt_64 CPU::GetTSC()
{
#if defined(EHS_OS_WINDOWS)
LARGE_INTEGER count = {};
QueryPerformanceCounter(&count);
return count.QuadPart;
#elif defined(EHS_OS_LINUX)
TSC tsc;
RDTSCP(&tsc);
#if defined(EHS_ARCH_X64)
UInt_64 result = 0;
#if defined(EHS_LITTLE_ENDIAN)
((UInt_32*)&result)[0] = tsc.lowCount;
((UInt_32*)&result)[1] = tsc.highCount;
#elif defined(EHS_BIG_ENDIAN)
((UInt_32*)&result)[0] = tsc.highCount;
((UInt_32*)&result)[1] = tsc.lowCount;
#endif
return result;
#elif defined(EHS_ARCH_X86)
return tsc.lowPart;
#endif
#endif
return 0;
}
UInt_8 CPU::GetSteppingId()
{
return (UInt_8)GetInfoBits() & 0x00001111;
}
UInt_8 CPU::GetModelId()
{
return (UInt_8)GetInfoBits() & 0x11110000;
}
UInt_8 CPU::GetFamilyId()
{
return (UInt_8)(GetInfoBits() >> 8) & 0x00001111;
}
UInt_8 CPU::GetProcessorTypeId()
{
return (UInt_8)(GetInfoBits() >> 12) & 0x00000011;
}
UInt_8 CPU::GetExtModelId()
{
return (UInt_8)(GetInfoBits() >> 16) & 0x00001111;
}
UInt_8 CPU::GetExtFamilyId()
{
return (UInt_8)(GetInfoBits() >> 20);
}
bool CPU::HasFPU()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000001;
}
bool CPU::HasVME()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000010;
}
bool CPU::HasDE()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000100;
}
bool CPU::HasPSE()
{
return GetFeatureBits_1() & 0b00000000000000000000000000001000;
}
bool CPU::HasTSC()
{
return GetFeatureBits_1() & 0b00000000000000000000000000010000;
}
bool CPU::HasMSR()
{
return GetFeatureBits_1() & 0b00000000000000000000000000100000;
}
bool CPU::HasPAE()
{
return GetFeatureBits_1() & 0b00000000000000000000000001000000;
}
bool CPU::HasMCE()
{
return GetFeatureBits_1() & 0b00000000000000000000000010000000;
}
bool CPU::HasCX8()
{
return GetFeatureBits_1() & 0b00000000000000000000000100000000;
}
bool CPU::HasAPIC()
{
return GetFeatureBits_1() & 0b00000000000000000000001000000000;
}
bool CPU::HasSEP()
{
return GetFeatureBits_1() & 0b00000000000000000000100000000000;
}
bool CPU::HasMTRR()
{
return GetFeatureBits_1() & 0b00000000000000000001000000000000;
}
bool CPU::HasPGE()
{
return GetFeatureBits_1() & 0b00000000000000000010000000000000;
}
bool CPU::HasMCA()
{
return GetFeatureBits_1() & 0b00000000000000000100000000000000;
}
bool CPU::HasCMOV()
{
return GetFeatureBits_1() & 0b00000000000000001000000000000000;
}
bool CPU::HasPAT()
{
return GetFeatureBits_1() & 0b00000000000000010000000000000000;
}
bool CPU::HasPSE_36()
{
return GetFeatureBits_1() & 0b00000000000000100000000000000000;
}
bool CPU::HasPSN()
{
return GetFeatureBits_1() & 0b00000000000001000000000000000000;
}
bool CPU::HasCLFSH()
{
return GetFeatureBits_1() & 0b00000000000010000000000000000000;
}
bool CPU::HasDS()
{
return GetFeatureBits_1() & 0b00000000001000000000000000000000;
}
bool CPU::HasACPI()
{
return GetFeatureBits_1() & 0b00000000010000000000000000000000;
}
bool CPU::HasMMX()
{
return GetFeatureBits_1() & 0b00000000100000000000000000000000;
}
bool CPU::HasFXSR()
{
return GetFeatureBits_1() & 0b00000001000000000000000000000000;
}
bool CPU::HasSSE()
{
return GetFeatureBits_1() & 0b00000010000000000000000000000000;
}
bool CPU::HasSSE2()
{
return GetFeatureBits_1() & 0b00000100000000000000000000000000;
}
bool CPU::HasSS()
{
return GetFeatureBits_1() & 0b00001000000000000000000000000000;
}
bool CPU::HasHTT()
{
return GetFeatureBits_1() & 0b00010000000000000000000000000000;
}
bool CPU::HasTM()
{
return GetFeatureBits_1() & 0b00100000000000000000000000000000;
}
bool CPU::HasIA64()
{
return GetFeatureBits_1() & 0b01000000000000000000000000000000;
}
bool CPU::HasPBE()
{
return GetFeatureBits_1() & 0b10000000000000000000000000000000;
}
bool CPU::HasSSE3()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000001;
}
bool CPU::HasPCLMULQDQ()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000010;
}
bool CPU::HasDTES64()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000100;
}
bool CPU::HasMONITOR()
{
return GetFeatureBits_2() & 0b00000000000000000000000000001000;
}
bool CPU::HasDS_CPL()
{
return GetFeatureBits_2() & 0b00000000000000000000000000010000;
}
bool CPU::HasVMX()
{
return GetFeatureBits_2() & 0b00000000000000000000000000100000;
}
bool CPU::HasSMX()
{
return GetFeatureBits_2() & 0b00000000000000000000000001000000;
}
bool CPU::HasEST()
{
return GetFeatureBits_2() & 0b00000000000000000000000010000000;
}
bool CPU::HasTM2()
{
return GetFeatureBits_2() & 0b00000000000000000000000100000000;
}
bool CPU::HasSSSE3()
{
return GetFeatureBits_2() & 0b00000000000000000000001000000000;
}
bool CPU::HasCNXT_ID()
{
return GetFeatureBits_2() & 0b00000000000000000000010000000000;
}
bool CPU::HasSDBG()
{
return GetFeatureBits_2() & 0b00000000000000000000100000000000;
}
bool CPU::HasFMA()
{
return GetFeatureBits_2() & 0b00000000000000000001000000000000;
}
bool CPU::HasCX16()
{
return GetFeatureBits_2() & 0b00000000000000000010000000000000;
}
bool CPU::HasXTPR()
{
return GetFeatureBits_2() & 0b00000000000000000100000000000000;
}
bool CPU::HasPDCM()
{
return GetFeatureBits_2() & 0b00000000000000001000000000000000;
}
bool CPU::HasPCID()
{
return GetFeatureBits_2() & 0b00000000000000100000000000000000;
}
bool CPU::HasDCA()
{
return GetFeatureBits_2() & 0b00000000000001000000000000000000;
}
bool CPU::HasSSE4_1()
{
return GetFeatureBits_2() & 0b00000000000010000000000000000000;
}
bool CPU::HasSSE4_2()
{
return GetFeatureBits_2() & 0b00000000000100000000000000000000;
}
bool CPU::HasX2APIC()
{
return GetFeatureBits_2() & 0b00000000001000000000000000000000;
}
bool CPU::HasMOVBE()
{
return GetFeatureBits_2() & 0b00000000010000000000000000000000;
}
bool CPU::HasPOPCNT()
{
return GetFeatureBits_2() & 0b00000000100000000000000000000000;
}
bool CPU::HasTSC_DEADLINE()
{
return GetFeatureBits_2() & 0b00000001000000000000000000000000;
}
bool CPU::HasAES()
{
return GetFeatureBits_2() & 0b00000010000000000000000000000000;
}
bool CPU::HasXSAVE()
{
return GetFeatureBits_2() & 0b00000100000000000000000000000000;
}
bool CPU::HasOSXSAVE()
{
return GetFeatureBits_2() & 0b00001000000000000000000000000000;
}
bool CPU::HasAVX()
{
return GetFeatureBits_2() & 0b00010000000000000000000000000000;
}
bool CPU::HasF16C()
{
return GetFeatureBits_2() & 0b00100000000000000000000000000000;
}
bool CPU::HasRDRND()
{
return GetFeatureBits_2() & 0b01000000000000000000000000000000;
}
bool CPU::HasHYPERVISOR()
{
return GetFeatureBits_2() & 0b10000000000000000000000000000000;
}
bool CPU::HasAVX2()
{
return GetExtFeatureBits_1() & 0b00000000000000000000000000100000;
}
bool CPU::HasRDSEED()
{
return GetExtFeatureBits_1() & 0b00000000000001000000000000000000;
}
bool CPU::HasADX()
{
return GetExtFeatureBits_1() & 0b00000000000010000000000000000000;
}
/*
Str_8 CPU::ToStr()
{
return "Manufacturer: " + GetManufacturer() + "\r\n" +
"Brand: " + GetBrand() + "\r\n" +
"Stepping Id: " + Str_8::FromNum(GetSteppingId()) + "\r\n" +
"GpuModel Id: " + Str_8::FromNum(GetModelId()) + "\r\n" +
"Family Id: " + Str_8::FromNum(GetFamilyId()) + "\r\n" +
"Processor Type Id: " + Str_8::FromNum(GetProcessorTypeId()) + "\r\n" +
"Extended GpuModel Id: " + Str_8::FromNum(GetExtModelId()) + "\r\n" +
"Extended Family Id: " + Str_8::FromNum(GetExtFamilyId()) + "\r\n" +
"Has FPU: " + Str_8::FromNum((UInt_8)HasFPU()) + "\r\n" +
"Has SSE: " + Str_8::FromNum((UInt_8)HasSSE()) + "\r\n" +
"Has SSE 2: " + Str_8::FromNum((UInt_8)HasSSE2()) + "\r\n" +
"Has SSE 3: " + Str_8::FromNum((UInt_8)HasSSE3()) + "\r\n" +
"Has SSSE 3: " + Str_8::FromNum((UInt_8)HasSSSE3()) + "\r\n" +
"Has SSE 4.1: " + Str_8::FromNum((UInt_8)HasSSE4_1()) + "\r\n" +
"Has SSE 4.2: " + Str_8::FromNum((UInt_8)HasSSE4_2()) + "\r\n" +
"Has AVX: " + Str_8::FromNum((UInt_8)HasAVX()) + "\r\n" +
"Has RDRND: " + Str_8::FromNum((UInt_8)HasRDRND()) + "\r\n" +
"Has AVX 2: " + Str_8::FromNum((UInt_8)HasAVX2()) + "\r\n" +
"Has ADX: " + Str_8::FromNum((UInt_8)HasADX()) + "\r\n" +
"Has RDSEED: " + Str_8::FromNum((UInt_8)HasRDSEED());
}
*/
UInt_64 CPU::RetrieveTSC_Freq()
{
File tscDatabase("TSC_Frequencies.json", Mode::READ_WRITE, Disposition::CREATE_PERSISTENT);
if (tscDatabase.Size())
{
Json json(tscDatabase.ReadStr_8(tscDatabase.Size()), 5);
JsonObj* root = (JsonObj*)json.GetValue();
Char_8 manu[13];
manu[12] = 0;
GetManufacturer(manu);
JsonVar* jManu = root->GetVar(manu);
if (jManu)
{
JsonObj* joManu = (JsonObj*)jManu->GetValue();
Char_8 brand[48];
GetBrand(brand);
JsonVar* jBrand = joManu->GetVar(brand);
if (jBrand)
{
tscDatabase.Release();
return (UInt_64)*(JsonNum*)jBrand->GetValue();
}
else
{
UInt_64 tscFreq = CalculateTSC_Freq();
joManu->AddVar({brand, tscFreq});
tscDatabase.SeekBeginning();
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
}
else
{
UInt_64 tscFreq = CalculateTSC_Freq();
Char_8 brand[48];
GetBrand(brand);
JsonObj cpus(1, 0);
cpus[0] = JsonVar(brand, tscFreq);
JsonVar tmp({brand, cpus});
root->AddVar(tmp);
tscDatabase.SeekBeginning();
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
}
UInt_64 tscFreq = CalculateTSC_Freq();
Char_8 manu[13];
manu[12] = 0;
GetManufacturer(manu);
Char_8 brand[49];
brand[48] = 0;
GetBrand(brand);
JsonObj jManu(1, 0);
jManu[0] = JsonVar(brand, tscFreq);
JsonObj root(1, 0);
root[0] = JsonVar(manu, jManu);
Json json(root);
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
UInt_64 CPU::CalculateTSC_Freq()
{
UInt_64 result = GetTSC();
Thread::SleepFor(10000);
return (GetTSC() - result) / 10;
}
}