mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-13 19:50:34 +00:00
Merge branch 'update-cpufeatures' into next
This commit is contained in:
commit
8849f78eb0
@ -270,10 +270,6 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.0 AND SUPPORTED_CPU_FEATURES_ARCH)
|
||||
set(BUILD_PIC ON CACHE BOOL
|
||||
"Build cpu_features with Position Independent Code (PIC)."
|
||||
FORCE
|
||||
)
|
||||
set(USE_CPU_FEATURES ON)
|
||||
set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
@ -32,13 +32,11 @@ option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
|
||||
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
|
||||
# Prefer static linking from source whenever possible.
|
||||
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
|
||||
# PIC
|
||||
option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
|
||||
|
||||
# Force PIC on unix when building shared libs
|
||||
# see: https://en.wikipedia.org/wiki/Position-independent_code
|
||||
if(BUILD_SHARED_LIBS AND UNIX)
|
||||
set(BUILD_PIC ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
|
||||
endif()
|
||||
|
||||
include(CheckIncludeFile)
|
||||
@ -110,7 +108,6 @@ add_library(utils OBJECT
|
||||
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
|
||||
${PROJECT_SOURCE_DIR}/src/string_view.c
|
||||
)
|
||||
set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||
setup_include_and_definitions(utils)
|
||||
|
||||
#
|
||||
@ -131,7 +128,6 @@ if(UNIX)
|
||||
if(HAVE_STRONG_GETAUXVAL)
|
||||
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
|
||||
endif()
|
||||
set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||
endif()
|
||||
|
||||
#
|
||||
@ -148,7 +144,6 @@ add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
|
||||
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
|
||||
setup_include_and_definitions(cpu_features)
|
||||
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
|
||||
set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||
target_include_directories(cpu_features
|
||||
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
|
||||
)
|
||||
@ -237,6 +232,7 @@ install(TARGETS cpu_features list_cpu_features
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
install(EXPORT CpuFeaturesTargets
|
||||
NAMESPACE CpuFeatures::
|
||||
|
@ -10,6 +10,11 @@
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// CPUID Vendors
|
||||
#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
|
||||
#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
|
||||
#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
|
||||
|
||||
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||
// The field names are based on the short name provided in the wikipedia tables.
|
||||
typedef struct
|
||||
|
@ -87,7 +87,8 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||
|
||||
// Checks if line contains the specified whitespace separated word.
|
||||
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const char* const word);
|
||||
const char* const word,
|
||||
const char separator);
|
||||
|
||||
// Get key/value from line. key and value are separated by ": ".
|
||||
// key and value are cleaned up from leading and trailing whitespaces.
|
||||
|
@ -107,8 +107,8 @@ static bool HandleAarch64Line(const LineResult result,
|
||||
{
|
||||
for (size_t i = 0; i < AARCH64_LAST_; ++i)
|
||||
{
|
||||
kSetters[i](&info->features,
|
||||
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
}
|
||||
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))
|
||||
|
@ -71,8 +71,8 @@ static bool HandleArmLine(const LineResult result, ArmInfo* const info,
|
||||
{
|
||||
for (size_t i = 0; i < ARM_LAST_; ++i)
|
||||
{
|
||||
kSetters[i](&info->features,
|
||||
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
}
|
||||
else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer")))
|
||||
|
@ -28,8 +28,8 @@ static bool HandleMipsLine(const LineResult result,
|
||||
{
|
||||
for (size_t i = 0; i < MIPS_LAST_; ++i)
|
||||
{
|
||||
kSetters[i](features,
|
||||
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||
kSetters[i](features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ static bool HandlePPCLine(const LineResult result,
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
|
||||
{
|
||||
if (CpuFeatures_StringView_HasWord(key, "platform"))
|
||||
if (CpuFeatures_StringView_HasWord(key, "platform", ' '))
|
||||
{
|
||||
CpuFeatures_StringView_CopyString(value, strings->platform,
|
||||
sizeof(strings->platform));
|
||||
|
@ -88,7 +88,6 @@
|
||||
defined(CPU_FEATURES_OS_FREEBSD)
|
||||
#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
|
||||
#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
|
||||
#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
|
||||
#elif defined(CPU_FEATURES_OS_DARWIN)
|
||||
#if !defined(HAVE_SYSCTLBYNAME)
|
||||
#error "Darwin needs support for sysctlbyname"
|
||||
@ -98,6 +97,8 @@
|
||||
#error "Unsupported OS"
|
||||
#endif // CPU_FEATURES_OS
|
||||
|
||||
#include "internal/string_view.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for CpuId and GetXCR0Eax.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -267,6 +268,11 @@ static int IsVendor(const Leaf leaf, const char* const name)
|
||||
return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
|
||||
}
|
||||
|
||||
static int IsVendorByX86Info(const X86Info* info, const char* const name)
|
||||
{
|
||||
return memcmp(info->vendor, name, sizeof(info->vendor)) == 0;
|
||||
}
|
||||
|
||||
static const CacheLevelInfo kEmptyCacheLevelInfo;
|
||||
|
||||
static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg)
|
||||
@ -1129,55 +1135,52 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg)
|
||||
}
|
||||
}
|
||||
|
||||
static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
// From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
|
||||
static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info)
|
||||
{
|
||||
Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
|
||||
uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
|
||||
for (int i = 0; i < 4; ++i)
|
||||
// The least-significant byte in register EAX (register AL) will always return
|
||||
// 01H. Software should ignore this value and not interpret it as an
|
||||
// informational descriptor.
|
||||
leaf.eax &= 0xFFFFFF00; // Zeroing out AL. 0 is the empty descriptor.
|
||||
// The most significant bit (bit 31) of each register indicates whether the
|
||||
// register contains valid information (set to 0) or is reserved (set to 1).
|
||||
if (IsBitSet(leaf.eax, 31)) leaf.eax = 0;
|
||||
if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0;
|
||||
if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0;
|
||||
if (IsBitSet(leaf.edx, 31)) leaf.edx = 0;
|
||||
|
||||
uint8_t data[16];
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes");
|
||||
#endif
|
||||
memcpy(&data, &leaf, sizeof(data));
|
||||
for (size_t i = 0; i < sizeof(data); ++i)
|
||||
{
|
||||
if (registers[i] & (1U << 31))
|
||||
{
|
||||
continue; // register does not contains valid information
|
||||
}
|
||||
uint32_t bytes[4];
|
||||
GetByteArrayFromRegister(bytes, registers[i]);
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
if (bytes[j] == 0xFF)
|
||||
break; // leaf 4 should be used to fetch cache information
|
||||
info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
|
||||
}
|
||||
const uint8_t descriptor = data[i];
|
||||
if (descriptor == 0) continue;
|
||||
info->levels[info->size] = GetCacheLevelInfo(descriptor);
|
||||
info->size++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info)
|
||||
// For newer Intel CPUs uses "CPUID, eax=0x00000004".
|
||||
// For newer AMD CPUs uses "CPUID, eax=0x8000001D"
|
||||
static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
|
||||
CacheInfo* info)
|
||||
{
|
||||
info->size = 0;
|
||||
for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++)
|
||||
{
|
||||
const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
|
||||
const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, cache_id);
|
||||
CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
|
||||
if (cache_type == CPU_FEATURE_CACHE_NULL)
|
||||
{
|
||||
info->levels[cache_id] = kEmptyCacheLevelInfo;
|
||||
continue;
|
||||
}
|
||||
if (cache_type == CPU_FEATURE_CACHE_NULL) continue;
|
||||
int level = ExtractBitRange(leaf.eax, 7, 5);
|
||||
int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
|
||||
int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
|
||||
int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
|
||||
int tlb_entries = leaf.ecx + 1;
|
||||
int cache_size = (ways * partitioning * line_size * (tlb_entries));
|
||||
info->levels[cache_id] = (CacheLevelInfo){.level = level,
|
||||
info->levels[info->size] = (CacheLevelInfo){.level = level,
|
||||
.cache_type = cache_type,
|
||||
.cache_size = cache_size,
|
||||
.ways = ways,
|
||||
@ -1371,41 +1374,33 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
|
||||
{
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;)
|
||||
for (bool stop = false; !stop;)
|
||||
{
|
||||
const LineResult result = StackLineReader_NextLine(&reader);
|
||||
if (result.eof) stop = true;
|
||||
const StringView line = result.line;
|
||||
const bool is_feature =
|
||||
CpuFeatures_StringView_StartsWith(line, str(" Features="));
|
||||
const bool is_feature2 =
|
||||
CpuFeatures_StringView_StartsWith(line, str(" Features2="));
|
||||
if (is_feature || is_feature2)
|
||||
{
|
||||
// Lines of interests are of the following form:
|
||||
// " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
|
||||
// We replace '<', '>' and ',' with space so we can search by
|
||||
// whitespace separated word.
|
||||
// TODO: Fix CpuFeatures_StringView_HasWord to allow for different
|
||||
// separators.
|
||||
for (size_t i = 0; i < line.size; ++i)
|
||||
{
|
||||
char* c = (char*)(&(line.ptr[i]));
|
||||
if (*c == '<' || *c == '>' || *c == ',') *c = ' ';
|
||||
}
|
||||
if (is_feature)
|
||||
{
|
||||
features->sse = CpuFeatures_StringView_HasWord(line, "SSE");
|
||||
features->sse2 = CpuFeatures_StringView_HasWord(line, "SSE2");
|
||||
}
|
||||
if (is_feature2)
|
||||
{
|
||||
features->sse3 = CpuFeatures_StringView_HasWord(line, "SSE3");
|
||||
features->ssse3 = CpuFeatures_StringView_HasWord(line, "SSSE3");
|
||||
features->sse4_1 = CpuFeatures_StringView_HasWord(line, "SSE4.1");
|
||||
features->sse4_2 = CpuFeatures_StringView_HasWord(line, "SSE4.2");
|
||||
}
|
||||
}
|
||||
if (result.eof) break;
|
||||
if (!CpuFeatures_StringView_StartsWith(line, str(" Features")))
|
||||
continue;
|
||||
// Lines of interests are of the following form:
|
||||
// " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
|
||||
// We first extract the comma separated values between angle brackets.
|
||||
StringView csv = result.line;
|
||||
int index = CpuFeatures_StringView_IndexOfChar(csv, '<');
|
||||
if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1);
|
||||
if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>')
|
||||
csv = CpuFeatures_StringView_PopBack(csv, 1);
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE", ','))
|
||||
features->sse = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE2", ','))
|
||||
features->sse2 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE3", ','))
|
||||
features->sse3 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ','))
|
||||
features->ssse3 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ','))
|
||||
features->sse4_1 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ','))
|
||||
features->sse4_2 = true;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
@ -1416,25 +1411,22 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
|
||||
{
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;)
|
||||
for (bool stop = false; !stop;)
|
||||
{
|
||||
const LineResult result = StackLineReader_NextLine(&reader);
|
||||
if (result.eof) stop = true;
|
||||
const StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
|
||||
{
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("flags")))
|
||||
{
|
||||
features->sse = CpuFeatures_StringView_HasWord(value, "sse");
|
||||
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2");
|
||||
features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3");
|
||||
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3");
|
||||
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1");
|
||||
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result.eof) break;
|
||||
if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
|
||||
continue;
|
||||
if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue;
|
||||
features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' ');
|
||||
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' ');
|
||||
features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3", ' ');
|
||||
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3", ' ');
|
||||
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1", ' ');
|
||||
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2", ' ');
|
||||
break;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
@ -1450,11 +1442,15 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
|
||||
|
||||
// Reference
|
||||
// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
|
||||
static Leaf GetLeafByIdAMD(uint32_t leaf_id)
|
||||
{
|
||||
uint32_t max_extended = CpuId(0x80000000).eax;
|
||||
return SafeCpuId(max_extended, leaf_id);
|
||||
}
|
||||
|
||||
static void ParseExtraAMDCpuId(X86Info* info, OsPreserves os_preserves)
|
||||
{
|
||||
const Leaf leaf_80000000 = CpuId(0x80000000);
|
||||
const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
|
||||
const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
|
||||
const Leaf leaf_80000001 = GetLeafByIdAMD(0x80000001);
|
||||
|
||||
X86Features* const features = &info->features;
|
||||
|
||||
@ -1477,9 +1473,9 @@ X86Info GetX86Info(void)
|
||||
{
|
||||
X86Info info = kEmptyX86Info;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
|
||||
const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
|
||||
const bool is_hygon = IsVendor(leaf_0, "HygonGenuine");
|
||||
const bool is_intel = IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
|
||||
const bool is_amd = IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
|
||||
const bool is_hygon = IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
|
||||
SetVendor(leaf_0, info.vendor);
|
||||
if (is_intel || is_amd || is_hygon)
|
||||
{
|
||||
@ -1498,11 +1494,25 @@ CacheInfo GetX86CacheInfo(void)
|
||||
{
|
||||
CacheInfo info = kEmptyCacheInfo;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
if (IsVendor(leaf_0, "GenuineIntel"))
|
||||
if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL))
|
||||
{
|
||||
ParseLeaf2(max_cpuid_leaf, &info);
|
||||
ParseLeaf4(max_cpuid_leaf, &info);
|
||||
info.size = 0;
|
||||
ParseLeaf2(leaf_0.eax, &info);
|
||||
ParseCacheInfo(leaf_0.eax, 4, &info);
|
||||
}
|
||||
else if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
|
||||
IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE))
|
||||
{
|
||||
const uint32_t max_ext = CpuId(0x80000000).eax;
|
||||
const uint32_t cpuid_ext = SafeCpuId(max_ext, 0x80000001).ecx;
|
||||
|
||||
// If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
|
||||
// then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
|
||||
// https://www.amd.com/system/files/TechDocs/25481.pdf
|
||||
if (IsBitSet(cpuid_ext, 22))
|
||||
{
|
||||
ParseCacheInfo(max_ext, 0x8000001D, &info);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@ -1511,7 +1521,7 @@ CacheInfo GetX86CacheInfo(void)
|
||||
|
||||
X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
|
||||
{
|
||||
if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0)
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL))
|
||||
{
|
||||
switch (CPUID(info->family, info->model))
|
||||
{
|
||||
@ -1616,7 +1626,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0)
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD))
|
||||
{
|
||||
switch (CPUID(info->family, info->model))
|
||||
{
|
||||
@ -1726,7 +1736,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "HygonGenuine", sizeof(info->vendor)) == 0)
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE))
|
||||
{
|
||||
switch (CPUID(info->family, info->model))
|
||||
{
|
||||
@ -1737,23 +1747,20 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info)
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
|
||||
static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
|
||||
char* buffer)
|
||||
{
|
||||
const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
|
||||
// We allow calling memcpy from SetString which is only called when requesting
|
||||
// X86BrandString.
|
||||
memcpy(buffer, &leaf, sizeof(Leaf));
|
||||
}
|
||||
|
||||
void FillX86BrandString(char brand_string[49])
|
||||
{
|
||||
const Leaf leaf_ext_0 = CpuId(0x80000000);
|
||||
const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
|
||||
SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
|
||||
brand_string[48] = '\0';
|
||||
const Leaf leaves[3] = {
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000002),
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000003),
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000004),
|
||||
};
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(leaves) == 48, "Leaves must be packed");
|
||||
#endif
|
||||
CpuFeatures_StringView_CopyString(view((const char*)leaves, sizeof(leaves)),
|
||||
brand_string, 49);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -158,7 +158,8 @@ void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const char* const word_str)
|
||||
const char* const word_str,
|
||||
const char separator)
|
||||
{
|
||||
const StringView word = str(word_str);
|
||||
StringView remainder = line;
|
||||
@ -176,9 +177,9 @@ bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const StringView after =
|
||||
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
|
||||
const bool valid_before =
|
||||
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
|
||||
before.size == 0 || CpuFeatures_StringView_Back(before) == separator;
|
||||
const bool valid_after =
|
||||
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
|
||||
after.size == 0 || CpuFeatures_StringView_Front(after) == separator;
|
||||
if (valid_before && valid_after) return true;
|
||||
remainder =
|
||||
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
|
||||
|
@ -76,26 +76,32 @@ private:
|
||||
uint32_t xcr0_eax_;
|
||||
};
|
||||
|
||||
FakeCpu* g_fake_cpu = nullptr;
|
||||
static FakeCpu* g_fake_cpu_instance = nullptr;
|
||||
|
||||
static FakeCpu& cpu()
|
||||
{
|
||||
assert(g_fake_cpu_instance != nullptr);
|
||||
return *g_fake_cpu_instance;
|
||||
}
|
||||
|
||||
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx)
|
||||
{
|
||||
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
|
||||
return cpu().GetCpuidLeaf(leaf_id, ecx);
|
||||
}
|
||||
|
||||
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
|
||||
extern "C" uint32_t GetXCR0Eax(void) { return cpu().GetXCR0Eax(); }
|
||||
|
||||
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||
extern "C" bool GetDarwinSysCtlByName(const char* name)
|
||||
{
|
||||
return g_fake_cpu->GetDarwinSysCtlByName(name);
|
||||
return cpu().GetDarwinSysCtlByName(name);
|
||||
}
|
||||
#endif // CPU_FEATURES_OS_DARWIN
|
||||
|
||||
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)
|
||||
{
|
||||
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
|
||||
return cpu().GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
|
||||
}
|
||||
#endif // CPU_FEATURES_OS_WINDOWS
|
||||
|
||||
@ -104,14 +110,22 @@ namespace
|
||||
class CpuidX86Test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override { g_fake_cpu = new FakeCpu(); }
|
||||
void TearDown() override { delete g_fake_cpu; }
|
||||
void SetUp() override
|
||||
{
|
||||
assert(g_fake_cpu_instance == nullptr);
|
||||
g_fake_cpu_instance = new FakeCpu();
|
||||
}
|
||||
void TearDown() override
|
||||
{
|
||||
delete g_fake_cpu_instance;
|
||||
g_fake_cpu_instance = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CpuidX86Test, SandyBridge)
|
||||
{
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetOsBackupsExtendedRegisters(true);
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
@ -153,28 +167,29 @@ TEST_F(CpuidX86Test, SandyBridge)
|
||||
EXPECT_FALSE(features.adx);
|
||||
}
|
||||
|
||||
const int UNDEF = -1;
|
||||
const int KiB = 1024;
|
||||
const int MiB = 1024 * KiB;
|
||||
|
||||
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
});
|
||||
// avx is disabled if os does not support backing up ymm registers.
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||
cpu().SetOsBackupsExtendedRegisters(false);
|
||||
EXPECT_FALSE(GetX86Info().features.avx);
|
||||
// avx is disabled if os does not support backing up ymm registers.
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
cpu().SetOsBackupsExtendedRegisters(true);
|
||||
EXPECT_TRUE(GetX86Info().features.avx);
|
||||
}
|
||||
|
||||
TEST_F(CpuidX86Test, SkyLake)
|
||||
{
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetOsBackupsExtendedRegisters(true);
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||
@ -189,7 +204,7 @@ TEST_F(CpuidX86Test, SkyLake)
|
||||
|
||||
TEST_F(CpuidX86Test, Branding)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||
@ -206,7 +221,7 @@ TEST_F(CpuidX86Test, Branding)
|
||||
|
||||
TEST_F(CpuidX86Test, KabyLakeCache)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||
@ -256,7 +271,7 @@ TEST_F(CpuidX86Test, KabyLakeCache)
|
||||
|
||||
TEST_F(CpuidX86Test, HSWCache)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||
@ -307,7 +322,7 @@ TEST_F(CpuidX86Test, HSWCache)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0200F30_K11_Griffin_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K11_GRIFFIN)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000001, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00200F30, 0x00020800, 0x00002001, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001A, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
@ -324,7 +339,7 @@ TEST_F(CpuidX86Test, AMD_K11_GRIFFIN)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0300F10_K12_Llano_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K12_LLANO)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00300F10, 0x00040800, 0x00802009, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
@ -341,7 +356,7 @@ TEST_F(CpuidX86Test, AMD_K12_LLANO)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F01_K14_Bobcat_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00500F01, 0x00020800, 0x00802209, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
@ -358,7 +373,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F01)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F10_K14_Bobcat_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00500F10, 0x00020800, 0x00802209, 0x178BFBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
@ -383,7 +398,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F10)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0500F20_K14_Bobcat_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000006, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00500F20, 0x00020800, 0x00802209, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001B, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
@ -400,7 +415,7 @@ TEST_F(CpuidX86Test, AMD_K14_BOBCAT_AMD0500F20)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0670F00_K15_StoneyRidge_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00670F00, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x000001A9, 0x00000000, 0x00000000}},
|
||||
@ -426,7 +441,7 @@ TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
|
||||
@ -449,10 +464,59 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI)
|
||||
EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 ");
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO)
|
||||
{
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}},
|
||||
{{0x8000001D, 0}, Leaf{0x00000121, 0x00C0003F, 0x0000003F, 0x00000000}},
|
||||
{{0x8000001D, 1}, Leaf{0x00004122, 0x0040003F, 0x000001FF, 0x00000000}},
|
||||
{{0x8000001D, 2}, Leaf{0x00004143, 0x03C0003F, 0x000007FF, 0x00000001}},
|
||||
{{0x8000001D, 3}, Leaf{0x0001C163, 0x0BC0003F, 0x000007FF, 0x00000001}},
|
||||
});
|
||||
const auto info = GetX86CacheInfo();
|
||||
|
||||
EXPECT_EQ(info.size, 4);
|
||||
EXPECT_EQ(info.levels[0].level, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 16 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, 4);
|
||||
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, 1);
|
||||
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, 2);
|
||||
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 512);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 2);
|
||||
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 2 * MiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 16);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, 2048);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 48);
|
||||
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, 2048);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00600F12, 0x000C0800, 0x1E98220B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
@ -478,7 +542,7 @@ TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
@ -506,7 +570,7 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0700F01_K16_Kabini_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00700F01, 0x00040800, 0x3ED8220B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
|
||||
@ -531,7 +595,7 @@ TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0730F01_K16_Beema_CPUID2.txt
|
||||
TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00730F01, 0x00040800, 0x7ED8220B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x00000008, 0x00000000, 0x00000000}},
|
||||
@ -556,7 +620,7 @@ TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0820F01_K17_Dali_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00820F01, 0x00020800, 0x7ED8320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
|
||||
@ -581,7 +645,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0800F82_K17_ZenP_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00800F82, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x209C01A9, 0x00000000, 0x00000000}},
|
||||
@ -606,7 +670,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE)
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0840F70_K17_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00840F70, 0x00100800, 0x7ED8320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x219C91A9, 0x00400004, 0x00000000}},
|
||||
@ -631,7 +695,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X)
|
||||
// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID3.txt
|
||||
TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
|
||||
{{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x009C01A9, 0x0040068C, 0x00000000}},
|
||||
@ -653,10 +717,59 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA)
|
||||
EXPECT_STREQ(brand_string, "Hygon C86 3185 8-core Processor ");
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO)
|
||||
{
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
|
||||
{{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
|
||||
{{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
|
||||
{{0x8000001D, 0}, Leaf{0x00004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||
{{0x8000001D, 1}, Leaf{0x00004122, 0x00C0003F, 0x000000FF, 0x00000000}},
|
||||
{{0x8000001D, 2}, Leaf{0x00004143, 0x01C0003F, 0x000003FF, 0x00000002}},
|
||||
{{0x8000001D, 3}, Leaf{0x0001C163, 0x03C0003F, 0x00001FFF, 0x00000001}},
|
||||
});
|
||||
const auto info = GetX86CacheInfo();
|
||||
|
||||
EXPECT_EQ(info.size, 4);
|
||||
EXPECT_EQ(info.levels[0].level, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, 8);
|
||||
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, 1);
|
||||
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, 4);
|
||||
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 256);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 2);
|
||||
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 8);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 8 * MiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 16);
|
||||
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER)
|
||||
{
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000010, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00A20F10, 0x01180800, 0x7ED8320B, 0x178BFBFF}},
|
||||
{{0x00000007, 0}, Leaf{0x00000000, 0x219C97A9, 0x0040068C, 0x00000000}},
|
||||
@ -682,21 +795,18 @@ TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER)
|
||||
TEST_F(CpuidX86Test, Nehalem)
|
||||
{
|
||||
// Pre AVX cpus don't have xsave
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||
cpu().SetOsBackupsExtendedRegisters(false);
|
||||
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||
#elif defined(CPU_FEATURES_OS_DARWIN)
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse2");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse3");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||
#elif defined(CPU_FEATURES_OS_FREEBSD)
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/var/run/dmesg.boot", R"(
|
||||
@ -713,7 +823,7 @@ real memory = 2147418112 (2047 MB)
|
||||
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||
)");
|
||||
#endif
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
|
||||
@ -768,21 +878,18 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||
TEST_F(CpuidX86Test, Atom)
|
||||
{
|
||||
// Pre AVX cpus don't have xsave
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||
cpu().SetOsBackupsExtendedRegisters(false);
|
||||
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||
#elif defined(CPU_FEATURES_OS_DARWIN)
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse2");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse3");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||
#elif defined(CPU_FEATURES_OS_FREEBSD)
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/var/run/dmesg.boot", R"(
|
||||
@ -799,7 +906,7 @@ real memory = 2147418112 (2047 MB)
|
||||
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||
)");
|
||||
#endif
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
|
||||
@ -850,16 +957,68 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||
#endif // !defined(CPU_FEATURES_OS_WINDOWS)
|
||||
}
|
||||
|
||||
// https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation
|
||||
TEST_F(CpuidX86Test, P4_CacheInfo)
|
||||
{
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x665B5001, 0x00000000, 0x00000000, 0x007A7000}},
|
||||
});
|
||||
|
||||
const auto info = GetX86CacheInfo();
|
||||
EXPECT_EQ(info.size, 5);
|
||||
|
||||
EXPECT_EQ(info.levels[0].level, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 4 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 4 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 1);
|
||||
EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 8 * KiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 4);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 1);
|
||||
EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 12 * KiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 8);
|
||||
EXPECT_EQ(info.levels[3].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[4].level, 2);
|
||||
EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA);
|
||||
EXPECT_EQ(info.levels[4].cache_size, 256 * KiB);
|
||||
EXPECT_EQ(info.levels[4].ways, 8);
|
||||
EXPECT_EQ(info.levels[4].line_size, 64);
|
||||
EXPECT_EQ(info.levels[4].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[4].partitioning, 2);
|
||||
}
|
||||
|
||||
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
|
||||
TEST_F(CpuidX86Test, P3)
|
||||
{
|
||||
// Pre AVX cpus don't have xsave
|
||||
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||
cpu().SetOsBackupsExtendedRegisters(false);
|
||||
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
cpu().SetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
#elif defined(CPU_FEATURES_OS_DARWIN)
|
||||
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||
cpu().SetDarwinSysCtlByName("hw.optional.sse");
|
||||
#elif defined(CPU_FEATURES_OS_FREEBSD)
|
||||
auto& fs = GetEmptyFilesystem();
|
||||
fs.CreateFile("/var/run/dmesg.boot", R"(
|
||||
@ -875,7 +1034,7 @@ real memory = 2147418112 (2047 MB)
|
||||
flags : fpu mmx sse
|
||||
)");
|
||||
#endif
|
||||
g_fake_cpu->SetLeaves({
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
|
||||
|
@ -167,15 +167,25 @@ TEST(StringViewTest, CpuFeatures_StringView_HasWord)
|
||||
{
|
||||
// Find flags at beginning, middle and end.
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "first", ' '));
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
|
||||
EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "middle", ' '));
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "last", ' '));
|
||||
// Find flags at beginning, middle and end with a different separator
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first-middle-last"), "first", '-'));
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first-middle-last"), "middle", '-'));
|
||||
EXPECT_TRUE(
|
||||
CpuFeatures_StringView_HasWord(str("first-middle-last"), "last", '-'));
|
||||
// Do not match partial flags
|
||||
EXPECT_FALSE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
|
||||
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
|
||||
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "irst", ' '));
|
||||
EXPECT_FALSE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "mid", ' '));
|
||||
EXPECT_FALSE(
|
||||
CpuFeatures_StringView_HasWord(str("first middle last"), "las", ' '));
|
||||
}
|
||||
|
||||
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue)
|
||||
|
Loading…
Reference in New Issue
Block a user