【问题标题】:How to receive L1, L2 & L3 cache size using CPUID instruction in x86如何在 x86 中使用 CPUID 指令接收 L1、L2 和 L3 缓存大小
【发布时间】:2012-12-26 07:56:20
【问题描述】:

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

我试图在英特尔文档和 Internet 中查找内容,但失败了。

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

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

【问题讨论】:

  • 它是用于您的个人项目还是您将交付给客户的东西?它应该独立于操作系统吗?
  • 这是我的个人项目,没有任何商业意义。我希望它在 Windows 上工作,因为在这里我可以检查我得到的结果与 CPU-Z 程序相比是否正确,即
  • 您可以使用 Yeppp 的 yepLibrary_GetCpuDataCacheSize 和 yepLibrary_GetCpuInstructionCacheSize 函数!图书馆 (www.yeppp.info)。请注意,这些 API 不受官方支持,将在未来版本中删除。
  • 如果您想直接从 CPU 获取信息,请阅读英特尔架构手册中的 CPUID 指令说明。请注意,大约有 5 个 CPUID 叶子可以指定缓存大小信息。
  • CPUID 与缓存信息一起离开:2(缓存描述符,其含义参见 Intel 架构手册,另外参见 Cyrix 手册以了解它们在 Cyrix 处理器上的含义,AMD CPU 有 0 个缓存描述符),4(较新Intel CPUs), 0x80000005 (AMD-only), 0x80000006 (AMD-only expect L2 information which is also provided on Intel CPUs), 0x8000001D (AMD-only, used on Bulldozer CPUs, and can contradict the leaf 0x80000006)

标签: caching x86 intel cpu-cache cpuid


【解决方案1】:

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/ 给出,更具体地说,在标题为“缓存拓扑枚举”的部分中。

【讨论】:

【解决方案2】:

您可以通过 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

【讨论】:

    【解决方案3】:

    对于英特尔 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“供应商/系列/型号/步进”(来自“CPUID,eax=0x0000001”)与一个表(或每个供应商可能 1 个表)一起使用,以便您可以在表中搜索正确的 CPU 并获取这样的信息。

    • 如果不支持CPUID,则可以尝试缩小可能性并以合理的准确度确定CPU是什么;但大多数情况下你应该放弃。

    另外;对于所有 CPU,您应该浏览勘误表以查看 CPUID 是否提供了错误信息;并实施变通方法来纠正错误信息。

    请注意(取决于您支持的 CPU 范围以及您希望代码的出色性能)可能需要几个月的工作才能提取有关缓存的可靠信息。

    【讨论】:

      猜你喜欢
      • 2014-07-04
      • 2020-05-19
      • 2017-03-10
      • 2014-02-16
      • 2021-11-24
      • 2013-01-20
      • 1970-01-01
      • 2021-11-27
      相关资源
      最近更新 更多