引言
计算机奠基人之一的科学家冯·诺依曼(John Von•Neumann)提出了至今仍在沿用的计算机体系结构模型,即计算机必须具备五大组成部分:输入设备、输出设备、存储器、 运算器和控制器 。 其中,运算器和控制器可以归于处理器核的范畴,其运行的指令和所需要的数据都必须来自于存储器。这种结构方便了计算机的设计,促进了微处理器的飞速发展,但是也导致了存储与处理器的发展速度不一致,处理器和存储器的性能差距不断拉大,存储器数据访问速度跟不上 CPU 的数据处理速度。近些年人们越来越感到这种存算分离架构的限制。1
下面这张图展示了一般计算机里的存储层次和物理分布,在虚线框内的就是微处理器,需要与片外的 DRAM(也就是内存)交换数据,而易失性的 DRAM 还需要把数据存在非易失性的 Flash 或磁盘上。而缓存(Cache)一般是基于 SRAM 。当然,距离微处理器核越近的存储器,访问速度越快,容量越小,每字节成本更高。
当然存储技术本身的发展以及各种存储技术的原理也是很有意思的,感兴趣的推荐这篇文章:https://sspai.com/post/68711
本篇只关注微处理器的存储架构——缓存。
缓存基础
缓存利用软件程序的时间局部性和空间局部性,将空间巨大的存储器数据动态映射到容量有限的缓存中,可以将访问存储器的平均延迟降低到最小的机制。
- 时间局部性:某个数据项在被访问之后可能很快被再次访问的特性。
- 空间局部性:某个数据项在被访问之后,与其地址相近的数据项可能很快破访问的特性。
可以给出量化程序中局部性的几个简单原则:
- 重复引用相同变量的程序有良好的时间局部性。
- 对于具有步长为k的引用模式的程序,步长越小,空间局部性越好。具有步长为1的引用模式的程序有很好的空间局部性。在内存中以大步长跳来跳去的程序空间局部性会很差。
- 对于取指令来说,循环有好的时间和空问局部性。循环体越小,循环迭代次数越多,局部性越好。
一般将一个两级层次结构中存储信息交换的最小单元称为块(block)或行(line), 如果处理器需要的数据存放在高层存储器中的某个块中,则称为一次命中。如果在高层存储器中没有找到所需的数据,这次数据请求则称为一次缺失。 随后访问低层存储器来寻找包含所需数据的那一块。命中率(hit rate) 或命中比率(hit ratio), 是在高层存储器中找到数据的存储访问比例,通常被当成存储器层次结构性能的一个衡量标准。命中时间(hit time)是指访问存储器层次结构中的高层存储器所需要的时间,包括了 判断当前访问是命中还是缺失所需的时间。缺失代价(miss penalty)是将相应的块从低层存储器替换到高层存储器中,以及将该信息块传送给处理器的时间之和。
映射类型
在 cache 中为主存中每个字分配一个位置的最简单方法就是根据这个字的主存地址进行分配,这种 cache 结构称为直接映射(direct mapped)。每个存储器地址对应到 cache 中一个确定的地址。几乎所有的直接映射 cache 都使用以下的映射方法:
( 块 地 址 ) m o d ( c a c h e 中 的 块 数 ) (块地址) mod (cache 中的块数)