2021-06-27 21:25:29 +00:00
/***
Copyright ( C ) 2021 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : CpuInfo . cpp
Date : 2021 - 6 - 12
Author : Reece
* * */
2021-09-30 14:57:41 +00:00
# include <Source/RuntimeInternal.hpp>
2021-06-27 21:25:29 +00:00
# include "HWInfo.hpp"
# include "CpuInfo.hpp"
2021-09-13 20:11:12 +00:00
# if defined(AURORA_IS_BSD_DERIVED)
# include <sys/types.h>
# include <sys/sysctl.h>
# endif
2021-09-17 19:26:05 +00:00
# if defined(AURORA_IS_POSIX_DERIVED)
# include <stdlib.h>
# include <sys/sysinfo.h>
# endif
2021-10-02 16:07:33 +00:00
# if defined(AURORA_COMPILER_CLANG) || defined(AURORA_IS_POSIX_DERIVED)
# include <cpuid.h>
# endif
2021-09-13 20:11:12 +00:00
namespace Aurora : : HWInfo
{
static CpuInfo gCpuInfo ;
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)
2021-11-05 17:34:23 +00:00
static CPUIdContext cpuid ( AuUInt32 a )
2021-09-13 20:11:12 +00:00
{
CPUIdContext context ;
__cpuid ( context . regs , a ) ;
return context ;
}
# elif defined(AURORA_COMPILER_CLANG) || defined(AURORA_COMPILER_GCC)
2021-11-05 17:34:23 +00:00
static CPUIdContext cpuid ( AuUInt32 a )
2021-09-13 20:11:12 +00:00
{
CPUIdContext context ;
__get_cpuid ( a , & context . eax , & context . ebx , & context . ecx , & context . edx ) ;
return context ;
}
# else
2021-11-05 17:34:23 +00:00
static CPUIdContext cpuid ( AuUInt32 a )
2021-09-13 20:11:12 +00:00
{
return { } ;
}
# endif
# else
2021-11-05 17:34:23 +00:00
static CPUIdContext cpuid ( AuUInt32 a )
2021-09-13 20:11:12 +00:00
{
return { } ;
}
# endif
bool CpuId : : SSE3 ( )
{
return AuTestBit ( f_1_ECX , 0 ) ;
}
bool CpuId : : PCLMULQDQ ( )
{
return AuTestBit ( f_1_ECX , 1 ) ;
}
bool CpuId : : MONITOR ( )
{
return AuTestBit ( f_1_ECX , 3 ) ;
}
bool CpuId : : SSSE3 ( )
{
return AuTestBit ( f_1_ECX , 9 ) ;
}
bool CpuId : : FMA ( )
{
return AuTestBit ( f_1_ECX , 12 ) ;
}
bool CpuId : : CMPXCHG16B ( )
{
return AuTestBit ( f_1_ECX , 13 ) ;
}
bool CpuId : : SSE41 ( )
{
return AuTestBit ( f_1_ECX , 19 ) ;
}
bool CpuId : : SSE42 ( )
{
return AuTestBit ( f_1_ECX , 20 ) ;
}
bool CpuId : : MOVBE ( )
{
return AuTestBit ( f_1_ECX , 22 ) ;
}
bool CpuId : : POPCNT ( )
{
return AuTestBit ( f_1_ECX , 23 ) ;
}
bool CpuId : : AES ( )
{
return AuTestBit ( f_1_ECX , 25 ) ;
}
bool CpuId : : XSAVE ( )
{
return AuTestBit ( f_1_ECX , 26 ) ;
}
bool CpuId : : OSXSAVE ( )
{
return AuTestBit ( f_1_ECX , 27 ) ;
}
bool CpuId : : AVX ( )
{
return AuTestBit ( f_1_ECX , 28 ) ;
}
bool CpuId : : F16C ( )
{
return AuTestBit ( f_1_ECX , 29 ) ;
}
bool CpuId : : RDRAND ( )
{
return AuTestBit ( f_1_ECX , 30 ) ;
}
bool CpuId : : MSR ( )
{
return AuTestBit ( f_1_EDX , 5 ) ;
}
bool CpuId : : CX8 ( )
{
return AuTestBit ( f_1_EDX , 8 ) ;
}
bool CpuId : : SEP ( )
{
return AuTestBit ( f_1_EDX , 11 ) ;
}
bool CpuId : : CMOV ( )
{
return AuTestBit ( f_1_EDX , 15 ) ;
}
bool CpuId : : CLFSH ( )
{
return AuTestBit ( f_1_EDX , 19 ) ;
}
bool CpuId : : MMX ( )
{
return AuTestBit ( f_1_EDX , 23 ) ;
}
bool CpuId : : FXSR ( )
{
return AuTestBit ( f_1_EDX , 24 ) ;
}
bool CpuId : : SSE ( )
{
return AuTestBit ( f_1_EDX , 25 ) ;
}
bool CpuId : : SSE2 ( )
{
return AuTestBit ( f_1_EDX , 26 ) ;
}
bool CpuId : : FSGSBASE ( )
{
return AuTestBit ( f_7_EBX , 0 ) ;
}
bool CpuId : : BMI1 ( )
{
return AuTestBit ( f_7_EBX , 3 ) ;
}
bool CpuId : : HLE ( )
{
2021-09-14 23:56:26 +00:00
return isIntel & & AuTestBit ( f_7_EBX , 4 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : AVX2 ( )
{
return AuTestBit ( f_7_EBX , 5 ) ;
}
bool CpuId : : BMI2 ( )
{
return AuTestBit ( f_7_EBX , 8 ) ;
}
bool CpuId : : ERMS ( )
{
return AuTestBit ( f_7_EBX , 9 ) ;
}
bool CpuId : : INVPCID ( )
{
return AuTestBit ( f_7_EBX , 10 ) ;
}
bool CpuId : : RTM ( )
{
2021-09-14 23:56:26 +00:00
return isIntel & & AuTestBit ( f_7_EBX , 11 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : AVX512F ( )
{
return AuTestBit ( f_7_EBX , 16 ) ;
}
bool CpuId : : RDSEED ( )
{
return AuTestBit ( f_7_EBX , 18 ) ;
}
bool CpuId : : ADX ( )
{
return AuTestBit ( f_7_EBX , 19 ) ;
}
bool CpuId : : AVX512PF ( )
{
return AuTestBit ( f_7_EBX , 26 ) ;
}
bool CpuId : : AVX512ER ( )
{
return AuTestBit ( f_7_EBX , 27 ) ;
}
bool CpuId : : AVX512CD ( )
{
return AuTestBit ( f_7_EBX , 28 ) ;
}
bool CpuId : : SHA ( )
{
return AuTestBit ( f_7_EBX , 29 ) ;
}
bool CpuId : : PREFETCHWT1 ( )
{
return AuTestBit ( f_7_ECX , 0 ) ;
}
bool CpuId : : LAHF ( )
{
return AuTestBit ( f_81_ECX , 0 ) ;
}
bool CpuId : : LZCNT ( )
{
2021-09-14 23:56:26 +00:00
return isIntel & & AuTestBit ( f_81_ECX , 5 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : ABM ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_ECX , 5 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : SSE4a ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_ECX , 6 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : XOP ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_ECX , 11 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : TBM ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_ECX , 21 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : SYSCALL ( )
{
2021-09-14 23:56:26 +00:00
return isIntel & & AuTestBit ( f_81_EDX , 11 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : MMXEXT ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_EDX , 22 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : RDTSCP ( )
{
2021-09-14 23:56:26 +00:00
return isIntel & & AuTestBit ( f_81_EDX , 27 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : _3DNOWEXT ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_EDX , 30 ) ;
2021-09-13 20:11:12 +00:00
}
bool CpuId : : _3DNOW ( )
{
2021-09-14 23:56:26 +00:00
return isAMD & & AuTestBit ( f_81_EDX , 31 ) ;
2021-09-13 20:11:12 +00:00
}
AUKN_SYM const CpuInfo & GetCPUInfo ( )
{
return gCpuInfo ;
}
static 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)
std : : vector < CPUIdContext > data ;
std : : vector < CPUIdContext > extdata ;
auto cpuInfo = cpuid ( 0 ) ;
auto nIds = cpuInfo . eax ;
for ( int i = 0 ; i < = nIds ; + + i )
{
data . push_back ( cpuid ( i ) ) ;
}
char vendor [ 0x20 ] ;
memset ( vendor , 0 , sizeof ( vendor ) ) ;
* reinterpret_cast < int * > ( vendor ) = cpuInfo . ebx ;
* reinterpret_cast < int * > ( vendor + 4 ) = cpuInfo . edx ;
* reinterpret_cast < int * > ( vendor + 8 ) = cpuInfo . ecx ;
gCpuInfo . cpuId . vendor = vendor ;
if ( gCpuInfo . cpuId . vendor = = " GenuineIntel " )
{
gCpuInfo . cpuId . isIntel = true ;
}
else if ( gCpuInfo . cpuId . vendor = = " AuthenticAMD " )
{
gCpuInfo . cpuId . isAMD = true ;
}
// 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 ] ;
memset ( brand , 0 , sizeof ( brand ) ) ;
for ( int i = 0x80000000 ; 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 )
{
memcpy ( brand , & extdata [ 2 ] , sizeof ( cpui ) ) ;
memcpy ( brand + 16 , & extdata [ 3 ] , sizeof ( cpui ) ) ;
memcpy ( brand + 32 , & extdata [ 4 ] , sizeof ( cpui ) ) ;
gCpuInfo . cpuId . brand = brand ;
}
# endif
}
static void SetCpuTopology ( )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
SYSTEM_LOGICAL_PROCESSOR_INFORMATION sysinfo [ 128 ] ;
DWORD length = AuArraySize ( sysinfo ) * sizeof ( * sysinfo ) ;
if ( ! GetLogicalProcessorInformation ( sysinfo , & length ) )
{
SYSTEM_INFO sysinfo ;
GetSystemInfo ( & sysinfo ) ;
gCpuInfo . socket = 1 ;
gCpuInfo . cores = 1 ;
gCpuInfo . threads = sysinfo . dwNumberOfProcessors ;
return ;
}
length / = sizeof ( * sysinfo ) ;
gCpuInfo . socket = 0 ;
gCpuInfo . cores = 0 ;
gCpuInfo . threads = 0 ;
for ( auto i = 0 ; i < length ; i + + )
{
if ( sysinfo [ i ] . Relationship = = RelationProcessorCore )
{
2021-10-25 17:06:24 +00:00
//TODO: fuck it, if some macro fuckery, use popcnt on x86
//we just need to count the bits. first it was just two BitScanForwards. discontiguous cores fucked things up so now we have a loop just to count a few bits.
2021-09-13 20:11:12 +00:00
gCpuInfo . cores + + ;
2021-10-15 23:15:13 +00:00
2021-09-13 20:11:12 +00:00
auto mask = sysinfo [ i ] . ProcessorMask ;
2021-10-15 23:15:13 +00:00
unsigned long offset { } , tmp ;
2021-10-15 23:55:27 +00:00
while ( offset ! = ( sizeof ( offset ) * 8 ) )
2021-10-15 23:15:13 +00:00
{
// Count the index to a 1
if ( BitScanForward ( & tmp , mask > > offset ) = = 0 ) break ; // mask was zero, end of scan
offset + = tmp ;
// Count the 1's by inverting the bitmap and counting to 1
BitScanForward ( & tmp , ~ ( mask > > offset ) ) ;
offset + = tmp ;
// Increment threads by the bits set in
gCpuInfo . threads + = tmp ;
}
2021-09-13 20:11:12 +00:00
}
else if ( sysinfo [ i ] . Relationship = = RelationProcessorPackage )
{
gCpuInfo . socket + + ;
}
}
# elif defined(AURORA_IS_BSD_DERIVED)
auto opt = QueryBsdHwStat ( HW_AVAILCPU ) ;
if ( opt . value_or ( 0 ) < 1 )
{
opt = QueryBsdHwStat ( HW_NCPU ) ;
}
gCpuInfo . socket = 1 ;
gCpuInfo . cores = 1 ;
2021-09-17 19:26:05 +00:00
gCpuInfo . threads = opt . value_or ( 1 ) ;
# elif defined(AURORA_IS_LINUX_DERIVED)
gCpuInfo . socket = 1 ;
gCpuInfo . cores = 1 ;
2021-10-02 16:07:33 +00:00
gCpuInfo . threads = get_nprocs ( ) ;
2021-09-13 20:11:12 +00:00
# elif defined(AURORA_IS_POSIX_DERIVED)
2021-09-14 13:13:58 +00:00
2021-09-13 20:11:12 +00:00
gCpuInfo . socket = 1 ;
gCpuInfo . cores = 1 ;
gCpuInfo . threads = sysconf ( _SC_NPROCESSORS_ONLN ) ;
2021-09-14 13:13:58 +00:00
2021-09-13 20:11:12 +00:00
# endif
}
void InitCpuInfo ( )
{
gCpuInfo . cpuArch = Aurora : : Build : : kCurrentArchitecture ;
SetCpuId ( ) ;
SetCpuTopology ( ) ;
}
2021-10-02 16:07:33 +00:00
}