英译中:英特尔x86处理器的L1内存缓存在哪里有文档记录?

52

我正在尝试对算法进行分析和优化,并且想了解缓存对不同处理器的具体影响。对于最新的英特尔x86处理器(例如Q9300),很难找到有关缓存结构的详细信息。特别是,大多数网站(包括Intel.com)发布处理器规格的页面都没有提到L1缓存。这是因为L1缓存不存在还是因为这些信息被认为不重要而被省略了?是否有任何关于取消L1缓存的文章或讨论?

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


这是Norman Ramsey在下面的评论中指出的,但当时我没有意识到他的意思。CPUID是一种x86指令,可用于查询缓存详细信息。 - Brent Bradburn
我刚在Linux上遇到了lscpu命令,它可以非常好地显示x86 CPU数据,包括缓存摘要。 - Brent Bradburn
7个回答

67

要找到有关Intel缓存的规格几乎是不可能的。去年我教授高速缓存课程时,我向英特尔(编译器组内)的朋友询问过,他们无法找到规格。

但等等!!!感谢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 字节的缓存行,具有 64KB 的 L1I/L1D 分离缓存。L1D 是 2 路组相联的,与 L2 排斥,延迟为 3 个周期。L2 缓存是 16 路组相联的,延迟约为 12 个周期。

AMD Bulldozer-family CPUs 使用分离的 L1,每个簇(2 个核心)具有一个 16kiB 的 4 路组相联的 L1D。

Intel CPU 长时间保持 L1 不变(从 Pentium M 到 Haswell 到 Skylake,以及预计之后的许多代):分开的 32KB I 和 D 缓存,其中 L1D 为 8 路组相联。64 字节的缓存行匹配 DDR DRAM 的突发传输大小。加载使用延迟约为 4 个周期。

此外,请参阅 标签维基,以获取更多性能和微架构数据的链接。


1
是的,Valgrind会查询CPUID,如果识别出您的CPU,则使用该CPU的模型。 - Norman Ramsey
17
Intel L1缓存是8路组相联的。在Linux上,您可以从/sys/devices/system/cpu/cpu*/index*/cache中获取所有数字。此外,带有glibc的系统通常具有getconf(1),使用方式类似于getconf LEVEL1_DCACHE_ASSOC - Jed
很遗憾,Jed的解决方案不适用于ARM:在Linux中获取ARM处理器的缓存详细信息 - Brent Bradburn
@Jed 你们能否也看一下这个缓存问题?http://stackoverflow.com/questions/30555623/how-many-bits-are-in-the-address-field-for-a-directly-mapped-cache - committedandroider
在 MacOS 上,您也可以使用 sysctl -a | grep cache 命令来检查此信息。 - mvlabat
显示剩余3条评论

31
这本英特尔手册:Intel® 64和IA-32架构优化参考手册有一份不错的关于高速缓存考虑的讨论。

enter image description here

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

即使微软也意识到需要更多工具来监视缓存使用和性能,并且有一个GetLogicalProcessorInformation()函数的示例(...在创建荒谬的长函数名称方面开创了新的道路),我想我会编写。

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

如果有任何疑问,如何充分利用缓存是多么关键的话,Cliff Click(曾在Azul工作)的this presentation应该能够消除所有的疑虑。用他的话来说,“内存是新的磁盘!”。

Haswell’s URS (Unified Reservation Station)

更新 II:SkyLake显著提高了缓存性能规格。

SkyLake Cache Specifications


很好的发现,非常有帮助! - Brent Bradburn
@nobar,谢谢,我自己也正朝着那个方向前进,所以我想我不妨为你留下这辆出租车。 :) - user1899861
@RocketRoy,你能看一下这个缓存问题吗?http://stackoverflow.com/questions/30555623/how-many-bits-are-in-the-address-field-for-a-directly-mapped-cache - committedandroider

8
您正在查看消费者规格,而不是开发者规格。这里是您需要的文档。 缓存大小因处理器系列子型号而异,因此通常不包含在 IA-32 开发手册中,但您可以轻松地在 NewEgg 等网站上查找它们。 编辑: 更具体地说:第 3A 卷第 10 章(系统编程指南),优化参考手册第 7 章,以及可能在 TLB 页面缓存手册中有一些内容,尽管我会假设那个比您关心的 L1 更远。

我在这些手册中找不到真正的缓存数据。你能引用卷和页码吗? - Norman Ramsey
还有第3A卷的第10章,即系统编程指南。 - Not Sure
我找到了3A卷的10-1表。虽然它没有列出单个处理器,但它为各种处理器系列的缓存信息提供了详细信息(或至少是数字范围)。它仍然有点模糊(Core 2 Quad在L1方面没有明确列出),但这已经是一些进展了。谢谢! - Brent Bradburn
我原本希望使用[q9300 "L1 cache" site:intel.com]在Google上进行搜索,以便从“开发者规格”中获取处理器特定的数据。但是没有这样的运气。 - Brent Bradburn
你的Q9300处理器肯定有L1缓存 - 只需在谷歌上搜索“intel q9300 l1 cache”,你就可以从硬件评测网站上获取规格。我想不出任何一个没有L1和L2缓存的现代处理器 - 使用CPU-z或类似工具查找你机器上的缓存信息。 - Not Sure
显示剩余2条评论

8
我进行了更多的调查。苏黎世联邦理工学院有一个团队开发了一个内存性能评估工具,可以获取至少L1和L2缓存的大小(也可能包括关联性)的信息。该程序通过实验尝试不同的读取模式并测量结果吞吐量来工作。一种简化版本被用于Bryant和O'Hallaron所著的流行教材中。

我尝试了这些(而且我已经写了一个类似的程序)。结果表明,在我的Q9300上,32K和3M存在不连续的性能结果。感谢您的帮助! - Brent Bradburn

2

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

在Windows上,可以使用GetLogicalProcessorInformation获取一些缓存信息(大小、行大小、联想度等)。Win7上的Ex版本将提供更多数据,比如哪些核心共享哪些缓存。 CpuZ也提供此类信息。


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

2

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


1

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

缓存大小(字节)

=(路数+1)*(分区+1)*(行大小+1)*(集合+1)

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

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

提供头文件声明:

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
不需要用汇编语言写这个; 大多数编译器都有一个CPUID内在函数。就像使用GNU C的#include <cpuid.h>得到__get_cpuid一样。https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i386/cpuid.h - Peter Cordes

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