我已经了解了不同的缓存映射技术,如直接映射,关联映射和集合关联映射技术,还学习了权衡。但我很好奇现在在intel core i7或AMD处理器中使用了什么。以及这些技术是如何演变的。还有什么需要改进的地方?
答案 0 :(得分:18)
直接映射缓存基本上从未在现代高性能CPU中使用。对于相同大小的组关联高速缓存,命中率的巨大优势抵消了功率节省,而控制逻辑中的复杂性稍高。如今,晶体管预算非常庞大。
软件至少有一对彼此相距4k的倍数的阵列非常常见,这会在直接映射的高速缓存中产生冲突错失。 (如果一个循环需要一次遍历所有数组,那么调整具有多个数组的代码可能涉及使它们倾斜以减少冲突错失)
现代CPU速度非常快,DRAM延迟超过200个核心时钟周期,即使强大的乱序执行CPU在高速缓存未命中时也能很好地隐藏,这个数据太大了。
多级缓存是必不可少的(并且使用的是所有高性能CPU),以便为最热门的数据提供低延迟(~4个周期)/高吞吐量(例如up to 2 loads and 1 store per clock ,在L1D高速缓存和向量加载/存储执行单元之间具有128,256或甚至512位路径),同时仍然足够大以缓存合理大小的工作集。在物理上不可能构建一个非常大/非常快/高度关联的缓存,其执行与典型工作负载的当前多级缓存一样好;数据必须物理移动远的光速延迟是一个问题。电力成本也是令人望而却步的。 (事实上,功率/功率密度是现代CPU的主要限制因素,请参阅Modern Microprocessors: A 90-Minute Guide!。)
所有级别的缓存(uop缓存除外)都在我所知道的所有x86 CPU中进行物理索引/物理标记。大多数设计中的L1D高速缓存从页面偏移量下方获取其索引位,因此也是VIPT,允许TLB查找与标记获取并行发生,但没有任何混叠问题。因此,缓存不需要在上下文切换或任何事情上刷新。 (一般参见this answer for more about multi-level caches和VIPT速度技巧,以及一些实际x86 CPU的一些缓存参数。)
私有(每个核心)L1D / L1I和L2缓存是传统的组关联缓存,对于小/快速缓存通常是8路或4路。所有现代x86 CPU上的高速缓存行大小为64字节。回写数据高速缓存。 (在AMD Bulldozer系列中除外,其中L1D使用小型4kiB写入组合缓冲区进行直写。)
http://www.7-cpu.com/具有良好的缓存组织/延迟数,带宽和TLB组织/性能数,适用于各种微体系结构,包括许多x86,like Haswell。
" L0"英特尔Sandybridge系列中的解码uop缓存是集关联的,虚拟地解决了。最多3个块,最多6个uop可以缓存来自32字节机器代码块中的指令的解码结果。相关:Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPUs。 (uop缓存是x86的一大进步:x86指令是可变长度的,难以快速/并行解码,因此缓存内部解码结果以及机器代码(L1I $)具有显着的功率和吞吐量优势。仍然需要解码器,因为uop缓存不大;它在循环中最有效(包括中到大循环)。这避免了Pentium4错误(或基于当时的Transitor大小的限制)拥有弱解码器并依赖跟踪缓存。)
现代英特尔(和AMD,我认为)L3 aka LLC又名最后一级缓存使用索引函数,该函数不仅仅是一系列地址位。它是一个散列函数,可以更好地分配内容以减少来自固定步幅的冲突。 According to Intel my cache should be 24-way associative though its 12-way, how is that?
从Nehalem开始,英特尔使用大型包含共享L3缓存,用于过滤核心之间的一致性流量。即,当一个核读取另一个核的L1d中处于修改状态的数据时,L3标签说明哪个核,因此RFO(Read For Ownership)只能发送到该核,而不是广播。 How are the modern Intel CPU L3 caches organized?。包容性属性很重要,因为这意味着没有私有L2或L1缓存可以拥有缓存行的副本而不知道L3。如果它在专用缓存中处于“独占”或“修改”状态,则L3将具有该行的无效数据,但标记仍将说明哪个核心可能具有副本。绝对没有副本的核心不需要发送有关它的消息,从而节省核心和L3之间的内部链接的功率和带宽。有关英特尔" i7"的片上高速缓存一致性的更多详细信息,请参阅Why On-Chip Cache Coherence Is Here to Stay。 (即Nehalem和Sandybridge-family,它们是不同的体系结构,但使用相同的缓存层次结构)。
Core2Duo 拥有共享的最后一级缓存(L2),但在L2未命中时生成RFO(Read-For-Ownership)请求的速度很慢。因此,具有适合L1d的小缓冲区的核之间的带宽与具有不适合L2的大缓冲区(即DRAM速度)一样慢。当缓冲器适合L2但不适合L1d时,存在快速的大小范围,因为写入核心将其自己的数据驱逐到L2,其中其他核心的负载可以在不产生RFO请求的情况下命中。 (参见Ulrich Drepper的Figure 3.27: Core 2 Bandwidth with 2 Threads"每个程序员应该了解的关于记忆的内容"。(Full version here)。
Skylake-AVX512具有更大的每核L2(1MiB而不是256k),以及每个核更小的L3(LLC)切片。它不再具有包容性。它使用网状网络而不是环形总线将核心相互连接。请参阅this AnandTech article(但在其他网页上的微架构详细信息中有一些不准确之处,see the comment I left)。
来自Intel® Xeon® Processor Scalable Family Technical Overview
由于LLC的非包容性,LLC中缺少高速缓存行并不表示该行不存在于任何内核的私有高速缓存中。因此,当未在LLC中分配时,使用监听过滤器来跟踪核心的L1或MLC中的高速缓存行的位置。在上一代CPU上,共享LLC本身负责这项任务。
这个" snoop-filter"只有在它不能有假阴性的情况下才有用。将无效或RFO(MESI)发送给没有线路副本的核心是可以的。当另一个核心请求对其进行独占访问时,让核心保留一行副本是不行的。因此,它可能是一个包含标签的跟踪器,它知道哪些核心可能具有哪一行的副本,但不会缓存任何数据。
或者,在不严格包含所有L2 / L1标签的情况下,监听过滤器仍然可以使用。我不是多核/多插口侦听协议的专家。我认为同样的窥探过滤器也可以帮助过滤套接字之间的窥探请求。 (在Broadwell和早期,只有四插槽和更高的Xeon有一个用于核心间流量的监听过滤器; dual-socket-only Broadwell Xeon and earlier don't filter snoop requests between the two sockets。)
AMD Ryzen uses separate L3 caches for clusters of cores ,因此必须在L3中为每个群集复制多个核心共享的数据。同样重要的是,来自一个集群中的核心的写入需要更长时间才能对另一个集群中的核心可见,其中一致性请求必须通过集群之间的互连。 (类似于多插槽Intel系统中的插槽,每个CPU封装都有自己的L3。)
因此,这给了我们NUCA(非统一高速缓存访问),类似于在多插槽系统中获得的通常NUMA(非统一内存访问),其中每个处理器都内置了内存控制器,并且访问本地内存比访问连接到另一个套接字的内存要快。
最近的英特尔多插槽系统具有可配置的监听模式,因此从理论上讲,您可以调整NUMA机制,使其最适合您正在运行的工作负载。有关可用的监听模式的表格+说明,请参阅Intel's page about Broadwell-Xeon。
另一个进步/进化是an adaptive replacement policy in the L3 on IvyBridge and later。当某些数据具有时间局部性但工作集的其他部分更大时,这可以减少污染。 (即,使用标准LRU替换来循环一个巨大的阵列将驱逐一切,留下L3缓存只缓存来自阵列的数据,这些数据很快就会被再次触及。自适应替换试图缓解这个问题。)
进一步阅读: