C Program to determine Levels & Size of Cache

前端 未结 6 977
北海茫月
北海茫月 2020-11-30 00:38

Full Re-Write/Update for clarity (and your sanity, its abit too long) ... (Old Post)

For an assignment, I need to find the levels (L1,L2,...) and si

6条回答
  •  粉色の甜心
    2020-11-30 01:24

    After 10 minutes of searching the Intel instruction manual and another 10 minutes of coding I came up with this (for Intel based processors):

    void i386_cpuid_caches () {
        int i;
        for (i = 0; i < 32; i++) {
    
            // Variables to hold the contents of the 4 i386 legacy registers
            uint32_t eax, ebx, ecx, edx; 
    
            eax = 4; // get cache info
            ecx = i; // cache id
    
            __asm__ (
                "cpuid" // call i386 cpuid instruction
                : "+a" (eax) // contains the cpuid command code, 4 for cache query
                , "=b" (ebx)
                , "+c" (ecx) // contains the cache id
                , "=d" (edx)
            ); // generates output in 4 registers eax, ebx, ecx and edx 
    
            // See the page 3-191 of the manual.
            int cache_type = eax & 0x1F; 
    
            if (cache_type == 0) // end of valid cache identifiers
                break;
    
            char * cache_type_string;
            switch (cache_type) {
                case 1: cache_type_string = "Data Cache"; break;
                case 2: cache_type_string = "Instruction Cache"; break;
                case 3: cache_type_string = "Unified Cache"; break;
                default: cache_type_string = "Unknown Type Cache"; break;
            }
    
            int cache_level = (eax >>= 5) & 0x7;
    
            int cache_is_self_initializing = (eax >>= 3) & 0x1; // does not need SW initialization
            int cache_is_fully_associative = (eax >>= 1) & 0x1;
    
            // See the page 3-192 of the manual.
            // ebx contains 3 integers of 10, 10 and 12 bits respectively
            unsigned int cache_sets = ecx + 1;
            unsigned int cache_coherency_line_size = (ebx & 0xFFF) + 1;
            unsigned int cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1;
            unsigned int cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1;
    
            // Total cache size is the product
            size_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets;
    
            printf(
                "Cache ID %d:\n"
                "- Level: %d\n"
                "- Type: %s\n"
                "- Sets: %d\n"
                "- System Coherency Line Size: %d bytes\n"
                "- Physical Line partitions: %d\n"
                "- Ways of associativity: %d\n"
                "- Total Size: %zu bytes (%zu kb)\n"
                "- Is fully associative: %s\n"
                "- Is Self Initializing: %s\n"
                "\n"
                , i
                , cache_level
                , cache_type_string
                , cache_sets
                , cache_coherency_line_size
                , cache_physical_line_partitions
                , cache_ways_of_associativity
                , cache_total_size, cache_total_size >> 10
                , cache_is_fully_associative ? "true" : "false"
                , cache_is_self_initializing ? "true" : "false"
            );
        }
    }
    

    Reference: Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A , page 3-190, CPUID—CPU Identification.

    This is much more reliable then measuring cache latencies as it is pretty much impossible to turn off cache prefetching on a modern processor. If you require similar info for a different processor architecture you will have to consult the respective manual.

提交回复
热议问题