Core: Rework HardwareInfo
This commit is contained in:
parent
9cd7976a91
commit
6d0b53b39e
|
|
@ -8,9 +8,11 @@
|
||||||
#define NAZARA_CORE_HPP
|
#define NAZARA_CORE_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Core/HardwareInfo.hpp>
|
||||||
#include <Nazara/Core/ModuleBase.hpp>
|
#include <Nazara/Core/ModuleBase.hpp>
|
||||||
#include <Nazara/Core/Modules.hpp>
|
#include <Nazara/Core/Modules.hpp>
|
||||||
#include <Nazara/Utils/TypeList.hpp>
|
#include <Nazara/Utils/TypeList.hpp>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +28,11 @@ namespace Nz
|
||||||
Core(Config /*config*/);
|
Core(Config /*config*/);
|
||||||
~Core();
|
~Core();
|
||||||
|
|
||||||
|
inline const HardwareInfo& GetHardwareInfo() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::optional<HardwareInfo> m_hardwareInfo;
|
||||||
|
|
||||||
static Core* s_instance;
|
static Core* s_instance;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
inline const HardwareInfo& Core::GetHardwareInfo() const
|
||||||
|
{
|
||||||
|
return *m_hardwareInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Core/DebugOff.hpp>
|
#include <Nazara/Core/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -147,10 +147,13 @@ namespace Nz
|
||||||
enum class ProcessorCap
|
enum class ProcessorCap
|
||||||
{
|
{
|
||||||
x64,
|
x64,
|
||||||
|
AES,
|
||||||
AVX,
|
AVX,
|
||||||
FMA3,
|
FMA3,
|
||||||
FMA4,
|
FMA4,
|
||||||
MMX,
|
MMX,
|
||||||
|
Popcnt,
|
||||||
|
RDRAND,
|
||||||
XOP,
|
XOP,
|
||||||
SSE,
|
SSE,
|
||||||
SSE2,
|
SSE2,
|
||||||
|
|
@ -169,14 +172,24 @@ namespace Nz
|
||||||
{
|
{
|
||||||
Unknown = -1,
|
Unknown = -1,
|
||||||
|
|
||||||
|
ACRN,
|
||||||
AMD,
|
AMD,
|
||||||
|
Ao486,
|
||||||
|
AppleRosetta2,
|
||||||
|
Bhyve,
|
||||||
Centaur,
|
Centaur,
|
||||||
Cyrix,
|
Cyrix,
|
||||||
|
Elbrus,
|
||||||
|
Hygon,
|
||||||
|
HyperV,
|
||||||
Intel,
|
Intel,
|
||||||
KVM,
|
KVM,
|
||||||
HyperV,
|
MicrosoftXTA,
|
||||||
NSC,
|
NSC,
|
||||||
NexGen,
|
NexGen,
|
||||||
|
Parallels,
|
||||||
|
QEMU,
|
||||||
|
QNX,
|
||||||
Rise,
|
Rise,
|
||||||
SIS,
|
SIS,
|
||||||
Transmeta,
|
Transmeta,
|
||||||
|
|
@ -185,8 +198,9 @@ namespace Nz
|
||||||
VMware,
|
VMware,
|
||||||
Vortex,
|
Vortex,
|
||||||
XenHVM,
|
XenHVM,
|
||||||
|
Zhaoxin,
|
||||||
|
|
||||||
Max = XenHVM
|
Max = Zhaoxin
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::size_t ProcessorVendorCount = static_cast<std::size_t>(ProcessorVendor::Max) + 1;
|
constexpr std::size_t ProcessorVendorCount = static_cast<std::size_t>(ProcessorVendor::Max) + 1;
|
||||||
|
|
|
||||||
|
|
@ -10,33 +10,45 @@
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
#include <Nazara/Core/Config.hpp>
|
#include <Nazara/Core/Config.hpp>
|
||||||
#include <Nazara/Core/Enums.hpp>
|
#include <Nazara/Core/Enums.hpp>
|
||||||
#include <string>
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
class NAZARA_CORE_API HardwareInfo
|
class NAZARA_CORE_API HardwareInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HardwareInfo() = delete;
|
HardwareInfo();
|
||||||
~HardwareInfo() = delete;
|
HardwareInfo(const HardwareInfo&) = delete;
|
||||||
|
HardwareInfo(HardwareInfo&&) = delete;
|
||||||
|
~HardwareInfo() = default;
|
||||||
|
|
||||||
|
inline const char* GetCpuBrandString() const;
|
||||||
|
inline unsigned int GetCpuThreadCount() const;
|
||||||
|
inline ProcessorVendor GetCpuVendor() const;
|
||||||
|
std::string_view GetCpuVendorName() const;
|
||||||
|
inline UInt64 GetSystemTotalMemory() const;
|
||||||
|
|
||||||
|
inline bool HasCapability(ProcessorCap capability) const;
|
||||||
|
|
||||||
static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4]);
|
static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4]);
|
||||||
|
|
||||||
static std::string_view GetProcessorBrandString();
|
|
||||||
static unsigned int GetProcessorCount();
|
|
||||||
static ProcessorVendor GetProcessorVendor();
|
|
||||||
static std::string_view GetProcessorVendorName();
|
|
||||||
static UInt64 GetTotalMemory();
|
|
||||||
|
|
||||||
static bool HasCapability(ProcessorCap capability);
|
|
||||||
|
|
||||||
static bool Initialize();
|
|
||||||
|
|
||||||
static bool IsCpuidSupported();
|
static bool IsCpuidSupported();
|
||||||
static bool IsInitialized();
|
|
||||||
|
|
||||||
static void Uninitialize();
|
HardwareInfo& operator=(const HardwareInfo&) = delete;
|
||||||
|
HardwareInfo& operator=(HardwareInfo&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FetchCPUInfo();
|
||||||
|
void FetchMemoryInfo();
|
||||||
|
|
||||||
|
std::array<bool, ProcessorCapCount> m_cpuCapabilities;
|
||||||
|
std::array<char, 3 * 4 * 4> m_cpuBrandString;
|
||||||
|
ProcessorVendor m_cpuVendor;
|
||||||
|
unsigned int m_cpuThreadCount;
|
||||||
|
UInt64 m_systemTotalMemory;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Core/HardwareInfo.inl>
|
||||||
|
|
||||||
#endif // NAZARA_CORE_HARDWAREINFO_HPP
|
#endif // NAZARA_CORE_HARDWAREINFO_HPP
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||||
|
// This file is part of the "Nazara Engine - Core module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Core/HardwareInfo.hpp>
|
||||||
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
|
#include <Nazara/Core/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline const char* HardwareInfo::GetCpuBrandString() const
|
||||||
|
{
|
||||||
|
return m_cpuBrandString.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int HardwareInfo::GetCpuThreadCount() const
|
||||||
|
{
|
||||||
|
return m_cpuThreadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ProcessorVendor HardwareInfo::GetCpuVendor() const
|
||||||
|
{
|
||||||
|
return m_cpuVendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt64 HardwareInfo::GetSystemTotalMemory() const
|
||||||
|
{
|
||||||
|
return m_systemTotalMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HardwareInfo::HasCapability(ProcessorCap capability) const
|
||||||
|
{
|
||||||
|
return m_cpuCapabilities[UnderlyingCast(capability)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Core/DebugOff.hpp>
|
||||||
|
|
@ -25,11 +25,14 @@ namespace Nz
|
||||||
Log::Initialize();
|
Log::Initialize();
|
||||||
|
|
||||||
LogInit();
|
LogInit();
|
||||||
|
|
||||||
|
m_hardwareInfo.emplace();
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::~Core()
|
Core::~Core()
|
||||||
{
|
{
|
||||||
HardwareInfo::Uninitialize();
|
m_hardwareInfo.reset();
|
||||||
|
|
||||||
TaskScheduler::Uninitialize();
|
TaskScheduler::Uninitialize();
|
||||||
LogUninit();
|
LogUninit();
|
||||||
Log::Uninitialize();
|
Log::Uninitialize();
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Core/HardwareInfo.hpp>
|
#include <Nazara/Core/HardwareInfo.hpp>
|
||||||
#include <Nazara/Core/Algorithm.hpp>
|
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <frozen/string.h>
|
||||||
|
#include <frozen/unordered_map.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
@ -22,62 +23,76 @@ namespace Nz
|
||||||
{
|
{
|
||||||
namespace NAZARA_ANONYMOUS_NAMESPACE
|
namespace NAZARA_ANONYMOUS_NAMESPACE
|
||||||
{
|
{
|
||||||
|
constexpr std::array s_vendorNames = {
|
||||||
|
std::string_view("ACRN"), // ProcessorVendor::ACRN
|
||||||
|
std::string_view("Advanced Micro Devices"), // ProcessorVendor::AMD
|
||||||
|
std::string_view("ao486"), // ProcessorVendor::Ao486
|
||||||
|
std::string_view("Apple Rosetta 2"), // ProcessorVendor::AppleRosetta2
|
||||||
|
std::string_view("bhyve"), // ProcessorVendor::Bhyve
|
||||||
|
std::string_view("Centaur Technology"), // ProcessorVendor::Centaur
|
||||||
|
std::string_view("Cyrix Corporation"), // ProcessorVendor::Cyrix
|
||||||
|
std::string_view("MCST Elbrus"), // ProcessorVendor::Elbrus
|
||||||
|
std::string_view("Hygon"), // ProcessorVendor::Hygon
|
||||||
|
std::string_view("Microsoft Hyper-V"), // ProcessorVendor::HyperV
|
||||||
|
std::string_view("Intel Corporation"), // ProcessorVendor::Intel
|
||||||
|
std::string_view("Kernel-based Virtual Machine"), // ProcessorVendor::KVM
|
||||||
|
std::string_view("Microsoft x86-to-ARM"), // ProcessorVendor::MicrosoftXTA
|
||||||
|
std::string_view("National Semiconductor"), // ProcessorVendor::NSC
|
||||||
|
std::string_view("NexGen"), // ProcessorVendor::NexGen
|
||||||
|
std::string_view("Parallels"), // ProcessorVendor::Parallels
|
||||||
|
std::string_view("QEMU"), // ProcessorVendor::QEMU
|
||||||
|
std::string_view("QNX Hypervisor"), // ProcessorVendor::QNX
|
||||||
|
std::string_view("Rise Technology"), // ProcessorVendor::Rise
|
||||||
|
std::string_view("Silicon Integrated Systems"), // ProcessorVendor::SiS
|
||||||
|
std::string_view("Transmeta Corporation"), // ProcessorVendor::Transmeta
|
||||||
|
std::string_view("United Microelectronics Corporation"), // ProcessorVendor::UMC
|
||||||
|
std::string_view("VIA Technologies"), // ProcessorVendor::VIA
|
||||||
|
std::string_view("VMware"), // ProcessorVendor::VMware
|
||||||
|
std::string_view("Vortex86"), // ProcessorVendor::Vortex
|
||||||
|
std::string_view("Xen"), // ProcessorVendor::XenHVM
|
||||||
|
std::string_view("Zhaoxin)") // ProcessorVendor::Zhaoxin
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(s_vendorNames.size() == ProcessorVendorCount, "Processor vendor name array is incomplete");
|
||||||
|
|
||||||
struct VendorString
|
struct VendorString
|
||||||
{
|
{
|
||||||
char vendor[13]; // +1 pour le \0 automatiquement ajouté par le compilateur
|
char vendor[13]; // +1 for the end of string character
|
||||||
ProcessorVendor vendorEnum;
|
ProcessorVendor vendorEnum;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* s_vendorNames[] =
|
constexpr frozen::unordered_map s_vendorStrings = frozen::make_unordered_map<frozen::string, ProcessorVendor>({
|
||||||
{
|
{ " Shanghai ", ProcessorVendor::Zhaoxin },
|
||||||
"Advanced Micro Devices", // ProcessorVendor::AMD
|
{ " KVMKVMKVM ", ProcessorVendor::KVM },
|
||||||
"Centaur Technology", // ProcessorVendor::Centaur
|
{ " QNXQVMBSQG ", ProcessorVendor::QNX },
|
||||||
"Cyrix Corporation", // ProcessorVendor::Cyrix
|
{ " lrpepyh vr", ProcessorVendor::Parallels },
|
||||||
"Intel Corporation", // ProcessorVendor::Intel
|
{ "ACRNACRNACRN", ProcessorVendor::ACRN },
|
||||||
"Kernel-based Virtual Machine", // ProcessorVendor::KVM
|
{ "AMDisbetter!", ProcessorVendor::AMD },
|
||||||
"Microsoft Hyper-V", // ProcessorVendor::HyperV
|
{ "AuthenticAMD", ProcessorVendor::AMD },
|
||||||
"National Semiconductor", // ProcessorVendor::NSC
|
{ "CentaurHauls", ProcessorVendor::Centaur },
|
||||||
"NexGen", // ProcessorVendor::NexGen
|
{ "CyrixInstead", ProcessorVendor::Cyrix },
|
||||||
"Rise Technology", // ProcessorVendor::Rise
|
{ "E2K MACHINE", ProcessorVendor::Elbrus },
|
||||||
"Silicon Integrated Systems", // ProcessorVendor::SIS
|
{ "GenuineIntel", ProcessorVendor::Intel },
|
||||||
"Transmeta Corporation", // ProcessorVendor::Transmeta
|
{ "GenuineTMx86", ProcessorVendor::Transmeta },
|
||||||
"United Microelectronics Corporation", // ProcessorVendor::UMC
|
{ "Geode by NSC", ProcessorVendor::NSC },
|
||||||
"VIA Technologies", // ProcessorVendor::VIA
|
{ "HygonGenuine", ProcessorVendor::Hygon },
|
||||||
"VMware", // ProcessorVendor::VMware
|
{ "KVMKVMKVMKVM", ProcessorVendor::KVM },
|
||||||
"Vortex86", // ProcessorVendor::Vortex
|
{ "Microsoft Hv", ProcessorVendor::HyperV },
|
||||||
"Xen" // ProcessorVendor::XenHVM
|
{ "MicrosoftXTA", ProcessorVendor::MicrosoftXTA },
|
||||||
};
|
{ "NexGenDriven", ProcessorVendor::NexGen },
|
||||||
|
{ "RiseRiseRise", ProcessorVendor::Rise },
|
||||||
static_assert(sizeof(s_vendorNames)/sizeof(const char*) == ProcessorVendorCount, "Processor vendor name array is incomplete");
|
{ "SiS SiS SiS ", ProcessorVendor::SIS },
|
||||||
|
{ "TCGTCGTCGTCG", ProcessorVendor::QEMU },
|
||||||
VendorString vendorStrings[] =
|
{ "TransmetaCPU", ProcessorVendor::Transmeta },
|
||||||
{
|
{ "UMC UMC UMC ", ProcessorVendor::UMC },
|
||||||
// Triés par ordre alphabétique (Majuscules primant sur minuscules)
|
{ "VIA VIA VIA ", ProcessorVendor::VIA },
|
||||||
{"AMDisbetter!", ProcessorVendor::AMD},
|
{ "VMwareVMware", ProcessorVendor::VMware },
|
||||||
{"AuthenticAMD", ProcessorVendor::AMD},
|
{ "VirtualApple", ProcessorVendor::AppleRosetta2 },
|
||||||
{"CentaurHauls", ProcessorVendor::Centaur},
|
{ "Vortex86 SoC", ProcessorVendor::Vortex },
|
||||||
{"CyrixInstead", ProcessorVendor::Cyrix},
|
{ "XenVMMXenVMM", ProcessorVendor::XenHVM },
|
||||||
{"GenuineIntel", ProcessorVendor::Intel},
|
{ "bhyve bhyve ", ProcessorVendor::Bhyve },
|
||||||
{"GenuineTMx86", ProcessorVendor::Transmeta},
|
{ "prl hyperv ", ProcessorVendor::Parallels }, //< endianness-fixed version of " lrpepyh vr"
|
||||||
{"Geode by NSC", ProcessorVendor::NSC},
|
});
|
||||||
{"KVMKVMKVMKVM", ProcessorVendor::KVM},
|
|
||||||
{"Microsoft Hv", ProcessorVendor::HyperV},
|
|
||||||
{"NexGenDriven", ProcessorVendor::NexGen},
|
|
||||||
{"RiseRiseRise", ProcessorVendor::Rise},
|
|
||||||
{"SiS SiS SiS ", ProcessorVendor::SIS},
|
|
||||||
{"TransmetaCPU", ProcessorVendor::Transmeta},
|
|
||||||
{"UMC UMC UMC ", ProcessorVendor::UMC},
|
|
||||||
{"VIA VIA VIA ", ProcessorVendor::VIA},
|
|
||||||
{"VMwareVMware", ProcessorVendor::VMware},
|
|
||||||
{"Vortex86 SoC", ProcessorVendor::Vortex},
|
|
||||||
{"XenVMMXenVMM", ProcessorVendor::XenHVM}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProcessorVendor s_vendorEnum = ProcessorVendor::Unknown;
|
|
||||||
bool s_capabilities[ProcessorCapCount] = {false};
|
|
||||||
bool s_initialized = false;
|
|
||||||
|
|
||||||
char s_brandString[48] = "Not initialized";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -86,238 +101,115 @@ namespace Nz
|
||||||
* \brief Core class that represents the info we can get from hardware
|
* \brief Core class that represents the info we can get from hardware
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
HardwareInfo::HardwareInfo()
|
||||||
* \brief Generates the cpuid instruction (available on x86 & x64)
|
{
|
||||||
*
|
FetchCPUInfo();
|
||||||
* \param functionId Information to retrieve
|
FetchMemoryInfo();
|
||||||
* \param subFunctionId Additional code for information retrieval
|
}
|
||||||
* \param result Supported features of the CPU
|
|
||||||
*/
|
std::string_view HardwareInfo::GetCpuVendorName() const
|
||||||
|
{
|
||||||
|
NAZARA_USE_ANONYMOUS_NAMESPACE
|
||||||
|
|
||||||
|
return s_vendorNames[UnderlyingCast(m_cpuVendor)];
|
||||||
|
}
|
||||||
|
|
||||||
void HardwareInfo::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4])
|
void HardwareInfo::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4])
|
||||||
{
|
{
|
||||||
return HardwareInfoImpl::Cpuid(functionId, subFunctionId, result);
|
return HardwareInfoImpl::Cpuid(functionId, subFunctionId, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the brand of the processor
|
|
||||||
* \return String of the brand
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if not Initialize
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::string_view HardwareInfo::GetProcessorBrandString()
|
|
||||||
{
|
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
|
||||||
|
|
||||||
if (!Initialize())
|
|
||||||
NazaraError("Failed to initialize HardwareInfo");
|
|
||||||
|
|
||||||
return s_brandString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the number of threads
|
|
||||||
* \return Number of threads available on the CPU
|
|
||||||
*
|
|
||||||
* \remark Doesn't need the initialization of HardwareInfo
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int HardwareInfo::GetProcessorCount()
|
|
||||||
{
|
|
||||||
static unsigned int processorCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U);
|
|
||||||
return processorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the processor vendor
|
|
||||||
* \return ProcessorVendor containing information the vendor
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if not Initialize
|
|
||||||
*/
|
|
||||||
|
|
||||||
ProcessorVendor HardwareInfo::GetProcessorVendor()
|
|
||||||
{
|
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
|
||||||
|
|
||||||
if (!Initialize())
|
|
||||||
NazaraError("Failed to initialize HardwareInfo");
|
|
||||||
|
|
||||||
return s_vendorEnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the vendor of the processor
|
|
||||||
* \return String of the vendor
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if not Initialize
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::string_view HardwareInfo::GetProcessorVendorName()
|
|
||||||
{
|
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
|
||||||
|
|
||||||
if (!Initialize())
|
|
||||||
NazaraError("Failed to initialize HardwareInfo");
|
|
||||||
|
|
||||||
return s_vendorNames[UnderlyingCast(s_vendorEnum)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the amount of total memory
|
|
||||||
* \return Number of total memory available
|
|
||||||
*
|
|
||||||
* \remark Doesn't need the initialization of HardwareInfo
|
|
||||||
*/
|
|
||||||
|
|
||||||
UInt64 HardwareInfo::GetTotalMemory()
|
|
||||||
{
|
|
||||||
static UInt64 totalMemory = HardwareInfoImpl::GetTotalMemory();
|
|
||||||
return totalMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Checks whether the processor owns the capacity to handle certain instructions
|
|
||||||
* \return true If instructions supported
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if capability is a wrong enum with NAZARA_DEBUG defined
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool HardwareInfo::HasCapability(ProcessorCap capability)
|
|
||||||
{
|
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
|
||||||
|
|
||||||
return s_capabilities[UnderlyingCast(capability)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Initializes the HardwareInfo class
|
|
||||||
* \return true if successful
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if cpuid is not supported
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool HardwareInfo::Initialize()
|
|
||||||
{
|
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
|
||||||
|
|
||||||
if (IsInitialized())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!HardwareInfoImpl::IsCpuidSupported())
|
|
||||||
{
|
|
||||||
NazaraError("Cpuid is not supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_initialized = true;
|
|
||||||
|
|
||||||
UInt32 registers[4]; // To store our registers values (EAX, EBX, ECX and EDX)
|
|
||||||
|
|
||||||
// Let's make it clearer
|
|
||||||
UInt32& eax = registers[0];
|
|
||||||
UInt32& ebx = registers[1];
|
|
||||||
UInt32& ecx = registers[2];
|
|
||||||
UInt32& edx = registers[3];
|
|
||||||
|
|
||||||
// To begin, we get the id of the constructor and the id of maximal functions supported by the CPUID
|
|
||||||
HardwareInfoImpl::Cpuid(0, 0, registers);
|
|
||||||
|
|
||||||
// Note the order: EBX, EDX, ECX
|
|
||||||
UInt32 manufacturerId[3] = {ebx, edx, ecx};
|
|
||||||
|
|
||||||
// Identification of conceptor
|
|
||||||
s_vendorEnum = ProcessorVendor::Unknown;
|
|
||||||
for (const VendorString& vendorString : vendorStrings)
|
|
||||||
{
|
|
||||||
if (std::memcmp(manufacturerId, vendorString.vendor, 12) == 0)
|
|
||||||
{
|
|
||||||
s_vendorEnum = vendorString.vendorEnum;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eax >= 1)
|
|
||||||
{
|
|
||||||
// Retrieval of certain capacities of the processor (ECX and EDX, function 1)
|
|
||||||
HardwareInfoImpl::Cpuid(1, 0, registers);
|
|
||||||
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::AVX)] = (ecx & (1U << 28)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::FMA3)] = (ecx & (1U << 12)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::MMX)] = (edx & (1U << 23)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE)] = (edx & (1U << 25)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE2)] = (edx & (1U << 26)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE3)] = (ecx & (1U << 0)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSSE3)] = (ecx & (1U << 9)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE41)] = (ecx & (1U << 19)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE42)] = (ecx & (1U << 20)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieval of biggest extended function handled (EAX, function 0x80000000)
|
|
||||||
HardwareInfoImpl::Cpuid(0x80000000, 0, registers);
|
|
||||||
|
|
||||||
UInt32 maxSupportedExtendedFunction = eax;
|
|
||||||
if (maxSupportedExtendedFunction >= 0x80000001)
|
|
||||||
{
|
|
||||||
// Retrieval of extended capabilities of the processor (ECX and EDX, function 0x80000001)
|
|
||||||
HardwareInfoImpl::Cpuid(0x80000001, 0, registers);
|
|
||||||
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::x64)] = (edx & (1U << 29)) != 0; // Support of 64bits, independent of the OS
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::FMA4)] = (ecx & (1U << 16)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::SSE4a)] = (ecx & (1U << 6)) != 0;
|
|
||||||
s_capabilities[UnderlyingCast(ProcessorCap::XOP)] = (ecx & (1U << 11)) != 0;
|
|
||||||
|
|
||||||
if (maxSupportedExtendedFunction >= 0x80000004)
|
|
||||||
{
|
|
||||||
// Retrieval of the string describing the processor (EAX, EBX, ECX and EDX,
|
|
||||||
// functions from 0x80000002 to 0x80000004 inclusive)
|
|
||||||
char* ptr = &s_brandString[0];
|
|
||||||
for (UInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
|
||||||
{
|
|
||||||
HardwareInfoImpl::Cpuid(code, 0, registers);
|
|
||||||
std::memcpy(ptr, ®isters[0], 4*sizeof(UInt32)); // We add the 16 bytes to the string
|
|
||||||
|
|
||||||
ptr += 4*sizeof(UInt32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The character '\0' is already part of the string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Checks whether the instruction of cpuid is supported
|
|
||||||
* \return true if it the case
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool HardwareInfo::IsCpuidSupported()
|
bool HardwareInfo::IsCpuidSupported()
|
||||||
{
|
{
|
||||||
return HardwareInfoImpl::IsCpuidSupported();
|
return HardwareInfoImpl::IsCpuidSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
void HardwareInfo::FetchCPUInfo()
|
||||||
* \brief Checks whether the class HardwareInfo is initialized
|
|
||||||
* \return true if it is initialized
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool HardwareInfo::IsInitialized()
|
|
||||||
{
|
{
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
NAZARA_USE_ANONYMOUS_NAMESPACE
|
||||||
|
|
||||||
return s_initialized;
|
m_cpuThreadCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U);
|
||||||
|
|
||||||
|
m_cpuCapabilities.fill(false);
|
||||||
|
m_cpuVendor = ProcessorVendor::Unknown;
|
||||||
|
|
||||||
|
std::strcpy(m_cpuBrandString.data(), "CPU from unknown vendor - cpuid not supported");
|
||||||
|
|
||||||
|
if (!HardwareInfoImpl::IsCpuidSupported())
|
||||||
|
{
|
||||||
|
NazaraWarning("Cpuid is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To begin, we get the id of the constructor and the id of maximal functions supported by the CPUID
|
||||||
|
std::array<UInt32, 4> registers;
|
||||||
|
HardwareInfoImpl::Cpuid(0, 0, registers.data());
|
||||||
|
|
||||||
|
UInt32& eax = registers[0];
|
||||||
|
UInt32& ebx = registers[1];
|
||||||
|
UInt32& ecx = registers[2];
|
||||||
|
UInt32& edx = registers[3];
|
||||||
|
|
||||||
|
UInt32 manufacturerId[3] = { ebx, edx, ecx };
|
||||||
|
frozen::string manufactorID(reinterpret_cast<const char*>(&manufacturerId[0]), 12);
|
||||||
|
|
||||||
|
if (auto vendorIt = s_vendorStrings.find(manufactorID); vendorIt != s_vendorStrings.end())
|
||||||
|
m_cpuVendor = vendorIt->second;
|
||||||
|
else
|
||||||
|
m_cpuVendor = ProcessorVendor::Unknown;
|
||||||
|
|
||||||
|
if (eax >= 1)
|
||||||
|
{
|
||||||
|
// Retrieval of certain capacities of the processor (ECX and EDX, function 1)
|
||||||
|
HardwareInfoImpl::Cpuid(1, 0, registers.data());
|
||||||
|
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::AES)] = (ecx & (1U << 25)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::AVX)] = (ecx & (1U << 28)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::FMA3)] = (ecx & (1U << 12)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::MMX)] = (edx & (1U << 23)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::Popcnt)] = (ecx & (1U << 23)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::RDRAND)] = (ecx & (1U << 30)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE)] = (edx & (1U << 25)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE2)] = (edx & (1U << 26)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE3)] = (ecx & (1U << 0)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSSE3)] = (ecx & (1U << 9)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE41)] = (ecx & (1U << 19)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE42)] = (ecx & (1U << 20)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieval of biggest extended function handled (EAX, function 0x80000000)
|
||||||
|
HardwareInfoImpl::Cpuid(0x80000000, 0, registers.data());
|
||||||
|
|
||||||
|
UInt32 maxSupportedExtendedFunction = eax;
|
||||||
|
if (maxSupportedExtendedFunction >= 0x80000001)
|
||||||
|
{
|
||||||
|
// Retrieval of extended capabilities of the processor (ECX and EDX, function 0x80000001)
|
||||||
|
HardwareInfoImpl::Cpuid(0x80000001, 0, registers.data());
|
||||||
|
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::x64)] = (edx & (1U << 29)) != 0; // Support of 64bits, doesn't mean executable is 64bits
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::FMA4)] = (ecx & (1U << 16)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::SSE4a)] = (ecx & (1U << 6)) != 0;
|
||||||
|
m_cpuCapabilities[UnderlyingCast(ProcessorCap::XOP)] = (ecx & (1U << 11)) != 0;
|
||||||
|
|
||||||
|
if (maxSupportedExtendedFunction >= 0x80000004)
|
||||||
|
{
|
||||||
|
// Retrieval of the string describing the processor (EAX, EBX, ECX and EDX, functions from 0x80000002 to 0x80000004 inclusive)
|
||||||
|
char* ptr = &m_cpuBrandString[0];
|
||||||
|
for (UInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
||||||
|
{
|
||||||
|
HardwareInfoImpl::Cpuid(code, 0, registers.data());
|
||||||
|
std::memcpy(ptr, ®isters[0], 4*sizeof(UInt32)); // We add the 16 bytes to the string
|
||||||
|
|
||||||
|
ptr += 4 * sizeof(UInt32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The character '\0' is already part of the string
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
void HardwareInfo::FetchMemoryInfo()
|
||||||
* \brief Unitializes the class HardwareInfo
|
|
||||||
*/
|
|
||||||
|
|
||||||
void HardwareInfo::Uninitialize()
|
|
||||||
{
|
{
|
||||||
NAZARA_USE_ANONYMOUS_NAMESPACE
|
m_systemTotalMemory = HardwareInfoImpl::GetTotalMemory();
|
||||||
|
|
||||||
// Nothing to do
|
|
||||||
s_initialized = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Core/TaskScheduler.hpp>
|
#include <Nazara/Core/TaskScheduler.hpp>
|
||||||
|
#include <Nazara/Core/Core.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <Nazara/Core/HardwareInfo.hpp>
|
|
||||||
|
|
||||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||||
#include <Nazara/Core/Win32/TaskSchedulerImpl.hpp>
|
#include <Nazara/Core/Win32/TaskSchedulerImpl.hpp>
|
||||||
|
|
@ -34,12 +34,12 @@ namespace Nz
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the number of threads
|
* \brief Gets the number of threads
|
||||||
* \return Number of threads, if none, the number of simulatenous threads on the processor is returned
|
* \return Number of threads, if none, the number of logical threads on the processor is returned
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int TaskScheduler::GetWorkerCount()
|
unsigned int TaskScheduler::GetWorkerCount()
|
||||||
{
|
{
|
||||||
return (s_workerCount > 0) ? s_workerCount : HardwareInfo::GetProcessorCount();
|
return (s_workerCount > 0) ? s_workerCount : Core::Instance()->GetHardwareInfo().GetCpuThreadCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Nz
|
||||||
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
||||||
{
|
{
|
||||||
#if defined(NAZARA_COMPILER_MSVC)
|
#if defined(NAZARA_COMPILER_MSVC)
|
||||||
static_assert(sizeof(UInt32) == sizeof(int), "Assertion failed");
|
static_assert(sizeof(UInt32) == sizeof(int));
|
||||||
|
|
||||||
// Use intrinsic function if available
|
// Use intrinsic function if available
|
||||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue