CPU Cache翻译

        CPU高速缓存[1]是由计算机的中央处理单元( CPU )用来降低从主存储器访问数据的平均成本(时间或能量)的硬件高速缓存。高速缓存是一种更小、更快的存储器,更靠近处理器核心,存储来自常用主存储器位置的数据拷贝。大多数CPU具有不同的独立高速缓存,包括指令和数据高速缓存,其中数据高速缓存通常被组织为更多高速缓存级别( L1、L2等)的层次结构。

        所有现代(快速) CPU (除了少数特殊例外,[2])都有多级CPU缓存。早期的CPU只有一级高速缓存,与后来的1级缓存不同,它没有被分成为L1d (用于数据)和L1i (用于指令)。目前所有的CPU都有一个分离的L1高速缓存,也有具有L2缓存的,对于更大的处理器,也有L3缓存的。L2缓存没有用于数据和用于指令之分,对于多核处理器,每一个核心(core)都有自己的L2换缓存。对于L3以及更高级别的缓存,他们既不分数据和指令,而且为多核处理器多个核心所共享。L4高速缓存目前并不常见,通常DRAM,而不是 SRAM ,位于单独的管芯或芯片上。从L1开始,L2和L3都是集成到芯片上,而L4不再继续走集成的方式。每一层次的缓存都变得更大,而且使用了不同的优化方式。

         其他的缓存也存在,例如 Transition Lookalike Buffer(TLB),但它是Memory Management Unit(MMU)的一部分。

         缓存的容量一般是4、8、16等KiB(L1、L2和L3)或MiB(容量大的L2和L3),但是IBM也有96KiB的L1缓存。

Overview

         当试图读取或写入主存储器中的某个位置时,处理器会检查该位置的数据是否已经在缓存中。如果是这样,处理器将从高速缓存中读取或写入高速缓存,而不是速度慢得多的主存储器。

        大多数现代PC和服务器CPU至少有三个独立的高速缓存:一个用于加速可执行指令提取的指令高速缓存,一个用于加速数据提取和存储的数据高速缓存,以及一个用于加速可执行指令和数据的虚拟到物理地址转换的转换后备缓冲器( TLB )。TLB可以用来访问指令和数据,或者可以提供单独的指令TLB ( ITLB )和数据TLB ( DTLB )。数据缓存通常被组织为更多缓存级别的层次结构(L1和L2等)。但是TLB是Memory Management Unit(MMU)的一部分,它不是CPU的缓存。

Cache Entries

        数据以固定大小的块(称为高速缓存线或高速缓存块)在存储器和高速缓存之间传输。当一条高速缓存块从内存复制到高速缓存中时,会创建一个高速缓存条目。缓存条目将包括复制的数据以及请求的内存位置(称为标签)。

        当处理器需要读取或写入主存储器(某个位置)时,它首先检查高速缓存中的相应条目。高速缓存检查所有的可能包含该内存地址的高速缓存块。如果处理器发现该内存位置在缓存中,就发生了一次cache hit。但是如果没有找到,就发生了一次cache miss。对于cache hit,处理器就会立刻在该缓存块中读取或者写入;对于cache miss,缓存就会创建新的条目并从主存中拷贝数据。

Polices

Replacement Polices

        在cache miss的时候,为了给新的缓存块腾出空间,缓存不得不删除旧的缓存块。它用来选择要删除的条目的启发式方法称为替换策略。任何替换策略的根本问题是,它必须预测将来最不可能使用哪个现有缓存条目。预测未来是困难的,因此在各种可用的替代政策中很难选择一种最佳的方案。一个流行的替换策略,最近最少使用( LRU ),替换最近访问最少的条目。

将一些内存区间标记为non-caching能够有效提高性能,因为这些内存区域很大概率不会再次访问。这就保证了缓存中存储一些不会再次访问的数据。

Write Polices

        如果数据被写入高速缓存,在某一时刻它也必须被写入主存储器,此写入的时间称为写入策略。在write-through高速缓存中,对高速缓存的每次写入都会导致对主存储器的写入。或者,在write-back或copy-back高速缓存中,写入不会立即镜像到主存储器,而是由高速缓存跟踪哪些位置已经被写入,将它们标记为dirty。只有当数据从高速缓存中被删除时,这些位置的数据才会被写回到主存储器中。因此在write-back缓存中一次read miss可能需要两次访问主存储器:一次将dirty数据写回主存,第二次重新读取主存的新的位置。并且,当访问主存一个位置,而这个位置还未映射到缓存中,这个时候write-back缓存将会回写同时删除这块缓存块,以释放缓存空间用于新的内存。

         还有中间政策。高速缓存可以是write-through,但是写入可以暂时保存在存储数据队列中,通常这样多个存储可以一起处理(这可以减少总线周转并提高总线利用率)。

       来自主存储器的高速缓存数据可能被其他实体(例如,使用直接存储器访问( DMA )的外围设备或多核处理器中的另一个核心)改变,在这种情况下,高速缓存中的副本可能会过时或陈旧。或者,当多处理器系统中的CPU更新高速缓存中的数据时,与其他CPU相关联的高速缓存中的数据副本就是过时的了。保持数据一致性的缓存管理器之间的通信协议称为缓存一致性协议。

Catch Performance

       最近,在内存性能和处理器性能之间的速度差距呈指数级增长的情况下,缓存性能测量变得非常重要。引入高速缓存是为了减小这种速度差距。因此,了解缓存在多大程度上能够弥合处理器和内存速度的差距变得非常重要,尤其是在高性能系统中。高速缓存命中率和高速缓存未命中率在决定这一性能方面起着重要作用。为了提高缓存性能,降低未命中率成为其他步骤中的必要步骤之一。减少对高速缓存的访问时间也会提高其性能。

CPU Stalls

       从内存中提取一条高速缓存块所花费的时间(由于高速缓存未命中而导致的读取延迟)很重要,因为CPU在等待高速缓存块时将会耗费很多时间。当CPU达到这种状态时,它被称为停滞(stall)。随着CPU与主存储器相比变得更快,由于高速缓存未命中导致的停顿会取代更多的潜在计算;现代CPU可以在从主存储器中提取一条高速缓存块所需的时间内执行数百条指令。

       已经有很多技术被开发出来使得CPU在stall时间内仍能够工作,包括无序执行,其中CPU (例如Pentium Pro和更高版本的英特尔设计)试图在等待缓存未命中数据的指令之后执行独立指令。许多处理器使用的另一项技术是同时多线程( SMT ),或英特尔术语“超线程( HT )”,它允许备用线程在第一个线程等待所需的CPU资源可用时使用CPU内核。

Cache Entry Structure

Cache row entries通常有以下结构:

      data block(cache line)包含实际从主存中复制过来的数据。tag包含实际的主存的地址(或部分地址),flag bits将会在下面讨论。

       缓存的容量为它能够容纳的主存数据的量。这个大小可以计算为存储在每个数据块中的字节数乘以存储在高速缓存中的块数。(tag、flag和error correction code bits不包括在容量中,虽然他们也影响缓存的物理容量。)

       一个有效的主存地址在缓存中被分为tag、index和block offset,如下:

       index说明数据被复制到哪一个cache row当中,index的长度为[log2(r)],r代表cache rows的数量。

        block offset是存储的数据在cache row上的偏移量。通常有效地址以字节为单位,所以block offset的长度为[log2(b)]位,b是每一个data block的数据量。tag包含地址的最高有效位,对照当前行(该行已被索引检索)进行检查,看看它是我们需要的还是另一个不相关的内存位置,碰巧与我们需要的索引位相同。tag 长度用位表示如下:

        一些作者将块偏移简称为“偏移”或“位移”。

Example

        最初的奔腾4处理器有一个大小为8kb的四路组关联L1数据高速缓存,有64字节的高速缓存块。因此,有8个KiB / 64 = 128个高速缓存块。集合的数量等于高速缓存块的数量除以关联方式的数量,这导致128 / 4 = 32个集合,因此2^{5}= 32个不同的索引。有 2^{6} = 64 可能的偏移量。由于 CPU 地址是32位宽, 这意味着标记字段的 32 - 5 - 6 = 21位。

Flag bits

        指令高速缓存每个高速缓存行条目只需要一个标志位:有效位。有效位指示缓存块是否已加载有效数据。上电时,硬件将所有缓存中的所有有效位设置为“无效”。一些系统还在其他时间将有效位设置为“无效”,例如当一个处理器的高速缓存中的多主总线窥探硬件听到来自其他处理器的地址广播时,并且意识到本地高速缓存中的某些数据块现在已经过时并且应该被标记为无效。

       数据高速缓存通常要求每个高速缓存块有两个标志位——valid bit和dirty bit。设置dirty位表示关联的高速缓存块自从主存储器读取以来已经改变(“脏”),这意味着处理器已经将数据写入该缓存块中,并且新值没有一直写回到到主存储器。

Associatity

       替换策略决定主存储器特定条目的副本在高速缓存中的位置。如果替换策略可以自由选择缓存中的任何条目来保存副本,则缓存被称为完全关联。在另一个极端,如果主存储器中的每个条目只能进入高速缓存中的一个位置,则高速缓存被直接映射。许多高速缓存实现了一种折衷,其中主存储器中的每个条目可以到达高速缓存中N个位置中的任何一个,并且被描述为N路集合关联。例如,AMD Athlon中的一级数据高速缓存是双向集合关联的,这意味着主存储器中的任何特定位置都可以高速缓存在Level 1数据高速缓存的两个位置中的任一个。

       选择正确的关联性值需要权衡。如果替换策略可能映射到十个位置,那么要检查主存中该位置是否在缓存中,必须搜索十个缓存条目。检查更多的地方需要更多的电力和芯片面积,并且可能需要更多的时间。另一方面,关联度越大的高速缓存丢失(cache miss)的次数越少(参见下面的冲突丢失),因此CPU从慢速主存储器中读取的时间就越少。一般的指导方针是,将关联性加倍,从直接映射到双向,或者从双向到四向,对提高命中率的影响与将缓存大小加倍差不多。然而,将关联性增加四倍以上并不能同样提高命中率,通常是出于其他原因(见下面的虚拟混叠)。一些CPU可以在低功耗状态下动态降低其缓存的关联性,这是一种节能措施。

      从简单到复杂的顺序:

      1.直接映射高速缓存——最佳情况下是好的,但最坏情况下是不稳定的

      2.双向关联高速缓存

      3.双向偏斜关联高速缓存

     4.四路关联高速缓存

     5.八路关联缓存,这是后续实现的常见选择

     6.12路关联缓存,类似于8路

     7.完全关联缓存–最佳未命中率,但仅适用于少量条目

Direct-mapped cache

        在这个高速缓存结构中,主存储器中的每个位置只能进入高速缓存中的一个条目。因此,直接映射缓存也可以称为“单向关联”缓存。它本身没有替换策略,因为没有选择删除哪个缓存条目的内容。这意味着,如果两个位置映射到同一个条目,它们可能会不断地相互碰撞。虽然比较简单,但直接映射缓存需要比关联缓存大得多,才能提供可比的性能,而且更不可预测。

Two-way set associative cache

        如果主内存中的每个位置都可以缓存在缓存中的两个位置中的任一个,那么一个逻辑问题是:这两个位置中的哪一个?最简单和最常用的方案,如上面的右图所示,是使用内存位置索引的最低有效位作为缓存的索引,并且每个索引有两个条目。这种方案的一个好处是,存储在高速缓存中的tag不必包括高速缓存索引指示的那部分主存储器地址。因为高速缓存tag具有较少的位,所以它们需要较少的晶体管,在处理器电路板或微处理器芯片上占用较少的空间,并且可以更快地读取和比较。LRU也特别简单,因为每对只需要存储一个位。

Speculative execution

        直接映射缓存的优点之一是它允许简单快速的推测。一旦内存地址被计算出来,可能在内存中有该内存副本对应的一个缓存索引也被获得。该高速缓存条目可以被读取,并且处理器可以在检查完tag实际上与请求的地址匹配之前继续处理该数据。

        让处理器在tag匹配完成之前使用缓存数据的想法也可以应用于关联缓存。tag的一个子集,称为hint,可以用来选择映射到请求地址的一个可能的缓存条目。然后,由hint选择的条目可以与检查完整tag并行使用。Hint技术在地址翻译的上下文中使用时效果最好,如下所述。

Two-way skewed associative cache

        已经提出了其他方案,例如倾斜高速缓存,其中0路的索引是直接的,如上所述,但是1路的索引是用散列函数形成的。一个好的散列函数具有这样的属性,即当与散列函数映射时,与直接映射冲突的地址倾向于不冲突。缺点是计算散列函数的额外延迟。此外,当需要加载新数据块并删除旧的数据块时,可能很难确定最近最少使用哪个数据块,因为新的数据块可能在不同路的不同的index发生冲突。非偏斜缓存的LRU的tracking通常是在每组的基础上完成的。尽管如此,与传统的集合关联缓存相比,偏斜关联缓存仍具有优势。

Pseudo-associative cache

        一个真正的集合关联高速缓存同时测试所有可能的方式,使用类似 content addressable memory。伪关联高速缓存一次一个地测试每种可能的方式。hash-rehash cache 和 column-associative cache是伪关联高速缓存的示例。

        在第一路测试中发现命中的常见情况下,伪关联高速缓存与直接映射高速缓存一样快,但冲突未命中率比直接映射高速缓存低得多,接近完全关联高速缓存的未命中率

Cache Miss

        高速缓存未命中是指试图在高速缓存中读取或写入一段数据失败,这导致主存储器访问延迟更长。有三种高速缓存未命中:指令读取未命中、数据读取未命中和数据写入未命中。

        来自指令未命中通常导致最大延迟,因为处理器(或至少执行线程)必须等待(暂停)直到指令从主存储器中取出。来自数据读取未命中通常导致较小的延迟,因为不依赖于高速缓存读取的指令可以被发出并继续执行,直到数据从主存储器返回,依赖于数据的指令可以继续执行。数据写入未命中通常导致最短的延迟,因为写入可以排队,并且对后续指令的执行没有什么限制;处理器可以继续,直到队列满为止。

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值