Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cstdio>
- #if defined(_MSC_VER)
- #include <intrin.h>
- #elif defined(__GNUC__)
- #include <cpuid.h>
- #endif
- struct X86CacheHierarchy {
- unsigned long l1d;
- unsigned long l1d_threads;
- unsigned long l2;
- unsigned long l2_threads;
- unsigned long l3;
- unsigned long l3_threads;
- bool l2_inclusive;
- bool l3_inclusive;
- bool valid;
- };
- /**
- * Execute the CPUID instruction.
- *
- * @param regs array to receive eax, ebx, ecx, edx
- * @param eax argument to instruction
- * @param ecx argument to instruction
- */
- void do_cpuid(int regs[4], int eax, int ecx)
- {
- #if defined(_MSC_VER)
- __cpuidex(regs, eax, ecx);
- #elif defined(__GNUC__)
- __cpuid_count(eax, ecx, regs[0], regs[1], regs[2], regs[3]);
- #else
- regs[0] = 0;
- regs[1] = 0;
- regs[2] = 0;
- regs[3] = 0;
- #endif
- }
- X86CacheHierarchy do_query_x86_cache_hierarchy_intel() noexcept
- {
- X86CacheHierarchy cache = { 0 };
- int regs[4];
- unsigned l1d_threads = 0;
- unsigned l2_threads = 0;
- unsigned l3_threads = 0;
- for (int i = 0; i < 8; ++i) {
- unsigned threads;
- unsigned long line_size;
- unsigned long partitions;
- unsigned long ways;
- unsigned long sets;
- unsigned long cache_size;
- int cache_type;
- bool inclusive;
- do_cpuid(regs, 4, i);
- cache_type = regs[0] & 0x1F;
- printf("cache type: %d\n", cache_type);
- // No more caches.
- if (cache_type == 0)
- break;
- // Not data or unified cache.
- if (cache_type != 1 && cache_type != 3)
- continue;
- threads = ((static_cast<unsigned>(regs[0]) >> 14) & 0x0FFFU) + 1;
- line_size = ((static_cast<unsigned>(regs[1]) >> 0) & 0x0FFFU) + 1;
- partitions = ((static_cast<unsigned>(regs[1]) >> 12) & 0x03FFU) + 1;
- ways = ((static_cast<unsigned>(regs[1]) >> 22) & 0x03FFU) + 1;
- sets = static_cast<unsigned>(regs[2]) + 1;
- cache_size = line_size * partitions * ways * sets;
- inclusive = regs[3] & (1U << 1);
- // Cache level.
- switch ((regs[0] >> 5) & 0x07) {
- case 1:
- cache.l1d = cache_size;
- cache.l1d_threads = threads;
- break;
- case 2:
- cache.l2 = cache_size;
- cache.l2_threads = threads;
- cache.l2_inclusive = inclusive;
- break;
- case 3:
- cache.l3 = cache_size;
- cache.l3_threads = threads;
- cache.l3_inclusive = inclusive;
- break;
- default:
- break;
- }
- }
- // Determine actual number of logical processors.
- for (int i = 0; i < 8; ++i) {
- unsigned logical_processors;
- do_cpuid(regs, 0x0B, i);
- if (((regs[2] >> 8) & 0xFF) == 0)
- break;
- logical_processors = regs[1] & 0xFFFFU;
- if (logical_processors < cache.l1d_threads)
- l1d_threads = logical_processors;
- if (logical_processors < cache.l2_threads)
- l2_threads = logical_processors;
- if (logical_processors < cache.l3_threads)
- l3_threads = logical_processors;
- }
- if (l1d_threads)
- cache.l1d_threads = l1d_threads;
- if (l2_threads)
- cache.l2_threads = l2_threads;
- if (l3_threads)
- cache.l3_threads = l3_threads;
- cache.valid = true;
- return cache;
- }
- X86CacheHierarchy do_query_x86_cache_hierarchy() noexcept
- {
- enum { GENUINEINTEL, AUTHENTICAMD, OTHER } vendor;
- int regs[4];
- int max_feature;
- do_cpuid(regs, 0, 1);
- max_feature = regs[0] & 0xFF;
- if (regs[1] == 0x756E6547U && regs[3] == 0x49656E69U && regs[2] == 0x6C65746EU)
- vendor = GENUINEINTEL;
- else if (regs[1] == 0x68747541U && regs[3] == 0x69746E65U && regs[2] == 0x444D4163U)
- vendor = AUTHENTICAMD;
- else
- vendor = OTHER;
- if (vendor == GENUINEINTEL && max_feature >= 0x0B)
- return do_query_x86_cache_hierarchy_intel();
- else
- return{};
- }
- int main()
- {
- auto cache = do_query_x86_cache_hierarchy();
- if (!cache.valid) {
- puts("No cache!");
- return 0;
- }
- printf("L1d: %lu / %u\n", cache.l1d, cache.l1d_threads);
- printf("L2: %lu / %u (%c)\n", cache.l2, cache.l2_threads, cache.l2_inclusive ? 'i' : 'x');
- printf("L3: %lu / %u (%c)\n", cache.l3, cache.l3_threads, cache.l3_inclusive ? 'i' : 'x');
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement