如何使用x86中的CPUID指令获取L1、L2和L3缓存大小

8

在准备一个汇编x86项目时,我遇到了一个问题,即编写一个程序以获取L1数据、L1代码、L2和L3缓存大小。

我尝试在英特尔文档和互联网上寻找相关信息,但都没有成功。

主要问题是:对于AMD处理器,只需将EAX寄存器设置为80000005h和80000006h的值,然后从ECX和EDX寄存器中获取所需数据,但对于英特尔处理器,我只能获取L2的信息。

我该怎么做才能获取英特尔处理器的L1和L3缓存大小?


这是你的个人项目还是要交付给客户?它需要跨操作系统吗? - Marat Dukhan
这是我的个人项目,没有商业目的。我希望它能在Windows上运行,因为这样我可以与CPU-Z程序比较来检查结果是否正确。 - Tomek Janiuk
如果你想直接从CPU中获取信息,可以在英特尔架构手册中查看CPUID指令的描述。请注意,有大约5个CPUID叶子节点可以指定缓存大小信息。 - Marat Dukhan
2
CPUID 带有缓存信息:2(缓存描述符,请参阅英特尔架构手册了解其含义,此外请参阅 Cyrix 手册了解其在 Cyrix 处理器上的含义,AMD CPU 没有缓存描述符),4(较新的 Intel CPU),0x80000005(仅限 AMD),0x80000006(仅限 AMD,但提供了 L2 信息,这也适用于 Intel CPU),0x8000001D(仅限 AMD,在 Bulldozer CPU 上使用,并且可能与叶子 0x80000006 相矛盾)。 - Marat Dukhan
哇,谢谢!所以要获取新的英特尔CPU缓存大小信息,我需要调用CPUID函数4,然后浏览寄存器,查找文档中指定的值,对吗?我以为这和AMD一样(好吧,老实说我想应该更简单),在那里你可以直接得到KB的值。 - Tomek Janiuk
3个回答

4
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/中给出,更具体地说,在标题为“Cache Topology Enumeration”的部分中。

3
我建议您查看glibc或其他libc实现在getconf LEVEL2_CACHE_SIZE方面的做法。 glibc源代码可以在以下链接找到:https://superuser.com/questions/55776/how-to-find-the-l2-cache-size-in-linux/1298808#1298808 - Ciro Santilli OurBigBook.com

1

对于Intel CPU:

  • 对于新一代的CPU,您应该使用 "CPUID, eax=0x00000004" (在ECX中使用不同的值)

  • 对于旧一代的CPU(不支持第一个选项),您应该使用 "CPUID, eax=0x00000002"。这需要有一个表格来查找值的含义。在某些情况下,相同的值对于不同的CPU有不同的含义,您需要额外的信息(例如,CPU家族/型号/步进)。

对于VIA CPU:使用与Intel相同的方法(涉及到"family/model/stepping"时使用不同的表格)。

对于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")与一个表格(或者也许是每一个制造商一个表格),这样你就可以在你的表格中搜索正确的CPU,并以此获得信息。

  • 如果不支持CPUID,则有办法尝试缩小可能性并合理准确地确定CPU;但大多数情况下你应该放弃。

此外,对于所有的CPU,你应该查看勘误表,以查看CPUID是否提供了错误的信息;并实施解决这些错误信息的方法。

请注意,(取决于您支持哪些范围的CPU和您想让您的代码有多棒),仅提取关于高速缓存的可靠信息可能需要几个月的工作。


1
你可以使用CPUID指令获取CPU的L1、L2和L3缓存大小。根据英特尔x86软件开发人员手册第2卷(指令集参考),您可以通过EAX等于2或4的CPUID指令获取CPU缓存信息。EAX=2是旧版本,似乎新的CPU不再使用它。因此,我将介绍EAX=4的情况。
其输出格式为:

CPUID4_1

CPUID4_2

因此,您可以使用以下公式计算缓存大小:

Cache size = (路数 + 1) * (分区数 + 1) * (行大小 + 1) * (集数 + 1) 或者

Cache size = (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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接