diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c index d0b61b857..47c711928 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c @@ -1134,32 +1134,31 @@ 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++; } } @@ -1169,23 +1168,18 @@ static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) 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, 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, @@ -1501,6 +1495,7 @@ CacheInfo GetX86CacheInfo(void) const Leaf leaf_0 = CpuId(0); if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) { + info.size = 0; ParseLeaf2(leaf_0.eax, &info); ParseCacheInfo(leaf_0.eax, 4, &info); } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc index d1f8fe83a..4c242cf8b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc @@ -167,6 +167,7 @@ TEST_F(CpuidX86Test, SandyBridge) EXPECT_FALSE(features.adx); } +const int UNDEF = -1; const int KiB = 1024; const int MiB = 1024 * KiB; @@ -956,6 +957,59 @@ 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) {