《浅谈Cache Memory》 学习-第一章

近些年,我在阅读一些和处理器相关的论文与书籍,有很多些体会,留下了若干文字。其中还是有一片领域,我一直不愿意书写,这片领域是处理器系统中的Cache Memory。我最后决定能够写下一段文字,不仅是为了这片领域,是我们这些人在受历史车轮的牵引,走向一个未知领域,所产生的一些质朴的想法。

待到动笔,总被德薄而位尊,知小而谋大,力少而任重,鲜不及矣打断。多次反复后,我几乎丢失了书写的兴趣。几个朋友间或劝说,不如将读过的经典文章列出来,有兴趣的可以去翻阅,没有兴趣的即便是写成中文也于事无补。我没有采纳这些建议,很多事情可以很多人去做,有些事情必须是有些人做。

这段文字起始于上半年,准备的时间更加久远些,收集翻译先驱的工作后,加入少许理解后逐步成文。这些文字是留给自己的一片回忆。倘若有人从这片回忆中收益,是我意料之外的,我为这些意外为我的付出所欣慰。Cache Memory很难用几十页字完成哪怕是一个简单的Survey,我愿意去尝试却没有足够的能力。知其不可为而为之使得这篇文章有许多未知的结论,也缺乏必要的支撑数据。

在书写中,我不苛求近些年出现的话题,这些话题即便是提出者可能也只是抛砖引玉,最后的结果未知。很多内容需要经过较长时间的检验。即便是这些验证过的内容,我依然没有把握将其清晰地描述。这些不影响这段文字的完成。知识的积累是一个漫长的过程,是微小尘埃累积而得的汗牛充栋。再小的尘埃也不能轻易拂去。

这些想法鼓励我能够继续写下去。

熙和禺皓的加入使本篇提前完成。每次书写时我总会邀些人参与,之前出版的书籍也是如此,只是最后坚持下来只有自己。熙和禺皓的年纪并不大,却有着超越他们年纪的一颗坚持的心。与他们商讨问题时,总拿他们与多年前的自己对照,感叹着时代的进步。他们比当年的我强出很多。我希望看到这些。

个体是很难超越所处的时代,所以需要更多的人能够去做一些力所能及的,也许会对他人有益的事情。聚沙成塔后的合力如上善之水。因为这个原因,我们希望能有更多的人能够加入到Contributors List,完善这篇与Cache Memory相关的文章。

Cache Memory也被称为Cache,是存储器子系统的组成部分,存放着程序经常使用的指令和数据,这只是Cache的传统定义。从广义的角度上看,Cache是缓解访问延时的Buffer,这些Buffer无处不在,只要存在着访问延时的系统,这些广义Cache就可以在掩盖访问延时的同时,尽可能地提高数据带宽。

在处理器系统设计中,广义Cache的身影随处可见。在一个系统设计中,快和慢是一个相对概念。与微架构(Microarchitecture)中的L1/L2/L3 Cache相比,DDR是一个慢速设备,在磁盘I/O系统中却是快速设备。在磁盘I/O系统中,仍在使用DDR内存作为磁介质的Cache。在一个微架构中,除了有L1/L2/L3 Cache之外,用于虚实地址转换的各级TLB,在指令流水线中的ROB,Register File,BTB,Reservation Station也是一种Cache。我们准备书写的Cache,是狭义Cache,是大家所熟悉的,围绕着处理器流水线和主存储器的L1/L2/L3 Cache。这些Cache组成的层次结构,是微架构的设计核心。

广义Cache的设计可以在狭义的实现中获得帮助,却不是书中重点。在网络与存储这两个热点话题中,算法层面之外的重中之重是广义Cache的管理问题。与云相关的各类概念中,亟需解决的事情依然是算法与广义Cache管理。算法层面的实现需要考虑广义Cache的管理策略,反之亦然。广义Cache与狭义Cache系统没有质的区别。这些Cache系统都是由数据缓冲,连接缓冲的数据通路和控制逻辑这三个部分组成。

从算法角度上看,广义Cache的设计与实现比狭义Cache相比也许略微复杂一些;用实现的角度上看,狭义Cache的设计复杂度远远超过大多数广义Cache。读者也许终其一生没有机会去体验狭义Cache系统的设计,依然可以从这些设计思想中受益。这些思想,可以应用于复杂的处理器系统中,可以解决一些细致入微的性能问题。系统开发者在不断思考探索的过程中,在挑战极限的奋斗中,在身旁最后一把利器寸寸折断后,杀虎屠龙。

我未曾想过书写一篇学术意义上完美的文章。我更愿意用工程师的语言完成写作,这并不阻碍本篇内容的有理可依。所有这些想法使我不堪重负,在整个处理器系统的设计中,几乎没有什么部件比Cache Memory系统更为复杂。

本篇书写的Cache系统以Alpha,Power,UltraSPARC和x86处理器为主线,这四个处理器目前属于Tier 1。虽然Alpha处理器已退出历史舞台,但是并不影响其Tier 1的地位。我不会刻意去书写目前较为流行的嵌入式处理器,because yesterday’s high-performance technologies are today’s embedded technologies, but yesterday’s embedded-systems issues are today’s high-performance issues.

在Tier 1处理器中,本篇偏重于Intel的x86处理器实现,不管有多少资料引证Power和UltraSPARC处理器的诸多优点,x86处理器依然是使用最为广阔,影响最为深远的处理器。单纯从结构上看,Intel的x86,即便是最新的Sandy Bridge EP处理器,也远未到达学术界意义上的完美。但是在Cache Memory层面,Intel的领先是事实。

我最初曾试使用英文书写这些文字,我已经记不清楚最后一次抱着学习的目的去读中文技术类书籍是曾几何时,中文科技类书籍不能如此发展下去。我远没有书写英文小说的能力,依然有使用英文写科普文章的胆子,不用翻译的书写更加惬意。最终放弃了这个选择,因为英文世界里有这样的文章,因为Cache Memory之外的内容,因为中文世界需要有人去贡献一些勇气与智慧。

待到完成,总留有遗憾。我习得从这些遗憾中偷得间隙,留一片空间给自己。书不尽言,言不尽意总是无可奈何。这些文字很难给予我任何成就感,细看先驱的诸多著作后,留下的是何足道后的反思。我安于反思后的平静。

在阅读这些文字前,希望您能够仔细阅读John和David书写的“A Quantitative Approach”。我常备这本书,看了许多遍,字里行间内外的一些细节仍然不慎明了,写作时重温此书有了新的收获,借此重新审读了下列文字。

这篇文章最初的版本是0.01,书名叫浅谈Cache Memory。

第一章 

1.1  关于Cache的思考

在现代处理器系统中,Cache Memory处于Memory Hierarchy的最顶端,其下是主存储器和外部存储器。在一个现代处理器系统中,Cache通常由多个层次组成,L1,L2和L3 Cache。CPU进行数据访问将通过各级Cache后到达主存储器。如果CPU所访问的数据在Cache中命中,将不会访问主存储器,以缩短访问延时。

工艺的提高,使得主存储器的访问延时在持续缩短,访问带宽也在进一步的提高,但是依然无法与CPU的主频,内部总线的访问延时和带宽匹配。主存储器是一个不争气的孩子,不是如人们期望那般越来越快,是越变越胖。

主存储器膨胀的形体对Cache Memory提出了更高的要求,也进一步降低了主存储器所提供的带宽与访问延时之间的比率。近些年,单端信号所提供的数据传送带宽受到了各种制约,使得差分信号闪亮登场。差分信号的使用却进一步扩大了访问延时,对于这种现象,理论派亦无能为力,只是简单规定了一个公式1‑1,这只是一个无奈的选择。

《浅谈Cache Memory》 学习-第一章_第1张图片

从以上公式可以发现,延时在以平方增长,而带宽以线性增长。可以预计在不远的将来,CPU访问主存储器的相对访问延时将进一步扩大,这是主存储器发展至今的现状,这使得在处理器设计时需要使用效率更高的Cache Memory系统去掩盖这些Latency,也使得Cache Memory需要使用更多的层次结构以提高处理器的执行效率。在现代处理器中,一个任务的执行时间通常由两部分组成,CPU运行时间和存储器访问延时,如公式1‑2所示。

《浅谈Cache Memory》 学习-第一章_第2张图片

在一个处理器系统中,影响CPU运行时间的因素很多,即便是几千页的书籍也未必能够清晰地对其进行阐述。但是即便在一个可以容纳几千条指令的并行执行的CPU流水线中,采用更多提高ILP(Instruction-Level Parallelism)的策略去进一步缩短CPU的运行时间,这些指令也必会因为存储器的访问延时被迫等待。

这使得如何缩短存储器访问时间受到更多的关注,合理使用Cache是降低存储器访问时间的有效途径。根据统计结果,在处理器执行一项任务时,在一段时间内通常会多次访问某段数据。这些任务通常具有时间局部性(Temporal Locality)和空间局部性(Spatial Locality)的特征,这使得Cache的引入顺理成章。这种局部性并不是程序天生具有的特性,是一个精心策划的结果。我们不排除有些蹩脚的程序时常对这两个Locality发起挑战。对于这样的程序,处理器微架构即便能够更加合理地安排Cache层次结构,使用更大的Cache也没有意义。

在一个任务的执行过程中,即便是同一条存储器指令在访问存储器时也可能会出现Cache Hit和Cache Miss两种情况。精确计算一个任务的每一次存储器访问时间是一件难以完成的任务,于是更多的人关注存储器平均访问时间AMAT(Average Memory Access Time),如公式1‑3所示。

《浅谈Cache Memory》 学习-第一章_第3张图片

从公式1‑3可以发现在一个处理器系统中,AMAT的计算也许并不困难,只需要能够确定Hit time,Miss Rate和Miss Penalty这三个参数即可。但是如何才能才能确定这三个参数。

在一个程序的执行过程中,精确计算Hit time,Miss Rate和Miss Penalty这三个参数并不容易,即便将计算这些参数所需的环境进行了一轮又一轮的约束。近些年,我在面试一些Candidates的时候,通常只问他们一个问题,让他们简单描述,在任何一个他所熟悉的处理器中,一条存储器读写指令的执行全过程。我很清楚在短暂的面试时间内没有任何一个人能够说清楚这个问题,即便这个Candidate已经获得了处理器体系结构方向的博士学位。

我所失望的是参加面试的学生几乎全部忘记了这些可能在课堂上学过的,可能会使他们受益终身的基础内容。参加面试的学生们更多的是在其并不算长的硕士博士学习阶段,研究如何提高编程能力,和一些与操作系统具体实现相关的技巧。这些并不是学生们的错,有太多的评审官们本身就仅专注于小的技术和所谓的编程能力。

这些具体的编程能力和技巧,本不是一个学生应该在学校中练习的。在弥足珍贵的青春岁月中,学会的这些小技巧越多,这个学生在整个技术生涯中的Potential可能越低。重剑无锋,大巧不公。泱泱大国最为缺少的,不是能够书写程序,实现各类技巧的工程师。

1.2 Cache不可不察

在现代处理器中,Cache Hierarchy一般由多级组成,处于CPU和主存储器之间,形成了一个层次结构,这个层次结构日趋复杂。Intel甚至放弃使用阿拉伯字母对Cache的各级层次编号,而直接使用LLC(Last-Level Cache),MLC(Medium-Level Cache)这样的术语。

变化的称呼表明了一个事实,Cache层次结构在整个处理器系统中愈发重要,也越发复杂。Sandy Bridge处理器大约使用了十亿个晶体管,在其正中不再是传统的CPU,是Ring Bus包裹着的最后一级Cache [1]。

《浅谈Cache Memory》 学习-第一章_第4张图片

处理器的制作过程异常复杂。在人类历史上,其设计难度只有古埃及的金字塔可以与其媲美,即便是胡夫金字塔也只使用了230万个巨石,几十万个劳工而已。现代CPU的所耗的资源何止这些数字。在处理器这座金字塔中,Cache层次结构是最基本的框架。

几千年前,孙子曾经说过,“兵者,国之大事,死生之地,存亡之道,不可不察也”。对于有志于站在金字塔顶峰的,即便目标只有半山腰的系统程序员,也是Cache,不可不察也。在Intel的Values->Discipline中有一句话“Pay attention to detail”。

但是不要忘记Devil is in the detail。准备深入理解Cache层次结构的读者需要时刻提醒自己真正了解什么是细节之后,才会重视细节,才能够避免因为忽视细节而引发的灾难。重视细节这个品质与你是否足够细心没有必然联系。

我们回到公式1‑3,简单探讨计算Hit time,Miss Rate和Miss Penalty这三个参数时所需要考虑的因素和相关的环境。

似乎Hit Time参数最容易获得。我们很快就可以从CPU的数据手册中找到各级Cache Hit后的访问时间,并从L1 Cache的访问时间开始计算Hit Time。可能我们上来就错了,现代处理器大多使用了Store-Load Forwarding技术。存储器读操作首先要查询的并不是L1 Cache,是在更前面执行的,还没有来得及提交的Store结果,这些结果保存在一段数据缓冲中,这个数据缓冲也是一种Cache,不过比L1 Cache更加快速一些,也更接近CPU。

除了数据Cache,在现代处理器中,在指令Cache前还有一个Line-Fill Buffer。Sandy Bridge微架构中还含有一个μops Cache[1],计算指令Cache的Hit延时也没有想象中容易。精确计算指令与数据Cache Hit的延时需要注意很多细节。简而言之,在处理器系统存储层次中,L1 Cache并不是最快的,也不是第一级。如果进一步考虑到Load Speculation使用的各类算法和命中率,Hit Time参数并不容易计算清楚。

即便不考虑这些较为复杂的细节,我们仅从L1 Cache开始,Hit Time参数也很难用简单的公式描述。在单处理器环境中,L1 Miss后会逐级查找下级Cache,直到主存储器。但是在多处理器内核环境中,情况复杂得多,一次存储器访问在自己的内核中没有命中,可能会在其他内核的Cache中命中,在其他内核的Cache中命中后,又存在数据如何传递,延时如何计算这些问题。说清楚这些问题并不容易。如果我们再进一步讨论多个SMP系统间Cache的一致性,这个Hit Time的计算就更加复杂。我只能选择放弃在这一节内,能够清楚地描述如何计算Hit Time这个参数。

Miss Rate参数更加难以琢磨。我们真的可以用Vtune,Perf这样的工具精确计算出哪怕是单个任务的Miss Rate这样的参数吗,用这样的工具得到的统计数值有什么用途。同一片树叶,有的人一叶障目,有的人一叶知秋。不要为一叶障目而苦恼。多看几片后,必会发现春天的到来,也不要为一叶知秋而骄傲,少看几片,终会被最后一片树叶阻隔。

Miss Penalty参数的计算仿佛容易一些。最糟糕的情况莫过于CPU从主存储器中获取数据。我们可以将环境进一步简化,以便于读者计算这个参数。我们可以不讨论SMP系统间的Cache一致性,甚至不讨论SMP之内的Cache一致性,仅讨论单处理器。即便如此Miss Penalty参数也不容易轻易计算,即便在这种情况之下,我们只讨论存储器读。

我们忽略微架构在Cache前使用的各类Queue,让存储器读操作首先对L1 Cache进行尝试。如果没有命中这级Cache,这次数据访问一定可以到达L2 Cache吗,如果不是L2 Cache,又是哪一级Cache。这一切由L1和L2 Cache的关联结构决定。在一个处理器系统中,L1与L2 Cache之间可能是Inclusive,也可能是Exclusive。如果是Inclusive,存储器读操作将接着尝试L2 Cache,如果不是将会跨越这级Cache。事实并非如此简单,L1与L2 Cache并不会直接相连,之间依然存在着许多Buffer。

历经千辛万苦,数据访问最终到达最后一级Cache,如果没有命中,就可以从主存储器中获得数据。在这种情况之下,我们仿佛可以计算出最恶劣情况之下的Miss Penalty。但是这只是噩梦的开始。在现代处理器系统中,每一次存储器读写指令,都是由若干个步骤组成,这些步骤间具有相互联系,如果进一步考虑Memory Consistency层面,所涉及到的同步操作更多一些,这些操作并不能用几句话概括。

我们抛开这些复杂话题,讨论在L1和L2 Cache Miss之后从存储器获得数据这个模型。存储器读从存储器获得数据仅是一次读访问的步骤。从主存储器获得的宝贵数据不会轻易丢失,会存放在Cache中,需要将这些数据存放到哪一级Cache最为合理,LLC,MLCs还是FLC。

在一个正常运行的系统中,在每一个Cache Block中存放的数据都是有用的。新数据存放通常意味着旧数据的淘汰。值得思考的是如何进行这些淘汰操作,使用什么策略进行淘汰。从L1 Cache中淘汰的数据虽然暂时没有用途,但是不意味着可以轻易丢失,是否应该先进入到L2 Cache暂存。采用这种策略时,L2 Cache也需要相应的进行淘汰操作。

从上文的描述可以看到,一个简单的存储器读访问带来了一系列的问题。我们首先需要为这次存储器读做基础的准备,然后进行真正的存储器读,读完成之后,还有复杂的扫尾工作。貌似容易计算的Miss Penalty参数即便在简化到了不能再简化的现代处理器系统中,也很难计算清楚。

我们还没有讨论存储器写对Cache Block的的污染与破坏,写操作可能会改变Cache Block的状态,使存储器读操作更加举步维艰,写操作还会带来很多Bus Traffic,这些Traffic加大了存储器读的Miss Penalty,我们没有讨论多处理器内核环境下的Cache Coherence。

我们依然忽略了一个更加基本的细节,虚实地址转换。在现代操作系统中运行的任务,没有哪个任务可以直接使用Physical Address(PA),使用更多的是Effective Address(EA)。在多数处理器系统中,EA首先被转换为Virtual Address(VA),之后再转化为PA。处理器微架构在更多的场景中直接使用的是PA,不是VA更不是EA。

虚拟化技术的引入,在略微有些复杂的VA,PA和EA的基础上又引入了MPA(Machine Physical Address)和GPA(Guest Physical Address),带来了一系列地址Mapping机制,中断重定向等内容。虚拟化还带来了IOMMU和I/O虚拟化技术。为了能够在最小的篇幅完成这篇文章,我们忽略虚拟化技术,专注最基础的虚实地址转换。

1.3 伟大的变革

虚拟地址的出现可以追朔到上世纪六十年代的Atlas计算系统[2]。在当时Atlas计算系统是一个庞然大物,但也只有96K字节的内部存储器和576K字节的磁鼓作为外部存储器。我们很难深刻体会在计算机发展的初级阶段,计算机使用者的无奈。

当时的使用者可能身兼数职,首先是一个有钱人,不然根本没有机会去购买和使用计算机;然后是一个精巧的工匠,不过打孔技术恐怕已经失传;还必须是一个科学家,需要使用计算机;最后才可能是程序员。

Atlas计算系统所提供的96KB物理地址空间很难满足程序员的需要。在当时程序员被迫显式地管理物理内存与磁鼓之间的数据交换,尽可能地利用外部存储器换入换出一些数据,以扩展物理内存地址空间。这些数据交换挫伤了程序员的编程热情。在这个大背景之下,Atlas计算系统引入了Virtual Memory,同时引入的还有分页机制。

技术的发展趋势惊人相似。在最具智慧的人解决了只有他能够解决的问题后,此后如潮水般涌入的人群爆发式地将其推至巅峰,等待下一位救世主的降临。虚拟地址出现之后迎来了这些变化。

在不到40年的时间里,虚拟存储技术遍及计算机系统的各个领域。从软件层面,多进程的引入顺理成章。与多进程相关的虚拟内存管理机制更加层出不穷,如On-Demand分配策略,COW(Copy On Write)策略等。从硬件层面,多线程处理器已被广泛接收,虚拟化技术更是软硬件层面的集大成者。这些变化已超出虚拟地址引入者的想象。这一切只是变化,或者是变化中的细节,终非变革。

虚拟地址的引入分离了程序员看到的地址和处理器使用的物理地址,设立了一个映射关系表存放虚拟地址与物理地址的映射关系,这个映射关系表也被称之为页表(Page Table)。最容易的想到的是使用主存储器存放这个映射关系表,但是没有程序能够忍受在使用虚拟地址访问一段物理空间时,首先需要从主存储器的页表中获得物理地址。

使用TLB(Translation Lookaside Buffer)作为页表的缓冲是一个不错的想法,很快实现在各类处理器中。TLB一般由多个Entry组成,不同处理器使用的Entry组成结构并不相同。下文以Freescale的E500内核为例简单介绍TLB Entry基本组成结构,如图1‑2所示。

《浅谈Cache Memory》 学习-第一章_第5张图片

E500内核的TLB中,一个Entry的必要组成部分包含EPN(Effective Page Number),RPN(Real Page Number),TSIZE(窗口大小,通常为4KB)。其中EPN与TIS和TS字段联合组成VPN(Virtual Page Number)[4];RPN是物理地址基地址;TSIZE记录映射窗口的大小,WIMGE和UWRX为状态信息。

在一段程序访问存储器时,需要进行虚实地址转换。首先需要做的是将EA转换为VA,这个过程因处理器而异,基本过程是VA=f(EA)。函数f可繁可简,x86处理器的处理方法较为复杂。E500内核的做法较为简单,将TS,TID和EA级联即可。

CPU得到VA后,将与TLB中所有Entry同时进行比较,如果Hit则获得RPN,之后通过简单的计算,最终获得PA;如果Miss,就必须从PTE中进行查找,或者使用软件或者使用硬件手段。这些因为Miss引发的一系列操作会相大程度得影响CPU的执行效率。

TLB最好永远不发生Miss,这要求TLB需要Cover整个主存储器空间,硬件无法容纳这样大的TLB。而且随着TLB的增大,其查找延时也越长,折中的选择是使用多级结构。TLB也因此拆分为L1和L2 TLB,与Cache Hierarchy的结构越发一致。TLB也是一种广义Cache。

多进程的频繁切换为TLB制造了不小的麻烦。在现代处理器系统中,每一个进程都使用各自独立的虚拟地址空间,进程的切换意味着虚拟地址空间的切换,也意味着TLB的刷新。进程的频繁切换导致TLB需要频繁预热,这个开销是难以接受的。这使得PCID(Process Context Identifiers)的引入成为可能。

Intel从Westmere处理器开始支持这一功能[5]。其原理是在TLB Entry中加入PCID,并作为VA的一部分。使用该功能后,进程切换时,没有必要刷新TLB,从而在一定程度上提高TLB的使用效率。E500内核使用图1‑2中的TID字段也可以实现同样的功能。AMD的Opteron微架构使用ASN(Address Space Number)[6]称呼这一功能。采用这种方法在减少TLB刷新操作的同时,进一步提高了函数f的复杂度和硬件负担。凡事有利有弊。

多线程处理器的引入再一次增加了TLB设计的负担。在多线程处理器中,存在多个逻辑CPU。这几个逻辑CPU共享同一条流水线,却使用不同的虚拟地址空间,也需要使用TLB进行虚实地址转换,在绝大多数情况下,这些逻辑CPU共享TLB,对进程切换带来的TLB刷新操作是Zero-Tolerance。这使得Logical Processor ID也加入到TLB Entry之中。

TLB经历若干变化后,其Entry结构日趋稳定,却迎来了更加严厉的挑战。因为主存储器的膨胀速度已经越发不可控制。程序对主存储器容量提出越来越高的要求。这使得主存储器容量几乎以每年100%的速度膨胀,使得TLB的Coverage Rate在逐年降低,直接导致TLB Miss Rate的不断提高。

经典的教科书曾告诉我们,程序的TLB Miss Rate平均值仅为5%左右,在某些情况之下不到1%[7]。而近些年的研究表明,在很多应用中,TLB Miss Rate仅为30~60%[8]。这使得如何降低TLB Miss Rate重新受到关注。

增加TLB的Coverage Rate是降低TLB Miss Rate的有效手段,Coverage Rate指TLB所能管理的存储器空间与主存储器容量的比值。近些年随着主存储器容量的不断扩大,TLB Miss Rate在逐步降低。在主存储器容量不变的前提下,增加TLB的Coverage Rate有两个途径。一是增加TLB的Entry数目,这个数目已经在不断增加,依然无法与膨胀得更加快速的主存储器容量匹配;另外一种方法是增加一条TLB Entry所能Cover的Size。

近期Intel的x86在TLB Size为4K~4MB Hugepage的基础上,提出了1GB Superpage的概念[5]。这一概念并非x86的发明,一些嵌入式处理器,如Freescale的E500内核,很早就使用TLB1[4]支持Superpage,使用TLB0支持常规页面。

增大的页面给操作系统带来了额外的负担。随着页面的增加,应用程序消耗的内存会相应增加,而且相应带来的换页开销也进一步增大。但是如果仅仅面对4K~4MB大小的页面,操作系统仍有能力找到通用策略,FreeBSD从7.0版本起支持4K~4MB大小的Hugepage,Linux也从2.6.23开始为各类微架构提供Hugepage的支持。

真正带来挑战的是1GB之上的Superpage。许多学者与工程人员试图寻求一些Superpage的通用管理策略[9][10][11],依然难以解决由Superpages带来的Allocation,Relocation,Promotion,Pollution和Fragmentation Control等一系列问题。这使得这些所谓Superpage管理的通用方法几乎停留在纸面上或者实现中,很少有人直接使用操作系统提供的实现机制。

这使得更多的人开始认真思考操作系统是应该继续找寻通用解决方法,还是为专用化与定制化提供服务,是虽千万难吾独往矣,还是耐心等待着水到渠成。Intel将TLB Size直接从4MB跨越为1GB的事实也在暗示着,操作系统需要进一步为应用让步,不再是全面接管,不再是继续制定放之四海而皆准的规则,而是让高效应用按照各自的轨迹前行,是为需要进一步优化的程序提供更大的空间。

Superpages的引入极大降低了TLB Miss Rate。还是有很多人发现TLB地址转换依然存在于存储器读写访问的关键路径上。在多数微架构中,一条存储器读指令,首先需要经过虚实地址转换,得到物理地址之后,才能通过若干级Cache,最终与主存储器系统进行数据交换。如果存储器访问可以部分忽略TLB转换而直接访问Cache,无疑可以缩短存储器访问在关键路径上的步骤,从而减少访问延时。Virtual Cache为此而生,John和David对其情有独钟,Virtual Cache也在MIPS系列处理器中得到了大规模普及,在Pentium 4,Opteron,Alpha21164和有些ARM处理器中使用了Virtual Cache。

采用Virtual Cache不是灵丹妙药,这种方法虽然缩短了存储器访问的关键路径,也带来了Cache Synonym/Alias这些问题,这些问题在SMP和SSMP系统中暴露出了更大的问题。解决这些问题更多需要考虑的是各种软硬件层面的权衡与取舍。

简单介绍虚实地址转换关系之后,我们首先需要关心在一个处理器系统中,存储器读写指令的执行过程。对此一无所知的读者,很难进一步理解Cache层次结构。也正是Cache层次结构的引入,加大了存储器读写指令执行的实现难度。

 参考博文:saling的博客 系列专题http://blog.sina.com.cn/s/blog_6472c4cc0102dusv.html

 

转载于:https://www.cnblogs.com/gujiangtaoFuture/articles/11163330.html

你可能感兴趣的:(《浅谈Cache Memory》 学习-第一章)