52

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

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

4

7 回答 7

67

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

可是等等!!! 保佑他的灵魂的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 系列 CPU使用一个拆分 L1,每个集群有一个 16kiB 4 路关联 L1D(每个内核 2 个)。

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

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

于 2009-04-04T01:05:07.260 回答
30

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

在此处输入图像描述

第 46 页,第 2.2.5.1 节英特尔® 64 和 IA-32 架构优化参考手册

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

更新 I:Hazwell 将缓存加载性能提高了 2 倍,来自 Tock 内部;哈斯韦尔的建筑

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

Haswell's URS(统一预订站)

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

SkyLake 缓存规格

于 2013-11-02T21:38:45.630 回答
8

您正在查看消费者规范,而不是开发人员规范。 这是您想要的文档。缓存大小因处理器系列子型号而异,因此它们通常不在 IA-32 开发手册中,但您可以在 NewEgg 等上轻松查找它们。

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

于 2009-04-04T01:06:21.860 回答
8

我又做了一些调查。苏黎世联邦理工学院的一个小组建立了一个内存性能评估工具,该工具可能能够获取有关 L1 和 L2 缓存的大小(也可能是关联性)的信息。该程序通过实验尝试不同的读取模式并测量产生的吞吐量来工作。Bryant 和 O'Hallaron的流行教科书使用了简化版本。

于 2009-04-04T19:03:28.650 回答
2

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

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

于 2009-04-04T00:11:34.160 回答
2

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

于 2009-04-04T00:59:37.850 回答
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)

使用with set to查询WaysPartitionsLine_Size的位置。Setscpuideax0x04

提供头文件声明

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);
}
于 2019-08-17T12:53:19.727 回答