【问题标题】:Where is the L1 memory cache of Intel x86 processors documented?Intel x86 处理器的 L1 内存缓存记录在哪里?
【发布时间】:2025-12-31 23:30:01
【问题描述】:

我正在尝试分析和优化算法,我想了解缓存对各种处理器的具体影响。对于最近的 Intel x86 处理器(例如 Q9300),很难找到有关缓存结构的详细信息。特别是,大多数后处理器规范的网站(包括Intel.com)不包含对 L1 缓存的任何引用。这是因为 L1 缓存不存在还是由于某种原因这些信息被认为不重要?有没有关于消除 L1 缓存的文章或讨论?

[编辑] 在运行各种测试和诊断程序(主要是在下面的答案中讨论的那些)之后,我得出结论,我的 Q9300 似乎有一个 32K L1 数据缓存。对于为什么这些信息如此难以获得,我仍然没有找到明确的解释。我目前的工作理论是,L1 缓存的细节现在被英特尔视为商业机密。

【问题讨论】:

  • Norman Ramsey 在下面的评论中指出了这一点,但我当时并没有意识到他的意思。 CPUID 是一条 x86 指令,可用于查询缓存详细信息。
  • 我刚刚在 Linux 上遇到了lscpu 命令,它可以很好地显示 x86 上的 CPU 数据——包括缓存摘要。

标签: performance intel cpu-architecture cpu-cache


【解决方案1】:

英特尔手册卷。 2 指定以下公式来计算缓存大小:

此缓存大小(以字节为单位)

= (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1)

= (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1)

其中WaysPartitionsLine_SizeSets 使用cpuid 查询,eax 设置为0x04

提供头文件声明

x86_cache_size.h:

unsigned int get_cache_line_size(unsigned int cache_level);

实现如下:

;1st argument - the cache level
get_cache_line_size:
    push rbx
    ;set line number argument to be used with CPUID instruction
    mov ecx, edi 
    ;set cpuid initial value
    mov eax, 0x04
    cpuid

    ;cache line size
    mov eax, ebx
    and eax, 0x7ff
    inc eax

    ;partitions
    shr ebx, 12
    mov edx, ebx
    and edx, 0x1ff
    inc edx
    mul edx

    ;ways of associativity
    shr ebx, 10
    mov edx, ebx
    and edx, 0x1ff
    inc edx
    mul edx

    ;number of sets
    inc ecx
    mul ecx

    pop rbx

    ret

在我的机器上运行如下:

#include "x86_cache_size.h"

int main(void){
    unsigned int L1_cache_size = get_cache_line_size(1);
    unsigned int L2_cache_size = get_cache_line_size(2);
    unsigned int L3_cache_size = get_cache_line_size(3);
    //L1 size = 32768, L2 size = 262144, L3 size = 8388608
    printf("L1 size = %u, L2 size = %u, L3 size = %u\n", L1_cache_size, L2_cache_size, L3_cache_size);
}

【讨论】:

【解决方案2】:

几乎不可能找到有关英特尔缓存的规范。去年我在教一门关于缓存的课程时,我问了英特尔内部的朋友(在编译器组中),他们找不到规范。

但是等等!!!Jed,保佑他的灵魂,告诉我们在 Linux 系统上,你可以从内核中挤出大量信息:

grep . /sys/devices/system/cpu/cpu0/cache/index*/*

这将为您提供关联性、集合大小和一堆其他信息(但不包括延迟)。 例如,我了解到虽然 AMD 宣传他们的 128K L1 缓存,但我的 AMD 机器有一个分离的 I 和 D 缓存,每个 64K。


感谢 Jed,现在大部分已经过时的两条建议:

  • AMD 发布了有关其缓存的更多信息,因此您至少可以获得一些有关现代缓存的信息。例如,去年的 AMD L1 缓存每个周期(峰值)提供两个字。

  • 开源工具valgrind 内部有各种缓存模型,对于分析和理解缓存行为非常有用。它带有一个非常不错的可视化工具kcachegrind,它是 KDE SDK 的一部分。


例如:在 2008 年第三季度,AMD K8/K10 CPU 使用 64 字节缓存线,每个 L1I/L1D 拆分缓存为 64kB。 L1D 与 L2 是 2 路关联和排他的,延迟为 3 个周期。 L2 缓存是 16 路关联的,延迟约为 12 个周期。

AMD Bulldozer-family CPUs 使用一个拆分 L1,每个集群有一个 16kiB 的 4 路关联 L1D(每个核心 2 个)。

Intel CPU 长期以来一直保持 L1 不变(从 Pentium M 到 Haswell 再到 Skylake,并且大概在此之后的许多代):每个 I 和 D 缓存拆分 32kB,L1D 是 8 路关联的。 64 字节高速缓存行,与 DDR DRAM 的突发传输大小相匹配。负载使用延迟约为 4 个周期。

另请参阅 标签 wiki,以获取更多性能和微架构数据的链接。

【讨论】:

  • 我已经开始尝试使用 kcachegrind。就我目前所发现的而言,我必须告诉工具我的缓存详细信息是什么——这就是我提出这个问题的原因。您提到了“缓存模型”。你的意思是说 valgrind 可能知道我正在寻找的细节?
  • 是的,绝对是——valgrind 查询 CPUID,如果它识别出你的 CPU,它会使用那个 CPU 的模型。
  • 与我在 Linux 上运行的其他一些工具(cpuid 和 x86info)一样,valgrind 似乎对我机器的缓存配置感到困惑。也许这只是我不认识我的 CPU 的问题,或者这表明英特尔隐瞒了信息。
  • 英特尔 L1 是 8 路关联的。在 Linux 上,您可以从 /sys/devices/system/cpu/cpu*/index*/cache 中提取所有号码。此外,使用 glibc 的系统通常有getconf(1),使用类似getconf LEVEL1_DCACHE_ASSOC
  • @Jed:感谢您提出这些好建议! @Norman:grep 的巧妙技巧——感谢您更新您的帖子! @getconf:你这辈子都去哪儿了? :-)
【解决方案3】:

本英特尔手册:英特尔® 64 和 IA-32 架构优化参考手册对缓存注意事项进行了不错的讨论。

第 46 页,第 2.2.5.1 节 Intel® 64 and IA-32 Architectures Optimization Reference Manual

甚至 MicroSlop 也意识到需要更多工具来监控缓存使用和性能,并且有一个 GetLogicalProcessorInformation() function 示例(......同时在创建过程中创建荒谬的长函数名称时开辟了新的道路)我想我'我会编码。

更新 I:Hazwell 将缓存加载性能提高了 2 倍,从 Inside the Tock; Haswell's Architecture

如果对充分利用缓存的重要性有任何疑问,前 Azul 的 Cliff Click 的this presentation 应该可以消除所有疑问。用他的话来说,“内存就是新磁盘!”。

更新二:SkyLake 显着改进的缓存性能规格。

【讨论】:

  • 很棒的发现,很有帮助!
  • @nobar,谢谢,我自己正朝着那个方向前进,所以我想我不妨为你等出租车。 :)
  • @RocketRoy 你能看看这个缓存问题吗? *.com/questions/30555623/…
【解决方案4】:

我做了更多调查。苏黎世联邦理工学院的一个小组建立了一个memory-performance evaluation tool,它可能能够至少获得有关 L1 和 L2 缓存大小(也可能是关联性)的信息。该程序通过实验尝试不同的读取模式并测量产生的吞吐量来工作。 popular textbook by Bryant and O'Hallaron 使用了简化版本。

【讨论】:

  • 我试过这些(我写了一个类似的程序)。结果表明我的 Q9300 在 32K 和 3M 处的性能结果不连续。感谢您的帮助!
【解决方案5】:

您查看的是消费者规范,而不是开发者规范。 Here is the documentation you want. 缓存大小因处理器系列子型号而异,因此它们通常不在 IA-32 开发手册中,但您可以在 NewEgg 等上轻松查找。

编辑: 更具体地说:第 3A 卷(系统编程指南)的第 10 章,优化参考手册的第 7 章,以及可能在 TLB 页面缓存手册中的内容,尽管我会假设一个比你关心的离 L1 更远。

【讨论】:

  • 我在这些手册中找不到真正的缓存数据。你能引用卷数和页码吗?
  • 我不太清楚你所说的“真实”是什么意思,但优化手册的第 7 章是一个详细介绍的地方。还有关于 TLB 和页面缓存的完整手册。了解您要确切地在寻找什么会有所帮助。
  • 还有第 3A 卷的第 10 章,系统编程指南。
  • 我找到了第 3A 卷的表 10-1。它没有列出单个处理器,但确实提供了各种处理器系列的缓存信息的详细信息(或至少是数字范围)。它仍然有点模棱两可(Core 2 Quad 没有明确列出 L1),但它是一些东西。谢谢!
  • 像大多数其他资源一样,newegg 没有将我的 Q9300 列为具有 L1 缓存(我也没有在您引用的英特尔文档中明确指出)。我猜测该芯片上不存在 L1 缓存——但我仍然只是猜测。
【解决方案6】:

Locality of Reference对某些算法的性能有重大影响; L1、L2(以及在较新的 CPU L3 上)缓存的大小和速度显然在其中发挥了重要作用。矩阵乘法就是这样一种算法。

【讨论】:

    【解决方案7】:

    这些平台上存在 L1 缓存。在内存和前端总线速度超过 CPU 速度之前,这几乎肯定会保持不变,这很可能还有很长的路要走。

    在 Windows 上,您可以使用GetLogicalProcessorInformation 获取某种级别的缓存信息(大小、行大小、关联性等)。Win7 上的 Ex 版本将提供更多数据,例如哪些内核共享哪些缓存。 CpuZ 也提供此信息。

    【讨论】:

    • 感谢您的建议。我能够运行 CpuZ——它告诉我我的 L1 数据缓存是 32K 字节(每个内核)。现在我只需要弄清楚我是否相信这些信息。
    • 你能解释一下为什么你对CpuZ的准确性如此自信吗?很高兴有这样的工具存在,但我无法找到强有力的确凿数据,这动摇了我的信心。
    • 我看到数据表明二级缓存以 CPU 时钟速度(2.5 GHz)运行。对我来说,这表明前端总线速度与 L1 存在的问题无关——L2 缓存比 FSB 快。
    • 这篇文章也促使我找到了类似的基于 Linux 的程序:cpuid 和 x86info。 x86info 给了我与 CpuZ 所说的相匹配的 L1 数据。但是,这两个程序的各种不一致和警告仍然让我怀疑。