VIPT缓存:TLB和高速缓存之间的连接?

7
我只是想澄清这个概念,并找到足够详细的答案,以便了解硬件中实际的工作原理。请提供任何相关细节。
在VIPT缓存的情况下,内存请求同时发送到TLB和Cache。
从TLB中获取翻译后的物理地址。 从缓存索引中获取标记列表(例如,来自属于集合的所有高速缓存行)。
然后将翻译的TLB地址与标记列表匹配,以查找候选项。
我的问题是这个检查在哪里进行?
在缓存中吗? 如果不在缓存中,还有别的地方吗?
如果检查在缓存中进行,那么
是否有一个旁路连接,从TLB到Cache模块,以获取用于与标记地址进行比较的翻译物理地址?
能否有人详细介绍一下常规实现方式及Cache模块与TLB(MMU)模块之间的连接?
我知道这取决于具体的架构和实现方式。 但是,在存在VIPT高速缓存时,您所知道的实现方式是什么?
谢谢。
1个回答

11
在这个详细级别上,你必须将“缓存”和“TLB”分解成它们的组成部分。它们在设计中紧密相连,使用了VIPT速度优化技巧,即并行进行标签提取的翻译(即利用所有索引位都在页面偏移之下,因此可以“免费”翻译)。相关链接:为什么大多数处理器的L1缓存大小小于L2缓存的大小? L1dTLB本身是一个小而快速的内容可寻址内存,例如,具有64个条目和4路组相联(Intel Skylake)。巨大页面通常使用第二个(和第三个)数组并行处理,例如,32个条目4路组用于2M页面,对于1G页面:4个条目完全(4路)相联。
但是现在,简化你的心智模型,暂时忘记巨大页面。L1dTLB是一个单一的CAM,检查它只需要进行一次查找操作。
"缓存"至少包括以下部分:
  • 存储标签+数据的SRAM阵列
  • 控制逻辑根据索引位提取一组数据+标签。(高性能L1d缓存通常与标签一起并行提取集合中所有路的数据,以减少命中延迟,而不是等待选择正确的标签,就像在更大、更高度关联的缓存中那样。)
  • 比较器用于将标签与翻译后的地址进行比较,并在其中之一匹配时选择正确的数据,或触发缺失处理。(在命中时,更新LRU位以标记此路作为最近使用)。有关不带TLB的2路关联缓存基本原理的图表,请参见https://courses.cs.washington.edu/courses/cse378/09wi/lectures/lec16.pdf#page=17。圆圈内的=表示比较器:如果标签宽度的输入相等,则产生布尔值为真的输出。
L1dTLB并不是与L1D缓存完全分离的。虽然我并不是硬件设计师,但我认为在现代高性能设计中,加载执行单元的工作原理大致如下
AGU从寄存器(s) + 位移生成地址。(如果非零,则包括段基址。)
(有趣的事实:Sandybridge系列在简单寻址模式下乐观地简化了这个过程:如果reg值与reg+disp在同一个4k页面中,则[reg + 0-2047]的负载使用延迟比其他寻址模式低1c。如果基址+偏移与基址不在同一页,是否会有惩罚?
索引位来自地址的页面内偏移部分,因此它们不需要从虚拟地址转换为物理地址。或者说转换是一个无操作。只要L1大小/关联度<=页面大小,这种VIPT速度与PIPT缓存的非别名性一起工作。例如,32kiB / 8路= 4k页面。
索引位选择一个组。对于该组的所有路,标签+数据并行获取。(这会消耗功耗以节省延迟,可能只对L1值得这样做。更高关联度(每组更多路)的L3缓存绝对不会这样做)
地址的高位在L1dTLB CAM阵列中查找。
标签比较器接收翻译后的物理地址标签和从该组获取的标签。
如果有标签匹配,缓存会从匹配的路中提取正确的字节(使用地址的行内偏移低位和操作数大小)。
或者,它可以利用之前的偏移位来仅获取每个路线中的一个(对齐的)字。没有高效的非对齐加载的CPU肯定是这样设计的。我不知道对于支持非对齐加载的CPU来说,这样做是否值得为了简单对齐加载而节省功耗。
但是现代的英特尔CPU(P6及更高版本)在不跨越缓存行边界的情况下,对于非对齐加载的uops没有惩罚,即使是32字节的向量。以字节为粒度进行8路并行索引可能比仅获取整个8 x 64字节并在获取+TLB发生时设置输出的多路复用更耗费资源,这取决于行内偏移、操作数大小和特殊属性(如零扩展或符号扩展,或广播加载)。因此,一旦标签比较完成,从所选路线获取的64字节数据可能会进入已经配置好的多路复用网络,该网络会抓取正确的字节并进行广播或符号扩展。
AVX512 CPU甚至可以进行64字节的完整行加载。
如果L1dTLB CAM中没有匹配项,整个缓存获取操作将无法继续进行。我不确定CPU是如何管理流水线的,以便在解决TLB缺失时可以继续执行其他加载操作;可能是执行单元在更新L1dTLB后重新执行加载或存储地址。这个过程涉及到检查L2TLB(Skylake:统一的1536个条目12路用于4k和2M,16个条目用于1G),如果失败,则进行页表遍历。
我假设TLB缺失会导致标签+数据获取被丢弃。一旦找到所需的转换,它们将被重新获取。在其他加载运行时,没有地方可以存放它们。
最简单的情况下,它可以重新运行整个操作(包括从L1dTLB获取翻译),当翻译准备好时,但它可以通过简化流程并直接使用翻译而不是将其放入L1dTLB并再次取出来来降低L2TLB命中的延迟。
显然,这要求dTLB和L1D真正地一起设计并紧密集成。由于它们只需要彼此通信,所以这是有道理的。硬件页表通过L1D缓存获取数据。(页表总是有已知的物理地址,以避免陷入困境/鸡生蛋问题)。
在Intel CPU上,装载uops显然在被分派到执行单元后立即离开调度器,因此它们不会从那里重播。也许装载执行单元或装载缓冲区条目会跟踪待处理的TLB缺失?装载缓冲区条目跟踪正在进行的缓存缺失,但在这种情况下,地址转换已经完成并且已知不会出错,它们只需要在数据到达时将数据转发给依赖的uops。

TLB和缓存之间是否有边带连接?

我不会称它为侧带连接。只有加载/存储地址生成单元(AGU)使用L1dTLB。同样,只有代码获取单元使用L1iTLB,它也读取L1i缓存。(页表遍历硬件也需要更新TLB条目,可能与加载或存储地址执行单元分开。TLB更新可以由硬件预取逻辑触发,以预取下一个虚拟页面的TLB条目。)
如果有第二级TLB,通常是统一的,所以如果L1iTLB和L1dTLB未命中,它们都会检查它。就像分离的L1I和L1D缓存通常在未命中时检查统一的L2缓存一样。
外部缓存(L2、L3)通常是PIPT(物理地址直接映射)。翻译发生在L1检查期间,因此物理地址可以发送到其他缓存。

注意:我不是真正的CPU架构师,所以我的理解可能有误。我的一些示例细节可能有误。但请参阅https://www.realworldtech.com/haswell-cpu/5/,并注意L1dTLB块附着在L1D块上,而不是像AGU-> L1D块那样通过箭头连接。David Kanter是CPU微架构分析师(他关于SnB、HSW和Bulldozer的文章非常好),这证实了我在这个答案中所说的话。 - Peter Cordes
1
在现代处理器中,所有的TLB和页行走器都有类似于L1D的MSHR。如果一个请求在TLB中未命中,则会被中止,并且需要该页表项的负载都会被阻塞在负载缓冲区中。稍后当TLB被填充时,这些负载将被唤醒并从负载缓冲区中重新播放。 - Hadi Brais
1
@HadiBrais:我正在研究非掩码加载。p05 ALU uop显然是用于掩码。请注意,Agner Fog的表格有两行:一行是无掩码(vmovdq[au]8/16/32/64 v,m的纯加载),另一行是有掩码(vmovdqu[au]8/16/32/64 v{k},m的1个微融合ALU+加载uop)。无论如何,在IACA输出中,您可以看到额外的uop是p05,而不是p23,因此它不是加载uop。 - Peter Cordes
1
@HadiBrais:不,Agner的表格显示两者。你有最新版本吗?在SKX表中有2个连续的行,分别为yz,mv{k},m - Peter Cordes
1
@HadiBrais:在AGU之后才能检测到分裂负载,这需要寄存器输入准备就绪(除非是绝对或RIP相对寻址模式)。在调度负载一次并发现它被分裂之后再分配第二个RS位置是没有意义的,因此我认为这是不可行的。我们已经知道分裂负载具有一半的吞吐量和更高的延迟。如何准确地基准测试x86_64上的非对齐访问速度。希望如果第一行在缓存中未命中,第二行仍然可以在它到达之前开始获取? - Peter Cordes
显示剩余16条评论

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