我想使用CPUID指令来获取每个缓存级别(L1、L2、L3)的大小。
我一直在读"AMD64体系结构程序员手册“第3卷:一般用途和系统说明。在第613页中有与L1相关的信息:

在第616页中有与L2和L3相关的信息。

我制作了一个简单的C+assembly程序来打印这些值。
const char* amd_L2_L3_associotivity_str(uint32_t code)
{
switch(code) {
case 0: return "Disabled";
case 1: return "1 way (direct mapped)";
case 2: return "2 way";
case 4: return "4 way";
case 6: return "8 way";
case 8: return "16 way";
case 10: return "32 way";
case 11: return "48 way";
case 12: return "64 way";
case 13: return "96 way";
case 14: return "128 way";
case 15: return "Fully Associative";
default: assert(0);
}
return 0;
}
void cpuid_caches_amd()
{
uint32_t eax, ebx, ecx, edx;
{ // L1
eax = 0x80000005; // the specific code of the cpuid instruction for L1
__asm__ (
"cpuid" // cpuid is the name of the instruction that queries the info we want
: "+a" (eax)
, "=b" (ebx)
, "=c" (ecx)
, "=d" (edx)
);
uint32_t
dataCache_size = ecx & 0xFF,
dataCache_associativity = (ecx >> 8) & 0xFF,
dataCache_linesPerTag = (ecx >> 16) & 0xFF,
dataCache_lineSize = (ecx >> 24) & 0xFF;
uint32_t
instrCache_size = edx & 0xFF,
instrCache_associativity = (edx >> 8) & 0xFF,
instrCache_linesPerTag = (edx >> 16) & 0xFF,
instrCache_lineSize = (edx >> 24) & 0xFF;
printf(
"L1 Data Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %d\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
"\n"
"L1 Instruction Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %d\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
,
dataCache_size,
dataCache_associativity,
dataCache_linesPerTag,
dataCache_lineSize,
instrCache_size,
instrCache_associativity,
instrCache_linesPerTag,
instrCache_lineSize
);
}
{ // L2, L3
eax = 0x80000006; // the specific code of the cpuid instruction for L1
__asm__ (
"cpuid" // cpuid is the name of the instruction that queries the info we want
: "+a" (eax)
, "=b" (ebx)
, "=c" (ecx)
, "=d" (edx)
);
uint32_t
L2_size = ecx & 0xFFFF,
L2_associativity = (ecx >> 16) & 0xF,
L2_linesPerTag = (ecx >> 20) & 0xF,
L2_lineSize = (ecx >> 24) & 0xFF;
uint32_t
L3_size = edx & 0x3FFF,
L3_associativity = (edx >> 16) & 0xF,
L3_linesPerTag = (edx >> 20) & 0xF,
L3_lineSize = (edx >> 24) & 0xFF;
printf(
"L2 Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %s\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
"\n"
"L3 Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %s\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
,
L2_size,
amd_L2_L3_associotivity_str(L2_associativity),
L2_linesPerTag,
L2_lineSize,
L3_size * 512,
amd_L2_L3_associotivity_str(L3_associativity),
L3_linesPerTag,
L3_lineSize
);
}
}
int main()
{
cpuid_caches_amd();
}这是我的Ryzen 3700X程序的输出:
L1 Data Cache:
Size: 64 KB
Associativity: 1
Lines per Tag: 8
Line Size: 32 B
L1 Instruction Cache:
Size: 64 KB
Associativity: 1
Lines per Tag: 8
Line Size: 32 B
L2 Cache:
Size: 24896 KB
Associativity: Disabled
Lines per Tag: 0
Line Size: 2 B
L3 Cache:
Size: 2260992 KB
Associativity: Disabled
Lines per Tag: 0
Line Size: 1 B根据这一点,我有2GB的L3缓存,这是不可能的。根据官方规范,它应该有L1: 512 4MB,L2: 4MB,L3: 32 4MB。
另一件让我困惑的是,L1DcSize只有8位宽。这只允许表示高达255 to的L1大小,尽管我的L1应该有512 to的L1!
我的密码怎么了?如何获得实际的缓存大小?
编辑:
谢谢大家的回复。正如人们所指出的,我的位移位是颠倒的。仍然存在关于缓存L1的问题。这就是代码现在的样子:
void cpuid_caches_amd()
{
uint32_t eax, ebx, ecx, edx;
{ // L1
eax = 0x80000005; // the specific code of the cpuid instruction for L1
__asm__ (
"cpuid" // cpuid is the name of the instruction that queries the info we want
: "+a" (eax)
, "=b" (ebx)
, "=c" (ecx)
, "=d" (edx)
);
uint32_t
dataCache_size = (ecx >> 24) & 0xFF,
dataCache_associativity = (ecx >> 16) & 0xFF,
dataCache_linesPerTag = (ecx >> 8) & 0xFF,
dataCache_lineSize = ecx & 0xFF;
uint32_t
instrCache_size = (edx >> 24) & 0xFF,
instrCache_associativity = (edx >> 16) & 0xFF,
instrCache_linesPerTag = (edx >> 8) & 0xFF,
instrCache_lineSize = edx & 0xFF;
printf(
"L1 Data Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %d\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
"\n"
"L1 Instruction Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %d\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
,
dataCache_size,
dataCache_associativity,
dataCache_linesPerTag,
dataCache_lineSize,
instrCache_size,
instrCache_associativity,
instrCache_linesPerTag,
instrCache_lineSize
);
}
{ // L2
eax = 0x80000006; // the specific code of the cpuid instruction for L1
__asm__ (
"cpuid" // cpuid is the name of the instruction that queries the info we want
: "+a" (eax)
, "=b" (ebx)
, "=c" (ecx)
, "=d" (edx)
);
uint32_t
L2_size = (ecx >> 16) & 0xFFFF,
L2_associativity = (ecx >> 12) & 0xF,
L2_linesPerTag = (ecx >> 8) & 0xF,
L2_lineSize = ecx & 0xFF;
uint32_t
L3_size = (edx >> 18) & 0x3FFF,
L3_associativity = (edx >> 12) & 0xF,
L3_linesPerTag = (edx >> 8) & 0xF,
L3_lineSize = (edx >> 0) & 0xFF;
printf(
"L2 Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %s\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
"\n"
"L3 Cache:\n"
"\tSize: %d KB\n"
"\tAssociativity: %s\n"
"\tLines per Tag: %d\n"
"\tLine Size: %d B\n"
,
L2_size,
amd_L2_L3_associotivity_str(L2_associativity),
L2_linesPerTag,
L2_lineSize,
L3_size * 512,
amd_L2_L3_associotivity_str(L3_associativity),
L3_linesPerTag,
L3_lineSize
);
}
}新的产出:
L1 Data Cache:
Size: 32 KB
Associativity: 8
Lines per Tag: 1
Line Size: 64 B
L1 Instruction Cache:
Size: 32 KB
Associativity: 8
Lines per Tag: 1
Line Size: 64 B
L2 Cache:
Size: 512 KB
Associativity: 8 way
Lines per Tag: 1
Line Size: 64 B
L3 Cache:
Size: 32768 KB
Associativity: Value for all fields should be determined from Fn8000_001D
Lines per Tag: 1
Line Size: 64 B发布于 2022-08-19 14:52:50
似乎你弄错了结果的位布局。大小结果在上位,但您正在提取下位。其他字段的顺序也类似地相反。
例如,L3Size在31:18中,但是您使用没有移位的0x3FFF掩码,它使用13:0。
而不是:
L3_size = edx & 0x3FFF,
L3_associativity = (edx >> 16) & 0xF,
L3_linesPerTag = (edx >> 20) & 0xF,
L3_lineSize = (edx >> 24) & 0xFF;写入:
L3_size = (edx >> 18) & 0x3FFF,
L3_associativity = (edx >> 12) & 0xF,
L3_linesPerTag = (edx >> 8) & 0xF,
L3_lineSize = (edx >> 0) & 0xFF;对其他寄存器也做同样的事情。字段的最低位数是您必须移动的数量。
至于关于L1大小的第二个问题,规格表有芯片总数。然而,从CPUID的角度来看,重要的是核心的缓存。如果将32 kiB of L1i和32 kiB of L1d乘以处理器中的8核,就会得到预期的512 kiB。
https://stackoverflow.com/questions/73418161
复制相似问题