我在准备一个汇编程序 x86 项目时遇到了一个问题,该项目的主题是编写一个获取 L1 数据、L1 代码、L2 和 L3 缓存大小的程序。
我试图在英特尔文档和互联网上找到一些东西,但我失败了。
主要问题是:对于 AMD 处理器,只需将 EAX 寄存器设置为 80000005h 和 80000006h 值并从 ECX 和 EDX 寄存器中获取所需的数据,但对于英特尔,我只能为 L2 获取此信息。
我应该怎么做才能获得英特尔处理器的 L1 和 L3 缓存大小?
Marat Dukhan 基本上给了你正确的答案。对于较新的英特尔处理器,即过去 5-6 年制造的处理器,最好的解决方案是枚举 cpuid 叶 4,这意味着您调用 cpuid 几次,首先使用 EAX=4 和 ECX=0,然后使用 EAX= 4和ECX = 1等等。这不仅会返回有关缓存大小和类型的信息,还会告诉您这些缓存如何连接到 CPU 内核和超线程/SMT 单元。算法和示例代码在https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/中给出,更具体地说,在标题为“缓存拓扑枚举”的部分中。
您可以使用 CPUID 指令获取 CPU L1、L2 和 L3 缓存大小。根据 Intel x86 Software Developer's Manual Volume 2 (Instruction Set Reference)。您可以通过 EAX 等于 2 或 4 的 CPUID insturciton 获取 CPU 缓存信息。EAX=2 是旧版本,似乎较新的 CPU 不使用它。所以我将介绍 EAX=4 的情况。
其输出格式为:
因此,您可以使用以下公式计算缓存大小:
缓存大小 = (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1) 或
缓存大小 = (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1)
例如,我在我的 ubuntu 系统中执行“cpuid -li”指令,得到以下输出:
deterministic cache parameters (4):
--- cache 0 ---
cache type = data cache (1)
cache level = 0x1 (1)
self-initializing cache level = true
fully associative cache = false
extra threads sharing this cache = 0x1 (1)
extra processor cores on this die = 0x7 (7)
system coherency line size = 0x3f (63)
physical line partitions = 0x0 (0)
ways of associativity = 0x7 (7)
ways of associativity = 0x0 (0)
WBINVD/INVD behavior on lower caches = false
inclusive to lower caches = false
complex cache indexing = false
number of sets - 1 (s) = 63
--- cache 1 ---
cache type = instruction cache (2)
cache level = 0x1 (1)
self-initializing cache level = true
fully associative cache = false
extra threads sharing this cache = 0x1 (1)
extra processor cores on this die = 0x7 (7)
system coherency line size = 0x3f (63)
physical line partitions = 0x0 (0)
ways of associativity = 0x7 (7)
ways of associativity = 0x0 (0)
WBINVD/INVD behavior on lower caches = false
inclusive to lower caches = false
complex cache indexing = false
number of sets - 1 (s) = 63
--- cache 2 ---
cache type = unified cache (3)
cache level = 0x2 (2)
self-initializing cache level = true
fully associative cache = false
extra threads sharing this cache = 0x1 (1)
**extra processor cores on this die = 0x7 (7)
system coherency line size = 0x3f (63)
physical line partitions = 0x0 (0)**
ways of associativity = 0x3 (3)
ways of associativity = 0x0 (0)
WBINVD/INVD behavior on lower caches = false
inclusive to lower caches = false
complex cache indexing = false
number of sets - 1 (s) = 1023
--- cache 3 ---
cache type = unified cache (3)
cache level = 0x3 (3)
self-initializing cache level = true
fully associative cache = false
extra threads sharing this cache = 0xf (15)
extra processor cores on this die = 0x7 (7)
system coherency line size = 0x3f (63)
physical line partitions = 0x0 (0)
ways of associativity = 0xb (11)
ways of associativity = 0x6 (6)
WBINVD/INVD behavior on lower caches = false
inclusive to lower caches = true
complex cache indexing = true
number of sets - 1 (s) = 12287
L1数据缓存大小为:(7+1) (0+1) (63+1)*(63+1)=32K
L3缓存大小为:(11+1) (0+1) (63+1)*(12287+1)=9M
对于英特尔 CPU:
对于较新的 CPU,您应该使用“CPUID, eax=0x00000004”(ECX 中的值不同)
对于较旧的 CPU(不支持第一个选项),您应该使用“CPUID,eax=0x00000002”。这涉及有一个表格来查找这些值的含义。在某些情况下,相同的值对不同的 CPU 意味着不同的东西,您需要额外的信息(例如 CPU 系列/型号/步进)。
对于威盛 CPU;使用与英特尔相同的方法(对于涉及“系列/型号/步进”的任何内容,使用不同的表格)。
对于 AMD CPU:
对于较新的 CPU,您应该使用“CPUID,eax=0x8000001D”(ECX 中的值不同)
对于较旧的 CPU(不支持第一个选项),您应该使用“CPUID, eax=0x80000006”(仅适用于 L2 和 L3),加上“CPUID, eax=0x80000005”(仅适用于 L1)。
对于所有其他情况(非常旧的 Intel/VIA/AMD CPU,其他制造商的 CPU):
使用 CPU “vendor/family/model/stepping”(来自“CPUID,eax=0x0000001”)和一个表(或者每个供应商可能 1 个表),这样您就可以在表中搜索正确的 CPU 并获取以下信息方法。
如果CPUID
不支持,则可以尝试缩小可能性并以合理的准确度确定 CPU 是什么;但大多数情况下你应该放弃。
此外; 对于所有 CPU,您应该浏览勘误表以查看 CPUID 是否提供了错误信息;并实施变通方法来纠正错误信息。
请注意(取决于您支持的 CPU 范围以及您希望您的代码有多棒)可能需要几个月的工作才能提取有关缓存的可靠信息。