各位书友大家好,欢迎做客我的栏目!
在前几期内容中,我们已经深入探讨了存储器层级结构的核心概念、设计目标与实现策略,也系统梳理了六种基础的性能优化方式。
而今天,我们将继续以量化公式为核心工具,带大家走进存储器层次结构性能优化的进阶领域,聊聊那些更具深度的高级策略。
目录
实现缓存访问流水化:提高时钟频率,提高缓存带宽,增加分支代价,增加流水线停顿
导图
小而简单的第一级缓存:缩短命中时间,降低功率,增大缺失率
图1 缓存大小&相联度与命中时间的关系
根据“在给定实现技术和功率预算的情况下,硬件越小,速度可以越快”原则可知,小型化的高速缓存可以获得更低的命中时间。同时处理器核心越来越高的时钟频率也正需要第一级高速缓存能够跟上它的速度。
小型化高速缓存包含两方面:容量小+低相联度。我们在本系列<六大基础策略,让你的系统跑更快>中已经了解到两者对于命中时间、缺失率和功耗的影响。
小型化缓存有利于命中时间和功耗,但不利于缺失率,因此设计时需要结合应用场景建模评估和权衡。比如随着程序规模和数据集规模增大,缓存竞争加剧,倾向于降低缓存缺失率可能更有利于降低存储器平均访问时间。
如今处理器芯片中的第一级缓存会采用较高的相联度,是考虑到:
①高端处理器时钟频率较低,SRAM类型的缓存吃掉了时钟周期的大部分,所以常需要流水化访问(至少需要两个时钟周期的访问时间),因此命中时间此时的影响降低,所需命中时间可以分摊在多级流水内而无需降低处理器核时钟频率。
②虚拟地址索引物理地址标签(VIPT)的高速缓存将缓存容量限制为页大小与相联度的乘积(具体原因我们放在虚拟存储部分细聊),因此在缓存组数受限情况下只能通过提高相联度来提高缓存容量并降低缺失率。
③处理器核在支持多线程后,所需覆盖的数据集规模增大,冲突缺失增加,因此提高相联度更具吸引力
路预测:缩短命中时间
图2 路预测优化技术
一种可以减少冲突缺失,同时又能保持直接映射缓存命中速度的方法。
路预测技术中通过在缓存中另外保存一些控制位,用于预测下一次可能访问的路。预测控制位的目的是尽早设定多路选择器,降低传统组相联缓存中缓存标签访问+标签比较+多路选择器路由合适数据的串行时间。
支持路预测技术后,关键路径变为路预测位访问+多路选择器路由合适数据,虽然仍高于直接映射的命中时间,但也是很大的改善。缓存标签访问和比较与关键路径并行执行,以最终确认预测是否正确,以及缓存是否缺失。
为了降低路预测位访问时间,可以使用独立的小型存储单元保存路预测位,称之为独立预测表;也可以与处理器中的分支预测器共享一部分存储。
如果预测控制位预测正确,则缓存命中时间就等于这一快速命中时间,数据直接传递给后续流水线使用。
如果预测失败,则需要读取标签匹配的路,同时更新预测控制位以提高后续预测准确性,这通常会导致访问延迟增加一个周期(在流水线内引入额外气泡)。如果检查出缺失则需要取消掉预测位读出的结果。
常使用动态更新机制维护预测位的准确性,常见的策略包括:基于历史的更新和基于统计的更新。基于历史的更新是指使用简单的历史记录(比如上一次访问的命中历史)更新预测位,基于统计的更新是根据每个路径的命中频率调整预测位。
模拟表明,对于一个两路组相联缓存,路预测的准确率超过90%;对于一个四路组相联缓存,路预测的准确率超过80%。
图3 路选择优化技术
另一种扩展形式是路选择,区别在于它仅会读取预测位指向的数据缓存块。
如果预测成功,将缩短命中时间且节省功率。
如果预测失败,则需要重新读取缓存,这将显著增加命中时间,并且不利于流水化访问实现。该优化方法在低功率处理器中非常受用,也可能会提升能耗效率。
图4 路选择功耗
路选择技术对功耗的影响严重依赖于预测的准确率。随着相联度的提升,预测的准确率会明显降低。
实现缓存访问流水化:提高时钟频率,提高缓存带宽,增加分支代价,增加流水线停顿
图5 访存流水化
将访问延迟分散到多个时钟周期,缩短处理器核时钟频率,提高缓存带宽,但会增加命中时间(因为流水线寄存器需要消耗额外的时间)。
缓存访问流水线的缺点是由于流水线级数增加,指令缓存访问流水化将增大分支预测错误的代价。同时数据缓存流水化导致载入指令的执行延迟变长,处理器流水线需要更多的可重叠执行指令掩盖访问延迟,这也许会增加流水线停顿。
多组缓存(Multibanked):提高缓存带宽,降低功率
图6 多组缓存
对于统一高速缓存,提高带宽意味着增加访问端口。高速缓存每多出一个端口就意味着额外的解码器、子行连线、位行连线、传感放大器和多路选择器。总之,面积和功耗膨胀得很快。
另一种解决高带宽的思路是采用分立高速缓存,将不同内容划分到不同的高速缓存中,比如分立的指令和数据缓存。
该思想的进一步延伸是将缓存划分为相互独立,支持同时访问的缓存组(cache bank)。常用的策略是将高速缓存按照不同的地址以交替的形式进行划分组,每个缓存组采用小型单端口的实现方式降低访问延迟。对不同bank的多个访问可以并行执行,而对同一bank的多个访问将会导致冲突。
多组缓存技术该可以降低访问功耗,因为仅需要访问某一小型缓存组。
L1高速缓存使用multi-bank优化策略主要倾向于增加访问带宽,因为目前超标量处理器支持每周期超过一次的存储器引用。而L2和L3高速缓存则不仅仅是增加缓存带宽,为了支持无阻塞缓存同时处理多个缺失请求;也倾向于降低功耗,因为两者的缓存容量更大。
非阻塞缓存:提高缓存带宽,降低实际缺失代价
非阻塞缓存允许缓存在缺失期间继续提供缓存命中服务,即处理器核在等待高速缓存返回缺失数据期间可以继续从缓存中提取别的数据,减少处理器核流水线停顿,称之为“hit under miss”。
非阻塞缓存还允许重叠多个缺失的处理,即高速缓存同时处理多个缺失请求时仍可以提供命中服务,减少缺失代价,称之为"miss under miss"或"hit under multi-miss"。
无阻塞缓存策略实现
图7 非阻塞缓存
为了支持上述功能,高速缓存引入缓存缺失状态保持寄存器(Miss Status Handling Register, MSHR)硬件,内容包括:缺失块映射到缓存中的位置、缺失状态的一些控制位,以及导致缺失指令的信息。
当存储访问出现缓存缺失时,会分配一个MSHR表项用于记录缺失状态,同时MSHR负责后台处理缺失请求并允许释放缓存以服务新的访问。当缓存缺失块返回时,数据写入缓存和目的寄存器后,相应的MSHR表项被释放。
MSHR表项数量会影响非阻塞缓存技术能够提供的并行度,在设计MSHR数量时需要考虑:处理器一个时钟周期内可以执行的指令数、访问外层存储层次的延迟和带宽,以及内层存储层次访问过滤的能力。
考虑如下处理器架构:处理器核IPC=4,程序中访存指令占据25%;L1缓存块大小为64B,缺失率为10%;L2缓存块大小为128B,带宽为32B/cycle,访问延迟为10cycles,缺失率为20%;内存带宽为32B/cycle,访问延迟为100cycles。
可以算出平均每个周期需要发出的L1缓存缺失请求为4*25%*10% = 0.1.
L1缓存缺失造成的额外平均访问时间为(10+2) + (100+4)*10%*20% = 14.08.
图8 MSHR数量评估
这代表每个时钟周期需要分配0.1个MSHR表项,即每隔10个周期分配一个MSHR表项,并且每隔14.08时钟周期才会释放一个MSHR表项。
由于访问低级存储通常流水化实现,因此仅第一次访问延迟期间会累计缺失请求,待第一个缺失请求返回后续整个通路会流水起来。因此该例子下MSHR深度需要0.1*14.08再上取整为2。
由于仅计算平均值无法有效处理短期波动场景,可以将访存指令占比改为100%进行计算,则结果乘4为8深度。
在增加MSHR深度的同时也就意味着支持更多的并行缺失请求,由于缓存资源有限,因此出现冲突的概率会上升。冲突是指命中和缺失返回之间竞争缓存资源的现象。
常使用的解决策略是优先处理命中请求(即缓存读请求优先),因为关乎于流水线顺畅;缺失返回之间可按等待时间排序。
缺失返回之间发生冲突是由于缺失请求之间往往是不保序的,比如一些缺失请求命中了低层次的缓存,而另一些缺失请求只能去访问内存,再比如非一致存储/分布式共享存储体系结构中远端存储的访问延迟较大。
这也说明MSHR无法根据缺失请求的返回顺序判断是谁发出的请求,通常都会使用MSHR编号标记缺失请求,后续请求返回时使用携带的编号信息进行判断。
非阻塞缓存策略潜在问题
非阻塞缓存技术会使平均存储器访问时间的评估变得困难,因为缺失不一定会造成处理器停顿,所以很难评估缺失代价。实际的缺失代价应该等于处理器的非重叠停顿时间,即真正由于缓存无法提供服务而导致处理器停顿的时间。
非阻塞缓存的另一个缺点是某些应用可能无法发挥出它的价值,比如程序真相关性较多无法开发出能够掩盖访存延迟的并行指令。
关键字优化和提前重启动:降低缺失代价
图9 关键字优化和提前重启
处理器核某一时刻通常仅需要缓存块中的一个字,因此无需等待整个块都被载入,一旦载入被请求字后,立即将其发送至处理器核。
该思想可细分为两种策略:关键字优化(Critical word first)和提前重启动(Early restart)。
关键字优先策略是指:首先从存储器中请求缺失的字(比如AXI WRAP访问类型),在其到达缓存之后立即发给处理器,使缓存块中其他字的载入和处理器核并行执行。
提前重启动策略是指:以正常顺序提取字(比如AXI INCR访问类型),但只要块中的被请求字到达缓存,就立即将其发送给处理器核。
该方案的缺点和非阻塞缓存一致,会使平均存储器访问时间的评估变得困难。在载入某个块中的剩余字过程中,处理器核访问剩余字并发生缺失,此时实际的缺失代价会降低。
当缓存块很小时,该方案收益较低,因为可重叠的缺失代价很小。
合并写缓冲区:提升存储访问效率,降低缺失代价
高速缓存中的写缓冲(Write Buffer)主要用于解决将数据写入到低级存储器时速度过慢的问题。写缓冲是一个速度非常快的临时缓存区,处理器核或高级缓存控制器将数据写入缓冲后就可以继续执行其他任务,而写缓冲会在后台处理这些请求。
图10 合并写缓冲区
合并写缓存冲区是指:新的写入请求需要检查写缓冲中其余有效表项的数据地址,看看它们之间是否存在匹配关系。如果匹配,则将新写入请求中的写数据与某个有效表项进行合并。
合并写缓冲区有利于提高写低级存储器的效率。假设处理器核的访存数据宽度是4B,如果与处理器核交互的写缓冲区表项设计为可以容纳4B写数据,则对于16B的数据块需要发送四次写请求。
如果写缓冲区的表项可以容纳16B的写数据,在进行3次合并写缓冲区后仅需一次写请求。由于处理器核外的数据总线宽度可能更宽,所以合并写缓冲区方案可以充分开发带宽且请求次数更少。
合并写缓冲区还会减少因为缓存区已满而导致的流水线停顿,进而降低缺失代价。
需要注意的是,如果访问的是I/O地址空间,则不允许进行合并写缓冲区操作。因为I/O地址空间默认访问存在副作用,并且对操作时序有严格要求。比如向打印机的I/O地址写入数据会触发打印机打印操作,该过程不仅仅是简单的数据传输,而需要按照特定的顺序写入控制命令。合并写缓冲区操作可能会改变写入的顺序和时间,可能导致I/O设备无法正确响应。
感谢您的阅读和陪伴,本文对计算机存储器层次结构性能的高级优化策略进行了全面介绍,希望对您有帮助。欢迎在留言区发表您的意见和看法,同时欢迎您加入我们的讨论,共同交流想法。
关注我 每周日做知识分享
微信公众号(欢迎关注):我想成为大佬