如果有可能,我愿意放弃使用Write操作,Write操作不是在进行单纯地进行写,而是将Read建立的千辛万苦异常小心地毁于一旦,是Cache Hierarchy设计苦难的发源地。没有写操作在Cache Block中就不会有这么多状态,更没有复杂的Memory Consistency模型。

很多人都不喜欢写操作,这并不能阻挡它的真实存在。绝大多数人痛恨写操作,也不愿意去研究如何提高写操作的效率,写虽然非常讨厌,但是很少在速度上拖累大家,只是写太快了,带来了许多副作用经常影响大家。不允许写操作使用Cache貌似是个方法,却几乎没有程序员能够做到这一点。过分的限制写操作也并非良策,凡事总有适度。

这使得在CacheHierarchy设计中读写操作得到了区别对待。读的资质差了一些,有很多问题亟待解决,最Critical的是如何提高Load-Use Latency;对于写,只要不给大家添乱就已经足够,Cache Bus的Bandwidth能少用点就少用点,能降低一点Bus Traffic就算一点,实在不能少用,就趁着别人不用的时候再用。从总线带宽的角度上看,Load比Store重要一些,在进行Cache优化时,更多的人关心读的效率。

在一个程序的执行过程中不可能不使用Write操作。如何在保证Memory Consistency的前提下,有效降低Write操作对Performance的影响,如何减少Write Traffic,是设计的重中之重。在一个处理器系统中,Write操作需要分两种情况分别讨论,一个是Write Hit,另一个是Write Miss。Write Hit指在一次Write操作在进行Probe的过程中在当前CMP的Cache Hierarchy中命中,而Write Miss指没有命中。

我们首先讨论WriteHit,从直觉上看Write Hit相对较为容易,与此相关的有些概念几乎是常识。Write Hit时常用的处理方法有两种,一个是Write Through,另一个是Write Back[1]。相信绝大部分读者都明白这两种方法。Write Through方法指进行写操作时,数据同时进入当前Cache,和其下的一级Cache或者是主存储器;Write Back方法指进行写操作时,数据将直接写入当前Cache,而不会继续传递,当发生Cache Block Replace时,被改写的数据才会更新到其下的Cache或者主存储器中。

很多人认为Write-Back在降低Write Traffic上优于Write-Though策略,只是Write-Back的实现难于Write-Though,所以有些低端处理器使用了Write-Though策略,多数高端处理器采用Write-Back策略。

这种说法可能并不完全正确,也必将引发无尽的讨论。在没有拿到一个微架构的全部设计,在没有对这个微架构进行系统研究与分析之前,并不能得出其应该选用Write-Through或者是Write-Back策略的结论。即便拿到了所有资料,进行了较为系统的Qualitative Research和Quantitative Analysis之后,你也很难得出有说服力的结论。

在目前已知的高端处理器中,SUN的Niagara和Niagara 2微架构的L1 Cache使用Write-Through策略[81],AMD最新的Bulldozer微架构也在L1 Cache中使用Write-Through策略[74]。Intel的Nehalem和Sandy Bridge微架构使用Write-Back策略。Write-Through和Write-Back策略各有其优点和不足,孰优孰劣很难说清。

Norman P.Jouppi列举了Write-Through策略的3大优点,一是有利于提高CPU Core至L1 Cache的总线带宽;二是Store操作可以集成在指令流水线中;三是Error-Tolerance [97]。这篇文章发表与1993年,但是绝大部分知识依然是Cache Write Policies的基础,值得借鉴。

其中前两条优点针对DirectMapped方式,非本节的重点,读者可参考[97]获得细节。制约Cache容量进一步增大的原因除了成本之外,还有Hit Time。如上文已经讨论过的,随着Cache容量的增加,Hit Time也随之增大。而Cache很难做到相对较大,这使得选择Direct Mapped方式时需要挑战John和David的2:1 Cache Rule of Thumb,目前在多处处理器系统中都不在使用Direct Mapped方式。

对这些Rule ofThumb的挑战都非一蹴而就。在某方面技术取得变革时,首先要Challenge的恰是之前的Rule of Thumb。善战者择时而动,而善战者只能攻城掠地,建立一个与旧世界类同的新世界,不会带来真正的改变。

革新者远在星辰之外,经得住大悲大喜,大耻大辱,忍受得住Stay Hungry Stay Foolish所带来的孤单寂寞。是几千年前孟子说过的“富贵不能淫,贫贱不能移,威武不能屈。居天下之广居,立天下之正位,行天下之大道。得志,与民由之,不得志,独行其道”。几千年祖辈的箴言真正习得是西方世界。

忽略以上这段文字。我们继续讨论Norman P.Jouppi提及的使用Write-Through策略的第三个优点,Error-Tolerance。CMOS工艺在不断接近着物理极限,进一步缩短了门级延时,也增加了晶体管的集成度,使得原本偶尔出现的Hard Failures和Soft Errors变得更加濒繁。这一切影响了SRAM Cells的稳定性,导致在基于SRAM Cells的Cache Memory中,Hard和Soft Defects不容忽视。

采用Write-Back策略的Cache很难继续忍受Single Bit的Defects,被迫加入复杂的ECC校验;使用Write-Though策略,Cache因为仍有数据副本的存在只需加入Parity Bit。与ECC相比,Parity Bit所带来的Overhead较小。这不是采用ECC校验的全部问题,在一个设计中,为了减少Overhead,需要至少每32位或者更多位的参与产生一次ECC结果。这些Overhead的减少不利于实现Byte,Word的Store操作,因为在进行这些操作时,需要首先需要读取32位数据和ECC校验,之后再Merge and Write新的数据并写入新的ECC校验值。

除此之外使用Write-Though策略可以极大降低Cache Coherence的实现难度,没有Dirty位使得多数设计更为流畅。但是你很难设想在一个ccNUMA处理器系统中,Cache的所有层次结构都使用Write-Though策略。由此带来的各类Bus Traffic将何等壮观。

采用Write-Though策略最大的缺点是给其他Cache层次带来的Write Traffic,而这恰恰是在一个Cache Hierarchy设计过程中,要努力避免的。为了降低这些Write Traffic,几乎所有采用Write-Though策略的高端处理器都使用了WCC(Write Coalescing Cache)或者其他类型的Store-Though Queue,本节仅关注WCC。

假设一个微架构的L1Cache采用Write-Through方式。WCC的作用是缓冲或者Coalescing来自L1 Cache的Store操作,以减少对L2 Cache的Write Traffic。在使用WCC时,来自L1 Cache的Store操作将首先检查WCC中是否含有与其地址相同的Entry,如果有则将数据与此Entry中的数据进行Coalescing;如果没有Store结果将存入WCC的空闲Entry中;如果WCC中没有空闲Entry则进行Write Through操作。WCC的大小决定了Write Traffic减少的程度。WCC的引入也带来了一系列Memory Consistency问题。

采用Write-Back策略增加了Cache Coherency设计难度,也有效降低了Write Traffic,避免了一系列Write-Through所带来的问题。下文以GEM5中的MOESI_CMP_directory为例简要Write-Back策略的实现方法。

如果WriteHit的Cache Block处于Exclusive[2]状态时,数据可以直接写入,并通知CPU Core Write操作完成。Write Hit的Cache Block处于Shared或者Owner状态时的处理较为复杂。即便是采用Write-Through策略,这种情况的处理依然较为复杂,只是Cache间的状态转换依然简单很多。本节仅介绍命中了Shared状态这种情况。

在L1Cache层面,这个Write Hit命中的Cache Block,其状态将会从S状态迁移到MM_W状态,之后经过一段延时迁移到MM状态。在MOESI_CMP_directory Protocol中,如果L2 Cache Block的状态为ILS,ILO,ILOS,SLS,OLS和OLSX时,L1 Cache中必定含有对应的状态为S的Block。由于Accidentally Inclusive的原因,L1 Cache Block多数时候在L2 Cache中具有副本,因此必须要考虑L1 Cache Block进行状态迁移时对L2 Cache Controller的影响。不仅如此还需要考虑CMP间Cache Coherency使用的Directory。

我们首先考虑L1 CacheBlock的从S开始的状态迁移过程。当CPU Core的Cache Hit到某个状态位S的L1 Cache Block后便开始了一次长途旅行。在这个Clock Block的S状态将经由SM,OM,最终到达MM_W和MM状态,如图4‑15所示。

CPU Core进行Store操作,Cache Hit一个状态为S的Block时,首先迁移到SM状态,之后在收到Data或者Exclusive Data之后进入到OM状态,OM状态到MM_W状态的迁移过程与图4‑14的过程类似。本节重点关注b_issueGETX请求,这个请求被称为Read for Exclusive。

在一个ccNUMA处理器系统中,b_issueGETX请求虽然复杂依然有机可循,首先在Intra-CMP中尝试并获得对访问Cache Block的Exclusive权限。如果没有获得Exclusive权限,则将这个请求转发给Directory Controller,并由Home Agent/Node经由CMP间的互联网络发送给其他CMP直到获得Exclusive权限。

在MOESI_CMP_directoryProtocol中,Cache Block的状态为S表示在当前ccNUMA处理器系统中至少还存在一个数据副本,因此b_issueGETX请求将首先在Intra-CMP中进行,并通过requestIntraChipL1Network_out发送至L2 Cache Controller。

L2 CacheController通过L1requestNetwork_in获得b_issueGETX请求,如果在L2 Cache中包含访问的数据副本,b_issueGETX请求将转换为L1_GETX请求。在L2 Cache中包含L1 Cache Block为S状态数据副本的情况有很多,还有一些L2 Cache Block包含数据副本,但是在当前CMP中其他L1 Cache中也包含数据副本的情况。这些状态转移的复杂程度如果我能够用语言简单描述,就不会有SLICC这种专用语言的存在价值。

如果在Intra-CMP中可以处理b_issueGETX请求,并不算太复杂,如果不能,而且L2 Cache Block的状态为SLS时,需要进一步做Inter-CMP Coherence的处理,此时b_issueGETX请求将转换为a_issueGETX,并通过globalRequestNetwork_out继续发送至Directory Controller。此时Directory Controller通过requestQueue_in获得该请求,并将其转换为GETX请求。Directory中具有4个Stable状态M,O,S和I,不同的状态对于GETX请求的处理不尽相同。

如果处于O状态,此时Intra-CMP为该Cache Block的Owner,此时仅需要向其他Inter-CMP发送g_sendInvalidations请求,并可将Exclusive_Data转发至上层,L1 Cache Block的状态也因此迁移为OM。

如果在Directory中没有记录哪些CMP中具有状态为S的数据拷贝时,g_sendInvalidations请求将广播到所有参与Cache Coherence的CMP处理器中,这种方式带来的Bus Traffic非常严重,也是这个原因在Directory中多设置了Bit Vectors,用来记录哪些CMP中具有状态为S的数据副本。

在这种情况下g_sendInvalidations请求仅需发送到指定的CMP,而不需要进行广播。因为Memory Consistence的原因,发起请求的CMP必须要等待这些指定的CMP返回所有的ACK后,才能进一步完成CPU Core的Store操作。除了在Directory中设置了Bit Vectors之外,Intel的MESIF中的F状态也可以在某种程度上避免因为过多的ACK带来的Bus Traffic。

通常情况在CMP间的连接拓扑不会使用Share Bus方式,对于Request/ACK这种数据请求模式,采用Share Bus方式最大的好处是具有一个天然的全局同步点,这个同步点在严重影响了总线带宽的前提下,极大了降低了设计难度。

采用ShareBus方式时,随着总线上节点数目的增加,冲突的概率也以O(N!)级别的算法复杂度进一步增长。这使得一个可用的CMP间的互联方式极少采用Share-Bus方式。采用其他方式,无论是Ring-Bus或者更加复杂的拓扑结构,都会涉及到多个数据通路,这使得从这些CMP返回的ACK并没有什么顺序,Home Agent/Node不能接收到一个ACK就向上转发一次,而是收集后统一转发。

当L1 CacheBlock收到All_acks后,将从OM状态转移为MM_W状态,完成最后的操作,其过程与图4‑14所示相同。为简略起见,本节不再介绍在Directory中是M,S和I状态的情况。而专注与Write Miss的处理。

Norman P.Jouppi从两个方面讨论Write Miss的处理策略。首先是否为每一个Miss的请求重新准备一个Cache Block,因此产生了两种方法,Write-Allocate或者No-Write Allocate。如果使用Write-Allocate方法,Cache Controller为Miss请求在当前Cache中分配一个新的Cache Block,否则不进行分配;

其次是否需要从底层Cache中获取数据,因此产生了两种处理方法,Fetch-on-Write或者No-Fetch-on-Write方法,如果采用Fetch-on-Write方法,Cache Controller将从其下Cache层次结构中Fetch已经写入的数据,并进行Merge操作后统一的进行写操作,否则不进行Fetch。还有一种方法是Write-Before-Hit,这种实现方法多出现在Direct Mapped Write Through Cache中,本节对此不再关注。

Write-Allocate与Fetch-on-Write方法没有必然联系,但是这两种方法经常被混淆,以至于后来没有更正的必要与余地,通常意义上微架构提到的Write-Allocate策略是Write-Allocate与Fetch-on-Write的组合;实际上Write-Allocate也可以与No-Fetch-on-Write混合使用,该方法也被称为Write-Validate,这种方法很少使用;No-Write Allocate与No-Fetch-on-Write的组合被称为Write-Around,如表4-5所示。

表4-5 Write-Allocate与Fetch-on-Write的组合[3]

Fetch-on-Write

No-Fetch-on-Write

Write-Allocate

Write-Allocate

Write-Validate

No-Write Allocate

N.A.

Write-Around

我们假设一个处理器系统的MemoryHierarchy包含L1,L2 Cache和主存储器,而Cache Miss发生在L1 Cache。并在这种场景下,分析Write-Allocate,Write-Validate和Write-Around这三种方法的实现。

当Write L1 CacheMiss而且使用Write-Allocate方法时,L1 Cache Controller将分配一个新的Cache Block,之后与Fetch的数据进行合并,然后写入到L1 Cache Block中。这种方法较为通用,但是带来了比较大的Bus Traffic。

新分配一个CacheBlock往往意味着Replace一个旧的Cache Block,如果这个Cache Block中含有Dirty数据,Cache Controller并不能将其Silent Eviction,而是需要进行Write-Back;其次Fetch操作本身也会带来不小的Bus Traffic。

Write-Around策略是No-Write Allocate和No-Fetch-on-Write的策略组合。使用这种方法时,数据将写入到L2 Cache或者主存储器,并不会Touch L1 Cache。当Cache Miss时,这种方法并不会影响Memory Consistency。但是这种方法在Cache Hit时,通常也会Around到下一级缓冲,这将对Memory Consistency带来深远的影响。

虽然我能构造出很多策略解决这些问题,但是这些方法都不容易实现。读者可以很自然的想到一种方法,就是在Cache Hit时不进行这个Around操作,对此有兴趣的读者可以进一步构想在这种情况之下,如何在保证Memory Consistency的情况较为完善的处理Cache Hit和Miss两种情况。本节对此不再进一步说明。

Write-Validate策略是No-Fetch-on-Write和Write-Allocate的策略组合。使用这种方法时,L1 Cache Controller首先将将分配一个新的Cache Block,但是并不会向Fetch其下的Memory Hierarchy中的数据。来自CPU Core的数据将直接写入新分配的L1 Cache Block中,使用这种方法带来的Bus Traffic非常小。

但是来自CPUCore的数据不会是Cache Block对界操作,可能是Byte,Word或者是DWord,L1 Cache必须要根据访问粒度设置使能位,这个使能位可以是By Byte,Word或者是Dword,也因此带来的较大的Overhead。当进行Cache Write操作时,除了要写入的数据的使能位置为有效外,其他所有位都将置为无效。在使用这种方法时,有效数据可能分别存在与L1 Cache和L2 Cache,这为Memory Consistence的实现带来了不小的困难。

No-WriteAllocate和Fetch-on-Write的策略组合没有实际用途。从其下Memory Hierarchy Fetch而来的数据因为没有存放位置,在与CPU Core的数据进行合并后,依然需要发送到其下的Memory Hierarchy。几乎没有什么设计会进行这种不必要的两次总线操作。

在WriteMiss的处理方法中,Write-Allocate和Write-Around策略较为常用,Write-Validate策略并不常用。Write Miss的处理方法与Write Hit存在一定的依赖关系。Write-Around需要与Write-Through策略混合使用,而Write-Allocate适用于Write-Through和Write-Back策略。

在一个ccNUMA处理器系统中,与Write操作相关的处理更为复杂。本节介绍的Hit Miss实现策略各有其优点,所有这些策略所重点考虑的依然是如何降低因为Write而带来的Bus Traffic和Memory Consistency。


[1] 还有一种是上文提及的WriteOnce,Write Once是Write Through和Write Back的联合实现。

[2] M,M_W,MM和MM_W状态都属于Exclusive状态。

[3] 表4-5源自[74],并有所改动。

4.6 Cache Write Policy相关推荐

  1. Cache Memory技术示例

    Cache Memory技术示例 为什么需要cache?如何判断一个数据在cache中是否命中?cache的种类有哪些,区别是什么? 为什么需要cache memory 先思考第一个问题:程序是如何运 ...

  2. [mmu/cache]-ARM cache的学习笔记-一篇就够了

    ★★★ 个人博客导读首页-点击此处 ★★★ . 说明: 在默认情况下,本文讲述的都是ARMV8-aarch64架构,linux kernel 64位 . 相关文章 1.ARM MMU的学习笔记-一篇就 ...

  3. T级图片数据Cache思路以及图片服务器搭建方法

    通过 pp.sohu.com,淘宝,拍拍网的域名分析: 1871.img.pp.sohu.com.cn ,1872.img.pp.sohu.com.cn,1873.img.pp.sohu.com.cn ...

  4. 浅入浅出Caffeine cache

    背景 公司项目中有用到caffeine cache 所以来了解一下. 本地缓存也就是我们适用内存缓存一些热点数据,使应用程序的程序处理的更加的快.以及保护我们的一些有磁盘/网络IO操作的函数/方法,以 ...

  5. 《浅谈Cache Memory》 学习-第四章

    Cache的层次结构 我第一次接触存储器瓶颈这个话题是在上世纪九十年代,距今已接近二十年.至今这个问题非但没有缓和的趋势,却愈演愈烈,进一步发展为Memory Wall.在这些问题没有得到解决之前,片 ...

  6. 浅谈Cache Memory--目录

    序 第1章有关Cache的思考 1.1 Cache不可不察也 1.2 伟大的变革 1.3 让指令飞 1.4 Crime and Punishment 第2章Cache的基础知识 2.1 Cache的工 ...

  7. 高速缓冲存储器--Cache

    本篇参考 arm 官网公开材料,和微信公众号 老秦谈芯 学习笔记 宋宝华:深入理解cache对写好代码至关重要(上) 深入学习Cache系列 1: 带着几个疑问,从Cache的应用场景学起 深入学习C ...

  8. Cache的基本原理

    对于没有接触过底层技术的朋友来说,或许从未听说过cache.毕竟cache的存在对程序员来说是透明的.在接触cache之前,先为你准备段code分析: int arr[10][128];for (i ...

  9. Cache的基本原理以及简单操作

    对于没有接触过底层技术的朋友来说,或许从未听说过cache.毕竟cache的存在对程序员来说是透明的.在接触cache之前,先为你准备段code分析. int arr[10][128];for (i ...

最新文章

  1. Java项目:学生考勤管理系统(java+SSM+Poi导出+Easyui+JFreeChart+maven+mysql)
  2. 搭建云mysql,基于ECS搭建云上博客
  3. linux 命令输出 保存到文件 日志记录
  4. SearchRecentsuggestionsProvider
  5. h3c s7506e 配置手册_H3C交换机s5500Web登录配置
  6. Android WebView重定向问题,Android WebView 重定向问题
  7. Java新手造假_老板居然让我在Java项目中“造假”
  8. 详解自然语言处理5大语义分析技术及14类应用(建议收藏)
  9. 世界500强牛企英语面试精彩问答
  10. 网络:Server returned HTTP response code: 400(url中文)
  11. Git学习总结(14)——Git使用前的注意事项
  12. 分享Silverlight/WPF/Windows Phone/HTML5一周学习导读(1月9日-1月15日)
  13. 存储过程循环遍历一个月的每一天的函数_3.3 循环
  14. Linux SSHD服务安装与维护详解(一)——SSHD安装、启动与密钥认证实现
  15. javaweb项目设计文档
  16. R语言安装教程 | 图文介绍超详细
  17. Eclipse下载版本的选择
  18. 计算机电源改造加大功率,最标准的电脑电源功率计算公式 十代酷睿电源搭配建议...
  19. android 快速开发(二)辅助类的使用,kotlin枚举类反射
  20. 舒老师的hu测(日常吐槽)

热门文章

  1. 【P02】OP并联缓冲器
  2. 【前端性能优化】浏览器渲染原理与性能优化
  3. matlab利用conv函数验证卷积和的交换律_分配律和结合律,【判断题】卷积运算满足三个基本代数运算规律:交换律、结合律和分配律。...
  4. 东师计算机应用基础20在线作业3,东师计算机应用基础-18春在线作业3-1.docx
  5. 自动泊车之停车位检测算法
  6. 如何识别人的技术能力和水平?
  7. oracle的mins,分钟的缩写是min还是mins?
  8. SpringBoot Endpoint
  9. 想要减少广告浪费,你需要学会这些设计常识
  10. 流式大数据实时处理技术、平台及应用