1.背景知识
随着CPU技术的飞速发展,常用处理器的频率越来越高。虽然处理器的速度越来越快,但是与之匹配的内存的速度却没有得到相应的提升,这极大的限制了CPU的处理性能。本系列文档中介绍的主角缓存技术就是用来解决这个问题的。
ARM发布Cortex-M7架构后,微控制器领域出现了数百兆的芯片,比如ST s STM32F7系列和恩智浦MX RT系列芯片。这些芯片中的处理器都有自己的高速缓存,如果配置得当,可以显示出非常强大的数据处理性能。那么什么是缓存呢?如何利用这个新特性编写高性能的程序?还有什么需要注意的吗?你可能有以上的疑问,唐别急,本系列文章将为您一一解答。
本系列文章分为三个部分。第一部分是《cache 的基本概念与工作原理》,讲解缓存的基础知识。第二部分《STM32F7 Cache 介绍与实战》讲解如何在STM32F7系列芯片上使用cache,并编写程序进行性能测试。第三部分是《Cache 的一致性问题与使用技巧》,会介绍缓存的数据一致性以及使用缓存过程中的一些技巧。让让我们从缓存的基础知识开始,来理解这个强大的特性。
2.计算机分层存储系统
如果你想了解缓存的工作原理,你必须知道如何在计算机系统中存储数据。
当一个程序在计算机中执行时,所有的指令和数据都从内存中取出来执行。内存是计算机系统的重要组成部分,相当于计算机的仓库。它用于存储各种程序及其处理后的数据。因此,存储器的容量和性能应该随着处理器速度和性能的提高而提高,以保持系统性能的平衡。
然而,在过去的20年里,随着时间的推移,处理器和存储器的性能差异越来越大,存储器在容量尤其是访问延迟方面的性能增长已经跟不上处理器性能发展的需要。为了缩小内存和处理器之间的性能差距,计算机通常采用分层内存结构。
从上图可以看出,速度越快,容量越小,离CPU越近。CPU可以直接访问内存。外存的信息要先拿到主存,才能被CPU访问。当CPU执行指令时,大部分需要的操作数来自寄存器。当它需要对内存进行读写时,首先访问缓存,如果不在缓存中,就访问主存,如果不在主存中,就访问硬盘。此时,从硬盘中读取操作数并发送到主存储器,然后从主存储器发送到高速缓存。
使用数据时,通常只在两个相邻层之间复制传输,而且总是从慢内存复制到快内存。传输的单位是定长块,需要确定定长块的大小,建立相邻两层之间的映射关系。
在我们接触的嵌入式系统中,具体的访问时间和存储容量可能与上图不符,但不同级别之间的量级比较是一致的。
3.为什么需要缓存?
由于CPU和主存使用的半导体器件工艺不同,两者的速度差导致了快CPU对慢内存的等待,所以需要想办法提高CPU访问主存的速度。除了提高DRAM芯片本身的速度,采用并行结构技术,加快CPU内存访问的一个主要方法就是在CPU和主存之间增加一个高速缓冲区,也就是我们的主角缓存。
缓存位于CPU和内存之间,可以节省CPU从外部存储器读取指令和数据的时间。
4.基本概念
程序访问的局部性
对大量典型程序的分析结果表明,在很短的时间间隔内,程序生成的地址往往集中在很小范围的存储空间内,称为程序访问的局部性。这种局部性可以细分为时间局部性和空间局部性。时间局部性意味着已经被访问的某个存储单元很可能在短时间间隔内再次被访问。空间局部性意味着被访问的存储单元的相邻单元可能在短时间间隔内被访问。
指令缓存
指令缓存只用来缓存指令,从外存读取指令需要很长时间。如果外部存储器是闪存,CPU获取指令可能需要50-100ns。
数据缓存
数据缓存仅用于缓存数据。与指令缓存类似,CPU从外部SRAM或SDRAM中检索数据需要很长时间。
5.工作原理
Cache是一种小容量的缓存存储器,由快速SRAM组成,直接制作在CPU芯片中。它的速度几乎和CPU一样。在CPU和主存之间设置缓存,总是将主存中频繁访问的活动程序块和数据块复制到缓存中。由于程序访问的局部性,在大多数情况下,CPU可以直接从缓存中获取指令和数据,而无需访问速度较慢的主存储器。
为了便于缓存和主存之间的信息交换,缓存和主存空间都被划分成相等的区域。例如,主存中512字节的区域称为块,而主存块存储在缓存中的区域称为行。
缓存的行有效位
系统启动时,每个缓存行都是空的,里面的信息是无效的,只有在缓存行加载了主存块的情况下才有效。为了指示高速缓存行中的信息是否有效,每一行都有一个有效位。清除一行的有效位,以消除该行存储的主存,这叫刷新,也就是我们常说的刷缓存。
CPU在缓存中的访问过程
当CPU执行一个程序,需要从主存中访问指令或写入数据时,首先检查缓存中是否有需要访问的信息,如果有,直接在缓存中读写,不访问主存。如果没有,将当前访问信息所在的主存块从主存复制到缓存中。因此,缓存中的内容是主存中某些内容的副本。下图显示了带有缓存的CPU执行内存访问操作的过程。
高速缓存主存储器的平均访问时间
在上图所示的访问内存的过程中,需要确定被访问的信息是否在缓存中。如果CPU访问单元的主存块在缓存中,称为缓存命中,命中概率称为命中率p(hit rate)。如果不在缓存中,就是未命中,其概率就是未命中率。命中时,CPU直接访问缓存中的信息,花费的时间就是缓存的访问时间Tc,称为命中时间。当它缺失时,需要从主存中读取一个主存块,同时将所需信息发送给CPU,所以花费的时间是主存访问时间Tm和缓存访问时间Tc之和。通常,从主存读取一个主存块到缓存的时间Tm称为页面丢失。
CPU缓存和主内存级别的平均访问时间为:
Ta=p * Tc (1 - p) * (Tm Tc)=Tc (1 - p) * Tm
由于程序访问的局部性,缓存的命中率可以达到很高,接近1。因此,尽管丢失页面的时间比命中时间长得多,但最终的平均访问时间仍然可以接近缓存的访问时间。
缓存的映射方法
高速缓存行中的信息取自主存储器中的一个块。当将主存储块复制到高速缓存行时,在主存储块和高速缓存行之间必须遵循某些映射规则。这样,当CPU要访问一个主存单元时,可以根据映射规则在缓存的对应行中查找要访问的信息,而不是在整个缓存中查找。
根据不同的映射规则,主存块和缓存线之间有以下三种映射方式。
目前我们常见的CPU一般采用组连接的映射方式。组连接的映射方法借鉴了前两种映射方法的优点,取得了优异的性能和较低的硬件实现难度。我赢了这里就不详细描述了。感兴趣的朋友可以通过搜索阅读相关内容了解详情。
直接映射:每个主存块被映射到一个固定的缓存行。
完全关联:每个主内存块都映射到缓存中的任何一行。
Set associate:每个主内存块被映射到固定的高速缓存组的任何一行。
值得注意的是,写高级或低级语言程序时,缓存对程序员是透明的,所以程序员不不需要知道缓存是否存在或者如何设置它,他们也不知道感觉不到缓存的存在。但是深入了解cahche有助于写出高效的程序!
标签:CPU内存程序