《计算机CPU缓存是如何工作的.docx》由会员分享,可在线阅读,更多相关《计算机CPU缓存是如何工作的.docx(4页珍藏版)》请在第一文库网上搜索。
1、代码都是由CPU跑起来的,我们代码写的好与坏就决定了CPU的执行效率,特别是在编写计算密集型的程序,更要注重CPU的执行效率,否则将会大大影响系统性能。CPU内部嵌入了CPUCaChe(高速缓存),它的存储容量很小,但是离CPU核心很近,所以缓存的读写速度是极快的,那么如果CPU运算时,直接从CPUCaChe读取数据,而不是从内存的话,运算速度就会很快。但是,大多数人不知道CPUCaehe的运行机制,以至于不知道如何才能够写出能够配合CPUCaChe工作机制的代码,一旦你掌握了它,你写代码的时候,就有新的优化思路了。那么,接下来我们就来看看,CPUCache到底是什么样的,是如何工作的呢,又该
2、如何写出让CPU执行更快的代码呢?根据摩尔定律,CPU的访问速度每18个月就会翻倍,相当于每年增长60%左右,内存的速度当然也会不断增长,但是增长的速度远小于CPU,平均每年只增长7%左右。于是,CPU与内存的访问性能的差距不断拉大。到现在,一次内存访问所需时间是200-300多个时钟周期,这意味着CPU和内存的访问速度已经相差2OO3OO多倍了。为了弥补CPU与内存两者之间的性能差异,就在CPU内部引入了CPUCaChe,也称高速缓存。CPUCache通常分为大小不等的三级缓存,分别是11Cache12Cache和13Cacheo由于CPUCaChe所使用的材料是SRAM,价格比内存使用的D
3、RAM高出很多,在当今每生产IMB大小的CPUCaChe需要7美金的成本,而内存只需要0.015美金的成本,成本方面相差了466倍,所以CPUCaChe不像内存那样动辄以GB计算,它的大小是以KB或MB来计算的。其中,11CaChe通常会分为数据缓存和指令缓存,这意味着数据和指令在11Cache这一层是分开缓存的,13Cache比11Cache和12Cache大很多,这是因为1ICaehe和12Cache都是每个CPU核心独有的,而13Cache是多个CPU核心共享的。程序执行时,会先将内存中的数据加载到共享的13Cache中,再加载到每个核心独有的12Cache,最后进入到最快的11CaCh
4、e,之后才会被CPU读取。他们之间的层级关系如下图所示:12Cache13Cache越靠近CPU核心的缓存其访问速度越快,CPU访问11Cache只需要24个时钟周期,访问12Cache大约10-20个时钟周期,访问13Cache大约20-60个时钟周期,而访问内存速度大概在200-300个时钟周期之间CPUCache的数据是从内存中读取过来的,它是以一小块一小块读取数据的,而不是按照单个数组元素来读取数据的,在CPUCaChe中的,这样一小块一小块的数据,称为CaChe1ine(缓存块),假如1ICaChe一次载入数据的大小是64字节,有一个imarray100的数组,当载入array时,由
5、于这个数组元素的大小在内存只占4字节,不足64字节,CPU就会顺序加载数组元素到array15,意味着array0array15数组元素都会被缓存在CPUCache中了,因此当下次访问这些数组元素时,会直接从CPUCaChe读取,而不用再从内存中读取,大大提高了CPU读取数据的性能。事实上,CPU读取数据的时候,无论数据是否存放到CaChe中,CPU都是先访问CaChe,只有当CaChe中找不到数据时,才会去访问内存,并把内存中的数据读入到CaChe中,CPU再从CPUCaChe读取数据。那CPU怎么知道要访问的内存数据,是否在CaChe里?如果在的话,如何找到Cache对应的数据呢?最简单、
6、基础的方法就是直接映射Cache(DirectMappedCache)。CPU访问内存数据时,是一小块一小块数据读取的,具体这一小块数据的大小,取决于Coherencyine_size的值,一般64字节。在内存中,这一块的数据我们称为内存块(B1ock),读取的时候我们要拿到数据所在内存块的地址。对于直接映射CaChe采用的策略,就是把内存块的地址始终映射在一个CPUCache1ine(缓存块)的地址,至于映射关系实现方式,则是使用取模运算,取模运算的结果就是内存块地址对应的CPUCaChe1ine(缓存块)的地址。举个例子,内存共被划分为32个内存块,CPUCaChe共有8个CPUCaChe
7、1ine,假设CPU想要访问第15号内存块,如果15号内存块中的数据已经缓存在CPUCache1ine中的话,则是一定映射在7号CPUCache1ine中,因为15%8的值是7。使用取模方式映射的话,就会出现多个内存块对应同一个CPUCaChe1ine,比如上面的例子,除了15号内存块是映射在7号CPUCaChe1ine中,还有7号、23号、31号内存块都是映射到7号CPUCaChe1ine中。B1ock32因此,为了区别不同的内存块,在对应的CPUCaChe1ine中我们还会存储一个组标记(Tag)。这个组标记会记录当前CPUCache1ine中存储的数据对应的内存块,我们可以用这个组标记来
8、区分不同的内存块。除了组标记信息外,CPUCaChe1ine还有两个信息:一个是,从内存加载过来的实际存放数据(Data)。另一个是,有效位(Va1idbit),它是用来标记对应的CPUCaChe1ine中的数据是否是有效的,如果有效位是0,无论CPUCaChe1ine中是否有数据,CPU都会直接访问内存,重新加载数据。CPU在从CPUCaChe读取数据的时候,并不是读取CPUCaChe1ine中的整个数据块,而是读取CPU所需要的一个数据片段,这样的数据统称为一个字(Word)。那怎么在对应的CPUCaChe1ine中数据块中找到所需的字呢?答案是,需要一个偏移量(OffSet)。因此,一个
9、内存的访问地址,包括组标记、CPUCaChe1ine索引、偏移量这三种信息,于是CPU就能通过这些信息,在CPUCaChe中找到缓存的数据。而对于CPUCaChe里的数据结构,则是由索引+有效位+组标记+数据块组成。如果内存中的数据已经在CPUCache中了,那CPU访问一个内存地址的时候,会经历这4个步骤:根据内存地址中索引信息,计算在CPUCaChe中的索引,也就是找出对应的CPUCache1ine的地址;找到对应CPUCaChe1ine后,判断CPUCaChe1ine中的有效位,确认CPUCaChe1ine中数据是否是有效的,如果是无效的,CPU就会直接访问内存,并重新加载数据,如果数据有效,则往下执行;对比内存地址中组标记和CPUCache1ine中的组标记,确认CPUCache1ine中的数据是我们要访问的内存数据,如果不是的话,CPU就会直接访问内存,并重新加载数据,如果是的话,则往下执行;根据内存地址中偏移量信息,从CPUCache1ine的数据块中,读取对应的字。