You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于__asm实现跨Intel/AMD的L3缓存检测与关联度获取问题排查

CPUID函数问题排查:has_l3_cache返回false、get_l3_cache_associativity结果错误

问题背景

作为汇编新手,我用__asm编写了三个函数:has_cpuid()、has_l3_cache()、get_l3_cache_associativity()。其中has_cpuid()工作正常,但明明CPU有L3缓存,has_l3_cache()却返回false,get_l3_cache_associativity()返回的关联度也不正确。以下是原代码:

#include <stdio.h>
#include <stdbool.h>

/* Function to check CPUID support */
bool has_cpuid() {
     int id_bit;
     __asm {
         pushfd             // Push EFLAGS on the stack
         pop eax            // Load EFLAGS flags into EAX
         mov ecx, eax       // Save a copy
         xor eax, 200000h   // Toggle the ID bit in EAX
         push eax           // Push new EFLAGS on the stack
         popfd              // Restore EFLAGS from the stack
         pushfd             // Save EFLAGS back on the stack
         pop eax            // Load EFLAGS flags into EAX again
         xor eax, ecx       // If the ID bit has changed, then the CPUID is supported
         shr eax, 21        // Move result to least significant bit
         mov id_bit,eax
     }
     return id_bit;
}

/* Function to check for L3 cache */
bool has_l3_cache() {
     int cacheLevel;
     __asm {
         mov eax, 0x80000006
         cpuid
         mov cacheLevel, ecx
     }
     return cacheLevel & (1 << 16);
}

/* Function to get L3 cache associativity */
int get_l3_cache_associativity() {
     int level = 3;         // L3 cache
     int result;
     __asm {
         mov eax, 4         // CPUID function for cache information
         mov ecx, level     // Cache level to check
         cpuid              // Call CPUID
         mov eax, ebx       // Associativity data is in EBX[31:22]
         shr eax, 22        // Move Associativity Data To LSB
         inc eax            // CPUID returns n-1, so increase by 1
         mov result, eax
     }
     return result;
}

int main() {
     if (!has_cpuid()) {
         printf("CPUID is not supported.\n");
         return 1;
     }

     if (has_l3_cache()) {
         printf("L3 Cache is present.\n");
         printf("L3 Cache associativity: %d\n", get_l3_cache_associativity());
     }
     else {
         printf("L3 Cache is not present.\n");
     }

     return 0;
}

问题分析与修正

1. has_l3_cache()函数错误

原代码存在两个核心问题:

  • 未提前确认CPU支持0x80000006扩展CPUID功能,需先调用0x80000000获取最大扩展功能号,判断其是否≥0x80000006。
  • 错误读取ECX寄存器并检查bit16,实际上0x80000006的EDX寄存器bits 15-8存储L3缓存大小(单位KB),该值非零则说明存在L3缓存。

修正后的has_l3_cache():

bool has_l3_cache() {
    int max_ext_func;
    __asm {
        mov eax, 0x80000000
        cpuid
        mov max_ext_func, eax
    }
    // 确认支持0x80000006扩展功能
    if (max_ext_func < 0x80000006) {
        return false;
    }
    
    int l3_size;
    __asm {
        mov eax, 0x80000006
        cpuid
        mov l3_size, edx
    }
    // 检查L3缓存大小是否大于0
    return (l3_size & 0xFF00) != 0;
}

2. get_l3_cache_associativity()函数错误

原代码的问题在于:

  • CPUID函数eax=4的ecx参数不是缓存级别,而是缓存类型索引,需要从ecx=0开始遍历,直到找到缓存级别为3的条目。
  • 未检查CPU是否支持eax=4功能,需先调用eax=0获取最大基本功能号,判断其是否≥4。

修正后的get_l3_cache_associativity():

int get_l3_cache_associativity() {
    int max_basic_func;
    __asm {
        mov eax, 0
        cpuid
        mov max_basic_func, eax
    }
    // 确认支持eax=4的缓存信息功能
    if (max_basic_func < 4) {
        return -1; // 不支持该功能,返回错误值
    }

    int ecx_idx = 0;
    int result = -1;
    while (1) {
        int eax_out, ebx_out;
        __asm {
            mov eax, 4
            mov ecx, ecx_idx
            cpuid
            mov eax_out, eax
            mov ebx_out, ebx
        }

        // 提取缓存级别(EAX的bits7-5)
        int cache_level = (eax_out >> 5) & 0x7;
        if (cache_level == 3) {
            // 提取关联度值(EBX的bits31-22,返回值为n-1)
            int assoc = (ebx_out >> 22) & 0x3FF;
            result = assoc + 1;
            break;
        }

        // 缓存类型为0时,无更多条目可遍历
        int cache_type = eax_out & 0x1F;
        if (cache_type == 0) {
            break;
        }

        ecx_idx++;
    }

    return result;
}

完整修正代码

#include <stdio.h>
#include <stdbool.h>

/* Function to check CPUID support */
bool has_cpuid() {
     int id_bit;
     __asm {
         pushfd             // Push EFLAGS on the stack
         pop eax            // Load EFLAGS flags into EAX
         mov ecx, eax       // Save a copy
         xor eax, 200000h   // Toggle the ID bit in EAX
         push eax           // Push new EFLAGS on the stack
         popfd              // Restore EFLAGS from the stack
         pushfd             // Save EFLAGS back on the stack
         pop eax            // Load EFLAGS flags into EAX again
         xor eax, ecx       // If the ID bit has changed, then the CPUID is supported
         shr eax, 21        // Move result to least significant bit
         mov id_bit,eax
     }
     return id_bit;
}

/* Function to check for L3 cache */
bool has_l3_cache() {
    int max_ext_func;
    __asm {
        mov eax, 0x80000000
        cpuid
        mov max_ext_func, eax
    }
    if (max_ext_func < 0x80000006) {
        return false;
    }
    
    int l3_size;
    __asm {
        mov eax, 0x80000006
        cpuid
        mov l3_size, edx
    }
    return (l3_size & 0xFF00) != 0;
}

/* Function to get L3 cache associativity */
int get_l3_cache_associativity() {
    int max_basic_func;
    __asm {
        mov eax, 0
        cpuid
        mov max_basic_func, eax
    }
    if (max_basic_func < 4) {
        return -1;
    }

    int ecx_idx = 0;
    int result = -1;
    while (1) {
        int eax_out, ebx_out;
        __asm {
            mov eax, 4
            mov ecx, ecx_idx
            cpuid
            mov eax_out, eax
            mov ebx_out, ebx
        }

        int cache_level = (eax_out >> 5) & 0x7;
        if (cache_level == 3) {
            int assoc = (ebx_out >> 22) & 0x3FF;
            result = assoc + 1;
            break;
        }

        int cache_type = eax_out & 0x1F;
        if (cache_type == 0) {
            break;
        }

        ecx_idx++;
    }

    return result;
}

int main() {
     if (!has_cpuid()) {
         printf("CPUID is not supported.\n");
         return 1;
     }

     if (has_l3_cache()) {
         printf("L3 Cache is present.\n");
         int assoc = get_l3_cache_associativity();
         if (assoc != -1) {
             printf("L3 Cache associativity: %d\n", assoc);
         } else {
             printf("Failed to get L3 Cache associativity.\n");
         }
     }
     else {
         printf("L3 Cache is not present.\n");
     }

     return 0;
}

内容的提问来源于stack exchange,提问作者Fenix FVE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:44:59