[转]CPU缓存的工作原理

”缓存就像清凉油,哪里不舒服,抹一下就好了”

当 CPU 要读取一个数据时,首先会从缓存 (Cache) 中查找,如果找到就立即读取并送给 CPU 处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU 处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。

  通过优化的的读取机制,可以使 CPU 读取缓存的命中率非常高 ( 大多数 CPU 可达 90% 左右 ) ,也就是说 CPU 下一次要读取的数据 90% 都在缓存中,只有大约 10% 需要从内存读取。这大大节省了 CPU 直接读取内存的时间,也使 CPU 读取数据时基本无需等待。总的来说, CPU 读取数据的顺序是先缓存后内存。

  早期的 CPU 缓存容量很小,并且功能单一, Intel 从 Pentium 时代后把缓存进行了分类,当时集成在 CPU 内核中的缓存已不足以满足 CPU 的需求,而制造工艺上的限制又不能大幅度提高缓存的容量。因此出现了集成在与 CPU 同一块电路板上和主板上的缓存等不同类型,于是当时便把 CPU 内核集成的缓存称为一级缓存 (L1 cache) ,而外部的称为二级缓存 (L2 Cache) ;后来随着生产技术的不断提高,最终二级缓存也被挪进了 CPU 当中。通常一级缓存中还分数据缓存 (Data Cache , D-Cache) 和指令缓存 (Instruction Cache , I-Cache) 。二者分别用来存放数据和执行这些数据的指令,而且两者可以同时被 CPU 访问,减少了争用 Cache 所造成的冲突,提高了 CPU 效能。此外, Intel 在 Pentium 4 CPU 中还增加了一种一级追踪缓存,容量为 12KB 。

L1 cache vs L2 Cache

  用于存储数据的缓存部分通常被称为 RAM ,掉电以后其中的信息就会消失。 RAM 又分两种,其中一种是静态 RAM(SRAM) ;另外一种是动态RAM(DRAM) 。前者的存储速度要比后者快得多,我们现在使用的内存一般都是动态 RAM 。 CPU 的 L1 级缓存通常都是静态 RAM ,速度非常的快,但是静态 RAM 集成度低 ( 存储相同的数据,静态 RAM 的体积是动态 RAM 的 6 倍 ) ,而且价格也相对较为昂贵 ( 同容量的静态 RAM 是动态 RAM 的四倍 ) 。扩大静态 RAM 作为缓存是一个不太合算的做法,但是为了提高系统的性能和速度又必须要扩大缓存,这就有了一个折中的方法:在不扩大原来的静态 RAM 缓存容量的情况下,仅仅增加一些高速动态 RAM 做为 L2 级缓存。高速动态 RAM 速度要比常规动态 RAM 快,但比原来的静态 RAM 缓存慢,而且成本也较为适中。一级缓存和二级缓存中的内容都是内存中访问频率高的数据的复制品 ( 映射 ) ,它们的存在都是为了减少高速 CPU 对慢速内存的访问。

  二级缓存是 CPU 性能表现的关键之一,在 CPU 核心不变化的情况下,增加二级缓存容量能使性能大幅度提高。而同一核心的 CPU 高低端之分往往也是在二级缓存上存在差异,由此可见二级缓存对 CPU 的重要性。 CPU 在缓存中找到有用的数据被称为命中,当缓存中没有 CPU 所需的数据时 ( 这时称为未命中) , CPU 才访问内存。从理论上讲,在一颗拥有二级缓存的 CPU 中,读取一级缓存的命中率为 80% 。也就是说 CPU 一级缓存中找到的有用数据占数据总量的 80% ,剩下的 20% 从二级缓存中读取。由于不能准确预测将要执行的数据,读取二级缓存的命中率也在 80% 左右 ( 从二级缓存读到有用的数据占总数据的 16%) 。那么还有的数据就不得不从内存调用,但这已经是一个相当小的比例了。目前的较高端 CPU 中,还会带有三级缓存,它是为读取二级缓存后未命中的数据设计的 — 种缓存,在拥有三级缓存的 CPU 中,只有约 5% 的数据需要从内存中调用,这进一步提高了 CPU 的效率,从某种意义上说,预取效率的提高,大大降低了生产成本却提供了非常接近理想状态的性能。除非某天生产技术变得非常强,否则内存仍会存在,缓存的性能递增特性也仍会保留。

CPU 缓存与内存的关系

  既然 CPU 缓存能够在很大程度上提高 CPU 的性能,那么,有些朋友可能会问,是不是将来有可能,目前的系统内存将会被 CPU 取代呢?

  答案应该是否定的,首先,尽管 CPU 缓存的传输速率确实很高,但要完全取代内存的地位仍不可行,这主要是因为缓存只是内存中少部分数据的复制品,所以 CPU 到缓存中寻找数据时,也会出现找不到的情况 ( 因为这些数据没有从内存复制到缓存中去 ) ,这时 CPU 还是会到内存中去找数据,与此同时系统的速度就慢了下来,不过 CPU 会把这些数据复制到缓存中去,以便下一次不用再到内存中去取。也即是说,随着缓存增大到一定程度,其对 CPU 性能的影响将越来越小,在性能比上来说,越来越不合算。

  就目前缓存容量、成本以及功耗表现来看,还远远无法与内存抗衡,另外从某种意义上来说,内存也是 CPU 缓存的一种表现形式,只不过在速率上慢很多,然而却在容量、功耗以及成本方面拥有巨大优势。如果内存在将来可以做到足够强的话,反而很有取代 CPU 缓存的可能。

缓存的读写算法同样重要

  即便 CPU 内部集成的缓存数据交换能力非常强,也仍需要对调取数据做一定的筛选。这是因为随着时间的变化,被访问得最频繁的数据不是一成不变的,也就是说,刚才还不频繁的数据,此时已经需要被频繁的访问,刚才还是最频繁的数据,现在又不频繁了,所以说缓存中的数据要经常按照一定的算法来更换,这样才能保证缓存中的数据经常是被访问最频繁的。命中率算法中较常用的 “ 最近最少使用算法 ”(LRU 算法 ) ,它是将最近一段时间内最少被访问过的行淘汰出局。因此需要为每行设置一个计数器, LRU 算法是把命中行的计数器清零,其他各行计数器加 1 。当需要替换时淘汰行计数器计数值最大的数据行出局。这是一种高效、科学的算法,其计数器清零过程可以把一些频繁调用后再不需要的数据淘汰出缓存,提高缓存的利用率。

 

补充:

写策略通常采用写回或写直达,采用写回法时,仅当cache中的某行数据被替换时,才更新存储器中相应数据。采用写直达法时,则每次写操作都要同时更新cache和主存储器中的数据。

所针对的DSP处于单处理器工作模式下,考虑到整个系统的数据处理效率,设计时我们采用写回法更新数据。写回法中,如果一级cache中的数据发生改变而未立即写回L2 cache和主存储器,或者L2 cache中的数据发生改变,未立即写回主存储器,那么就会造成数据不一致而导致错误。为保证数据的一致性,在驻留于cache中的某一块被替换之前,必须考虑它是否在cache中被修改。如果没有修改,则cache中原来的块就可以直接被替换掉,而不需回写;如果修改过,则意味着对cache这一行至少执行过一次写操作,那么在替换之前主存储器中的数据也必须随之做相应修改。为此我们在cache的tag中设置了修改位M,在执行回写操作前我们均对修改位进行判断,其值为1时表示数据被修改过,需回写,为0则表示未修改,不进行回写。

Cache的替换算法有很多种 ,为了提高命中率,在设计时采用了优化的LRU算法:栈链法。栈链法的管理规则如下:

1) 把本次访问的块号与栈中保存的所有块号进行比较。如果发现有相等的,则cache命中,本次访问的块号从栈顶压入,栈内各单元的块号依次往下移,直至与本次访问的块号相等的那个单元为止,再往下的单元直至栈底都不改变。

2)如果相联比较没有发现相等的,则cache失效。栈底单元中的块号就是要被替换的块号。

实现时采用四个存储单元,每个单元两位,用来保存当前cache组的四个块号。首先是相联比较,以组号为地址,从四个标记寄存器中读取数据,和地址进行比较,然后就可以产生命中与否的信号,以及命中时相应的块号。

问题:对于两级缓存而言,一级、二级缓存的读写算法如何选择呢?

 

  小结

  高速缓存做为 CPU 不可分割的一部分,已经融入到性能提升的考虑因素当中,伴随生产技术的进一步发展,缓存的级数还将增加,容量也会进一步提高。作为 CPU 性能助推器的高速缓存,仍会在成本和功耗控制方面发挥巨大的优势,而性能方面也会取得长足的发展。

posted @ 2012-01-07 16:55  Let it be!  阅读(848)  评论(0编辑  收藏  举报