超标量处理器设计合集cache篇之提高cache的性能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

上一篇介绍了cache的基本原理,在真实世界的处理器中。会采用更复杂的方法来提高cache的性能。这些方法包括:写缓存(write buffer)、流水线(pipeline cache)、多级结构(multilevel cache)、victim cache 和预取(prefetching)等方法。对于乱序执行的超标量处理器来说,还有一些其他的方法来提高cache的性能,例如非阻塞cache、关键字优先和提前开始等方法。


一、写缓存

在处理器中,不管是执行load指令还是store指令,当D-cache发生缺失时,需要从下一级存储器中读取数据,并写道一个选定的cache line 中,考虑一般的下级存储器,例如L2 cache或是物理内存,一般只有一个读写端口,这就需要以上过程都是串行完成,也就是说,先要将脏状态的cache line 中的数据写回到下级存储器中,然后才能读取下级存储器得到缺失的数据,由于下级存储器的访问时间都比较长,这种串行的过程导致D-cache 发生缺失的处理时间变得很长,此时就可以采用写缓存来解决这个问题,脏状态的cache line 会首先放到写缓存中,等到下级存储器有空闲的时候,才会将写缓存中的数据写到下级缓存器中,这个过程如下图所示:
write buffer 的位置
加入写缓存之后,会增加系统设计的复杂度,写缓存相当于在L1 cache 到下级存储器之间的一个缓冲,通过它,向下级存储器中写数据的动作会被隐藏,从而可以提高处理器执行的效率,尤其对于写通类型的D-cache 来说,写缓存尤为重要。

二、流水线

对于读取D-cache 来说,由于Tag SRAM 和Data SRAM可以同时读取,所以当处理器的周期时间要求不是很严格时,可以在一个周期内完成读取操作;而对于写D-cache来说,情况就比较特殊了,读取Tag SRAM 和写Data SRAM 也只能串行完成,只有通过Tag 比较,确认要写的地址在cache 中之后,才可以写Data SRAM,在主频比较高的处理器中,这些操作很难在一个周期内完成,这就需要对D-cache 的写操作采用流水线的结构,流水线的划分有多种,比较典型的是将Tag SRAM 的读取和比较放在一个周期,写Data SRAM 放在下一个周期,这样对于一条store 指令来说,即使在D-cache hit时,最快也需要2周期才可以完成写操作。

需要注意的是:当执行load 指令时,它想要的数据可能正好在store指令的流水线寄存器中,而不是来自于Data SRAM,因此需要一种机制,能够检测到这种情况,这需要将load 指令所携带的地址和store指令的流水线寄存器进行比较,如果相等,那么就将store指令的数据作为load 指令的结果,对写D-cache使用流水线后,不仅增加了流水线本身的硬件,也带来了其他一些额外开销。

三、多级结构

为了能够使处理器“看起来”使用了一个容量大同时速度快的存储器,可以使用多级结构的cache,比如L1 cache,L2 cache ,DRAM。一般情况下,L1 cache 的容量很小,能够和处理器内核保持在同样的速度等级,L2 cache的访问通常需要消耗处理器的几个时钟周期,但是容量更大一些。在现代的处理器中,L1 cache 和L2 cache 都会和处理器放在同一个芯片内,一些比较高阶的处理器,例如面向处理器领域的处理器,还会有片上L3 cache。在处理器中,L2 cache 会使用写回(write back)的方式,但是对于L1 cache 来说,写通(Write through)的实现方式也是可以接受的,这样可以简化流水线的设计,尤其是便于在多核的环境下,管理存储器之间的一致性,因此一些处理器L1 cache都采用了写通的方式

对于多级结构的cache ,还需要了解两个概念inclusive 和exclusive。inclusive:如果L2 cache包括了L1 cache中的所有内容,则称L2 cache 是inclusive的;Exclusive:如果L2 cache 合入L1 cache的内容互不相同,则称L2 cache 是exclusive的。
inclusive 类型的cache是比较浪费硬件资源的,但是也是有优势的,首先将数据直接写到L1 cache中,虽然此时会将cache line中原来的数据覆盖了,但是在L2 cache中存有这个数据的备份,所以这样的覆盖不会引起任何问题(当然,被覆盖的line 不能是脏转态的);inclusive类型的cache也简化了一致性的管理,如果是inclusive类型的cache,那么只需要检查最低一级的cache即可,这样避免了对流水线的影响。如果采用exclusive类型的cache,很显然要检查所有的cache,这样会影响处理器的执行效率,同时,如果处理器要读取的数据不在L1 cache 中,而是在L2 cache中,那么将数据从L2 cache放到L1 cache的同时,也需要将L1 cache中被覆盖的line 写到L2 cache中,这种交换数据的过程很显然会降低处理器的效率,但是exclusive类型的cache 避免了硬件的浪费,尤其是当代的处理中,cache的容量的大小会直接影响处理器的性能,在同样的硅片面积下,exclusive类型的cache可以获得更多可用的容量,在一定程度上提高了处理器的性能,不过就目前来看,现代的大多数处理器都采用了inclusive类型的cache。

四、victim cache

有时,cache中被“踢出”的数据可能马上又要被使用,毕竟在cache中存储的是经常被使用的数据,例如,对于一个2路组相连(2-way set-associative)结构的D-cache来说,如果一个程序频繁地使用3个数据恰好都位于同一个cache set中,那么就会导致一个way中的数据经常被 “踢出”cache,然后又经常被写回cache。
图 4-1在两路组相连的cache中,频繁使用的三个数据位于同一个cache set 中
如图4-1,如果下次要访问数据C时,就会将数据A 从cache中踢出,将C写入;再访问数据A时,又会将数据B踢出,将A写入;然后再访问数据B时,又会将数据C踢出,将B写入…,这样会导致cache始终无法命中需要的数据,显然降低了处理器的执行效率,如果为此而增加cache 中way的个数,又会浪费掉大量的空间。因为其他的cache set未必有这样的特征,victim cache(VC)正是要解决该问题,它可以保存最近被踢出cache的数据,因此所有的cache set 都可以利用它来提高way的个数,通常victim cache 采用全相连(fully-associative)的方式,容量都比较小(一般可以存储4~16个数据),它在处理器的位置如图所示:
图4-2  victim cache所处的位置
victim cache 本质上相当于增加了cache中way的个数,能够避免多个数据竞争cache中有限的位置,从而降低cache的缺失率。一般情况下,cache和Victim cache 存在互斥的关系,也就是它们不会包含同样的数据,处理器内核可以同时读到它们,如果在cache中没有发现想要的数据,而在victim cache中找到了,那么只需要使用victim cache 中的数据即可,这样和
cache命中的效果是一样的。总体来看,使用victim cache可以减少cache的缺失率,从而提高处理器的性能。
还有一种和victim cache 类似的设计思路,称为filter cache,只不过它使用在cache “之前”,而victim cache使用在cache"之后"。当一个数据第一次被使用时,它并不会马上放到cache中,而是首先会被放到filter cache中,等到这个数据再次被使用时,它才会被搬移到cache中,这样做可以防止那些偶然被使用的数据占据cache,因为这样的数据在以后的时间并不会继续被使用,因此它最好不要放在cache中,使用filter cache 可以过滤掉这些偶然使用的数据,从而提高cache的利用率。设计思路如下:
图4-2  filter cache

五、预取

使用预取可以缓解cache 缺失中的compulsory 问题,其本质上也是一种预测技术,它猜测处理器在以后能使用什么指令或数据,然后将其放到cache中,这个过程可以使用硬件完成,也可以软件完成,最终目的都是一样的。

1、硬件预取

将预取的指令放到一个单独缓存中,如下图所示
图5-1 对指令采用硬件预取
当I-cache 发生缺失时,除了将需要的数据块从下级存储器取出来并放到I-cache中,还会将下一个数据块也读取出来,只不过它不会放到I-cache中,而是放到一个称为stream buffer的地方,在后续执行时,如果在I-cache中发生了缺失,但是在stream buffer 中找到了想要的指令,那么除了使用stream buffer中读取的指令外,还会将其中对应的数据块搬移到I-cache中,同时继续从L2 cache中读取下一个数据块放到stream buffer中,当程序没有遇到分支指令时,这种方法会一直工作,从而使I-cache的缺失率得到降低,当然,分支指令会导致stream buffer中的指令变得无效,此时的预取相当于做了无用功,浪费了总线带宽和功耗,事实上,使用预取的方法是一把双刃剑,它可能会减少cache的缺失率,也可能由于错误的预取而浪费功耗和性能,这种情况对于数据的预取尤为明显,需要 在设计时进行权衡。

数据的预取和指令有所不同,一般情况下,当访问D-cache发生缺失时,除了将所需要的数据块从下级存储器取出来之外,还会将下一个数据块也读出来,但是这种方法不总是有效。有些处理器采取了更激进的方法实现数据的预取,提前预取多个数据块,这种预取方法是比较激进的,对于一些程序,可能会大幅度提高执行速度,但是也有可能对一些其他的程序带来负面影响,毕竟这种方法只是一种猜测,而且这些预取来的数据需要替换掉D-cache中一些可能在以后使用的数据,因此这种方法也要视具体情况而言。

2、软件预取

使用硬件进行数据的预取,很难得到满意的结果,其实,在程序的编译阶段,编译器就可以对程序进行分析,进而知道哪些数据是需要进行预取的,如果在指令集中设有预取指令,那么编译器就可以直接控制程序进行预取,此时的预取就比较有针对性了。但是,这种软件预取的方法有一个前提,那就是预取的时机,如果预取时间太早,那就可能踢掉D-cache中一些本来就有的数据,造成cache的“污染”。要选择一个合适的时机进行预取,还需要注意的是,使用软件预取的方法,当执行预取指令时,处理器需要能够继续执行,也就是继续能够从D-cache中读取数据,而不能够让预取指令阻碍了后面指令的执行,这就要求D-cache是非阻塞结构的。
在实现了虚拟存储器的系统中,预取指令有可能会引起一些异常,例如发生page fault、虚拟地址错误或者保护违例等。此时有两种选择,如果对这些异常进行处理,就称这种预取指令为处理错误的预取指令,反之,如果不对这些异常进行处理并抛弃掉这条预取指令,就称这种预取指令为不处理错误的预取指令,此时发生异常的预取指令就会变成一条空指令,这种方法符合预取指令的定位,使预取指令“悄无声息”执行。

总结

提示:这里对文章进行总结:
目前对于cache的性能提升主要使用的方法包括写缓存、流水线、多级结构、预取和采用victim cacche 的方式,每种方法都有其优劣势和应用场景,具体如下:
提高cachex性能的方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
超标处理器设计》讲述超标(SuperScalar)处理器设计,现代的高性能处理器都采用了超标结构,大至服务器和高性能PC的处理器,小至平板电脑和智能手机的处理器,无一例外。《超标处理器设计》以超标处理器的流水线为主线展开内容介绍。《超标处理器设计》主要内容包括超标处理器的背景知识、流水线、顺序执行和乱序执行两种方式的特点;Cache的一般性原理、提高Cache性能的方法以及超标处理器中的Cache,尤其是多端口的Cache;虚拟存储器的基础知识、页表、TLB和Cache加入流水线后的工作流程;分支预测的一般性原理、在超标处理器中使用分支预测时遇到的问题和解决方法以及如何在分支预测失败时对处理器的状态进行恢复;一般的RISC指令集体系的简单介绍;指令解码的过程,尤其是超标处理器中的指令解码;寄存器重命名的一般性原理、重命名的方式、超标处理器中使用寄存器重命名时遇到的问题和解决方法以及如何对寄存器重命名的过程实现状态恢复;指令的分发(Dispatch)和发射(Issue)、发射过程中的流水线、选择电路和唤醒电路的实现过程;处理器中使用的基本运算单元、旁路网络、Cluster结构以及如何对Load/Store指令的执行过程进行加速;重排序缓存(ROB)、处理器状态的管理以及超标处理器中对异常的处理过程;经典的Alpha21264处理器的介绍。在本书中使用了一些现实世界的超标处理器作为例子,以便于读者加深对超标处理器的理解和认识。 《超标处理器设计》可用作高等院校电子及计算机专业研究生和高年级本科生教材,也可供自学者阅读。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值