首页 > 代码库 > 如何使用DSP的cache(转)
如何使用DSP的cache(转)
C6747在执行一块算法的执行时间在114ms左右,需求要20ms以下。6000属于分层存储器体系架构,内部RAM跟CPU不同频运行,只有cache使能才跟CPU同频。可能是cache没打开。下面转载一遍文章。非常感谢原创。
处理器中的cache是存放于处理器四周的高速存储器,它可以用来保存运算处理时的一些共有的指令,从而加速运算的速度。
在本文中,将比较cache存储器和系统中的普通的存储器,随后将先容cache的一些基本理论和基本术语,以及在高速处理器结构中cache的重要性。以TI的TMS320C64x DSP结构为基础,将着重向开发者先容cache是如何工作,如何配置,以及如何正确使用cahce,本文将以cache的一致性贯串全文。
存储器结构
在图一中,左边的模块先容了普通的存储器系统结构,CPU和内部存储器均工作在300MHZ。当CPU访问外部存储器时,将不会发生存储器访问禁止的情况。并且当访问内部存储器时也不会发生访问延迟的情况。
当CPU的时钟增加到600MHZ时,只有当存储器的速度也增加到600MHZ时才不会发生访问等待的状态。很不幸,对于大多数情况下同样频率工作在600MHZ的内部存储器价格将十分昂贵。而300MHZ的也不是好的选择,由于将大幅降低CPU的频率。设想一个算法需要在每个周期访问存储器,每一次对存储器的访问需等待一个周期,加倍了访问周期从而抵消了CPU的双倍工作频率。
图一:普通存储器和多层存储器结构
解决的办法就是采用一个多层次的存储器。最靠近CPU的存储器由一块速度快但体积小组成,访问时不存在任何延迟。稍阔别一些CPU的采用体积大但速度稍慢的存储器。对于低级别的存储器来说,最靠近CPU的这块存储器便是典型的cache存储器位置法则 当然,这个解决办法必须工作在CPU能够最快访问最近的存储器的情况时。由于位置法则,对于大多数CPU来说这一情况都是适用的。这意为着在一个特定的窗口时间内,程序仅仅访问全部地址空间的一块相关的小区域。这包括一下两个基本的位置种类:
1、空间位置法则:一块刚刚被访问过的资源四周的资源更有可能被访问
2、时间位置法则:在过往的一个时间点刚刚被访问的资源更有可能马上在将来被访问
空间位置法则是由计算机程序的编程风格所决定的,一般情况下,相关的数据将被连续的存储在存储器中。例如一个共同的类型在计算时,总是将第一个元素放在第一列,然后是第二个元素,以此类推。同理,时间位置法则形成的原因是程序包含的结构比如循环结构调用的是相同的指令(甚至是同样的数据),以此反复。
图二阐述了空间位置法则,它描述了一个6阶FIR滤波器。为了计算y[0]输出,将从输进数据缓存x[](值由预算法则对内存中访问的采样数据决定)里读出6个采样数据。当完成一次数据访问时,cache控制器从内存中取出x[0]和一系列的取样值地址。这个一系列的地址值称为cache 串。假如再从低速率的存储器中取出数据串将导致一些CPU的延迟周期。这样做的目的是而当进行以下计算时,邻近x[0]的这些数占有可能马上将被访问。而对于FIR滤波器来说正好适用这个原则,由于接着的五个采样数值(x[1]-x[5])马上将被访问。这五个数值的访问过程将进进到cache中完成而不是在低速率的存储器中进行,因而不会产生任何延迟周期。
图二:位置原则
当计算下一个输出y[1]时,五个抽样值(x[1]-x[5]) 将被再次使用,只有一个抽样值(x[6])是新的。所有的抽样值已经提取到cache中,CPU不会发生任何的延迟。这个早先使用过的数据在数据处理中再次被用到的例子很好的说明了时间位置原则。
cache是以局部时间地和空间地访问数据为基础的。因此极大的降低了对低速率的存储器访问,尽大多数数据访问都由高速cache存储器以CPU的工作频率服务于CPU。
存储器数率:
cache系统代表性的包括三种级别
1、第一级cache (L1)位于CPU芯片上并且运算快于CPU工作速度。
2、第二级cache(L2)也位于芯片上比L1速度慢而体积大。
3、第三级cache(L3)位于CPU外部,是速度最慢体积最大的存储器。
每一级别的cahce相应执行的因素决定于cache间隔处理器的间隔。表一中体现了一个有代表性的各自相应的时间。
图三:在一个2ns时钟周期的具有多级cache系统的处理器cache执行时间
当运算器需要从存储器中提取数据时,它首先在最高级的cache中寻找然后在次高级的cache中寻找。假如在cache中找到,则称为命中。反之,则称为不命中。
一个cache系统的性能决定于cache申请命中的次数,也称为命中率。对于一个特定的级别的cache来说,一个高的cache命中率意为着更高的性能。而整个cahce系统的性能决定于各级cache的命中率。比如一个cache系统第一级 L1 cache命中率为70%,第二级L2cache命中率为20%,第三级L3cache命中率为5%,整个存储器的为5%,因此基于图三这个系统的均匀存储器性能为:
(0.7 * 4) + (0.2 * 5) + (0.05 * 30) + (0.05 * 220) = 16.30 ns
为了阐述这个概念,我们以TI的TMS320C64x DSP 存储器结构为例,(表四)包含了一个两级内部cache存储器以及外部存储器。L1cache可以被CPU无延迟的访问。L2存储器可被编程并且可分配为L2SRAM(可设地址的片上存储器)和L2cache。无论何种设置中,L2存储器都只能每两个周期被访问一次。L2的大小决定于芯片的不同,但总是比L1大的多。以TMS320C6454 DSP为例,L2的大小为1MByte。而C64x DSP 最多支持2GBytes 的外部存储器。存储器的速度决定于存储器采用的技术种类,尽大多数在100MHZ左右。在图三中,所有的cache和数据通道均自动的由cache控制器控制。
图四:TMS320C64x Cache 存储器结构
Cache的数据更新
由于cache也是主存储器中的一部分备份,因此cache是否能实时反映主存储器的数据显得至关重要。当cache里的数据改变,而主存储器内的数据未能改变时,cache里的数据被称为“脏”数据。当数据在主存储中改变,而cache中未能实时改变,cache里的这个数据被称为“延迟”数据。
cache控制器采用一系列的技术来维持cache的一致性从而保证cache里存储的都是有用的信息而不是延迟数据。“监测”和“写回”操纵便是两种保持cache一致性的办法。”监测“指的是用来答应cache在主存储器中是否进行影响cache地址的传输。假如cache探测到有这样的传输发生,它将及时更性自己从而匹配主存储器。这个在主存储器中复制数据的过程称为”写回“操纵。
由于cache比主存储器体积小,因此经常会被填布满。当此种情况发生时,所有搬到cache里面的新数据将会取代已经存在的数据。这里有多种决定数据取代的方法。例如随机取代法、先进先出取代法、最近最少使用取代法。大多数的处理器采用的都是最近最少使用取代法。这样可以是的最新的数据取代最近最少使用的数据。这种方法来源于时间位置法则。
直接映射cache
cache存储器可以被设置为“直接映射”或者“联合方式”。为了解释这些术语,我们以图四所示的C64X的L1Pcache为例,这些cache由512列32字节组成。每一排映射到一些固定的具有相识的存储器地址上。比如:
从0000h 到 0019h的地址经常被cache安排在第0列
从0020h 到 0039h的地址经常被cache安排在第1列
从3FE0h 到 3FFFh 的地址经常被cache安排在第511列。
因此一旦我们需要获得地址4000h,由于cache的容量被用尽了,因此从4000h 到 4019h的地址需要从新从第0列开始。
图五:直接映射caches
为了保持复制的数据,每一行的L1Pcache包括:
一位有效信号,用来指示cache的列中 是否包含的是有用的信息
一个标记符,其值即是地址的高18位,这个是必须的由于一个指定的列可能包含着不同地址的数据,比如,第0列可以包含的是从0000h 到 0019h的数据,也可以是从4000h 到 4019h的数据。
一个可设置的数据,这个数据等同于从第5位到第13位的地址。对于直接映射方式,这个设置的数据同这个列的值是一样的。而对于联合方式时要更加复杂,这种情况我们将在随后讨论。
现在让我们看看当CPU访问位于0020h的地址时发生了什么。假定cache被完全无效,即意为着所有的列都没有包含有效数据。当CPU发出对地址20h的访问请求时,cache控制器开始首先在部分地址位(比如:从第5位到13位)等同于列地址的位置查询。当这个部分地址值(从第5位到13位)被设置为1时,匹配需查询的地址。控制器将继续检查第一列的标记位是否也和地址0020h 到 0039h的高18位相符合。当这些都完成时,将检查有效数据位看cache保存的是否为有效数据。假如有效数据位为0时,cache控制器记录一个不命中操纵。
这个不命中操纵将使得控制器将从存储器中将此列的数据0020h-0039h读进,并将该有效数据位设置为1。同时将部分地址值保存在标记符RAM中。取得的数据将被传送到CPU中,完成访问操纵。
假如这个0020h的地址被再次访问,cache控制器将再次取得这个地址,检查它的设置符和标记符。当有效数据位为1时,控制器将记录一个命中操纵,因此cache列里面的数据也将被送到CPU中,完成整个访问操纵。
联合设置方式
联合设置方式是直接映射方式的延续。在直接映射方式中,每一个设置只包含一列。而在联合设置方式中,每一个设置包含多个列,被称为多路方式。图五中阐述了这样一个联合设置的cache,以C64x DSP‘s L1D为例。这是一个两路的包含64个字节总共16KBytes容量的联合设置cache。
为了保持数据,L1Dcache的每一列包含以下:
一个最近最少使用位用来指示哪些路最近很少被使用(这个在L1P中未被使用);
一个脏数据位,用来指示cache列是否匹配主存储器的容量(这个在L1P中未被使用);
一个有效数据位,用来指示cache列中包含的是否是有效数据;
一个标记位,等价于地址的高18位;
一个设置数据,等价于地址的5到13位。
命中和不命中决定的方式和直接映射cache方式是一样的。不同的是此时需要两个标记位,一个标记位记录是哪一路的请求数据。假如是第0路的数据被命中,则第0路的列中的数据被访问,假如是第1路的数据被命中,则第1路的列中的数据被访问。
假如两路均不命中的话,数据将从内存中被指派。一个最近最少使用位将决定数据如何分配类似于一个开关操纵。假如被指派的第0列的最近最少使用位被设置为0,那么将把此数据分配于第一列。无论对这个cache列是读还是写的访问,都将改变这个最近最少使用标记位。例如:假如第0路的列被读取,则最近最少使用位将切换到1。由于最近最少使用位只记录不命中操纵,但是它的状态每次都会更新,无论对列访问是命中还是不命中,读或者写。
对于L1P来说,L1D是一个读分配的cache,不管新数据在内存中申请时读操纵是命中或者不命中。在一个写不命中操纵时,数据从写存储器传递到内存中,绕过L1Dcacee。在一个写命中操纵时,数据写进cache中而不是立即写进内存。当数据被CPU写访问改变时,cache里的内容将提交给一个写回cache,随后数据将被写进内存中。
脏数据位指示当cache里面的数据被写操纵修改时,而修改后的新数据还未被写进到主存储器中。最初脏数据位将被赋值为0。一旦当CPU对某列进行写操纵时,脏数据位将变为1。当此列被逐出cache时,这个数据将被写回主存储器中。当发生读不命中操纵时新数据将从脏数据列中申请,这种情况才会发生。一个写回命令将传递给cache控制器从而产生一个写回操纵,只是这种情况并不经常发生。
优化cache性能
这里有三种不命中的情况:
必然不命中(也叫首次不命中):这种不命中发生在当数据第一次放进cache中,为了和下面两种不命中方式区分开来,它们可以被避免。
冲突不命中:不命中发生在在该列在被重复使用之前被取代。
容量不命中:这种方式发生在当cache容量被耗尽时,容量不命中是冲突命中的一种方式。
对于每一种不命中方式,控制器在将数据从存储器放进cache中时都会产生延迟。为了得到更高的性能,每一列中的内容在被取代之前应该尽可能的被重复利用。重复使用某列以此来获得不同的位置能够改善空间位置的访问,而重复使用某列可以改善时间位置的访问。这就是优化cache存储
性能的一个最基本的准则。
例如,当cache存储器经常被访问时,cache的性能是比较高的。这种访问模式在对下一列访问之前将重复对上一列的访问。例如,下面的代码就
有一个很高的命中率:
而下面的代码的性能就如上一个,由于他的内存的访问有一个很大幅度的跨越,这就意味着在对下一列访问之前对上一列的访问率就降低了。
假如某一列被从cache里驱除而又需要重新访问,这一列必须重新写进cache。因此,如何避免这种驱除就变得非常重要,确定这种不命中的原因可以帮助我们避免下一次的不命中。
正如上面所说,容量不命中产生的原因是由于cache的容量小于主存储器。假如发生容量不命中,最简单的办法就是加大cache的容量。例如,
C64x DSP上的L2cache可以被配置为cache和SRAM的混合体。假如有很多的容量不命中的情况,编程者可以将L2存储器更多的申请为cache。另一种
解决办法就是减少所需要的数据量。
假如产生冲突不命中,关键在于重新编排数据的排列方式,从而使得最近时间数据能够映射到其他路中。(对于直接映射方式,这个类似于将数据映射对应于不同的行中)改变存储器的排列方式,可以使得数据位于存储器中的不同位置,从而不会产生冲突。作为可选择的,从一个硬件设计的角度,多设置方式可以产生多列的方式。因此,存储器中映射于相同设置的两列都可以在cache中被申请,而不会发生冲突。
前面已多次提到了Cache,这可是一个讨人喜欢的东西,您有必要详细了解它的作用与原理。Cache是介于CPU与主内存之间、或者主内存与磁盘之间的高速缓冲器,其作用是解决系统中数据读写速度不匹配的问题。其中介于CPU与主内存之间的缓冲器又称为RAM Cache,而介于主内存与磁盘驱动器之间的缓冲器则称之为Disk Cache,这里要讨论的是前者,也就通常简称的Cache。
那么,Cache是怎样工作的呢?您一定明白CPU的运算速度比主内存的读写速度要快得多,这就使得CPU在访问内存时要花很长的等待时间,从而造成系统整体性能的下降。为了解决这种速度不匹配的问题,需要在CPU与主内存之间加入比主内存更快的SRAM(Static Ram,静态存储器)。SRAM储存了主内存中的数据(专业术语称为“映象”),使CPU可以直接通过访问SRAM来读写数据。由于SRAM的速度与CPU的速度相当,因而大大缩短了数据读写的等待时间,系统的整体速度也就得到了提高。既然SRAM那么快,为什么不用来作为主内存呢?这是因为SRAM采用了与CPU相类似的半导体制造工艺,成本极高,只有在那些只关心性能不考虑价格的场合才会这样做。这也就使得Cache粉墨登场了,它能将CPU用过的数据,以及结果保存起来,让CPU下次处理时先来访问Cache,如果没有可用的数据再去别处找,以此来提高运行速度。
Cache由标记存储器和数据存储器两个基本部分组成。标记存储器是用来储存Cache的控制位与块地址标签,控制位用于管理Cache的读写操作,而块地址标签则记录着Cache中各块的地址。这个地址包含了与主内存映射的块地址,并且都与Cache中的一块“数据”相对应。而这块“数据”正是贮存于Cache的数据存储器中。当CPU读取数据时,先通过地址总线把物理地址送到Cache中,与Cache中的块地址标签进行对比。若相符合,则表示此数据已经存在于Cache中(此情况被戏称为“命中”),这时只需把Cache中的对应数据经由数据总线直接传送给CPU即可。但如果CPU送来的物理地址无法与Cache中的块地址标签相符,则表明这一数据不在Cache中(称为“失误”),这时,需要由主内存把CPU所需的数据地址拷贝到Cache中,再由Cache把数据传送给CPU。从这个过程我们可以看到,若CPU读取“命中”,存取速度确实可以提高许多,但如果“失误”,则Cache的存在反而减慢了CPU的读取速度。因此,采用何种技术和方法提高读写命中率、减少失误率,就成了Cache设计的关键。加大Cache的容量当然可以提高命中率,但因成本问题,Cache不可能无限增大,但可以通过采用适当的映射方式和块替代方式来提高命中率。
所谓映射方式是指Cache中的数据如何与主内存中的数据相对应的问题。映射方式通常有以下三种:
1:直接映射
如果主内存上的块只能映射到Cache中的特定块,我们称这种映射方式为直接映射。直接映射的存取速度最快,但失误率也最高。
2:完全映射
在这种映射方式下,主内存上的块可以映射到Cache的任意块之中,当CPU欲读取某一个块时,Cache会把CPU送来的地址与Cache中的所有地址标签进行对比。由于是完全对比,因此存取时间最长,但失误率也最低。
3:结合映射
这种映射方式是把Cache分成若干个页面,每个页面会有相同数目的块。主内存中数据块可以映射到Cache中指定页面的任一块中。这种映射方式可以看成是直接映射与完全映射的折衷,是效率最高的映射方式。
由上可见,结合映射方式最为理想,也是应用最为广泛的映射方式。但由于Cache的容量比主内存要小得多,因此无论采用何种映射方式,失误都在所难免。由于当CPU的存取出现“失误”时,必须从主内存把相应的块地址与数据写入Cache中,若此时Cache已经饱和,写入的数据必然会覆盖掉Cache中原有的数据,这就是“块替代”。那么,采用何种块替代方式可以最大限度的减低失误率呢?可以采用的方式又是什么呢?是这么三种:
1.先入先出,新写入的块取代最先存放到Cache中的旧块。
2.随机替代,新写入的块随机地取代Cache中的旧块。
3.最近、最不常用替代方式(LRU,Least Recent Used),新写入的块将取代Cache中最少被CPU访问的旧块。
不难看出,第三种方式的效率最高,能有效地降低失误率,因此这也是目前大多数Cache所采用的块替代方式。此外,在CPU的读取操作中,Cache中的数据与主内存上的数据是一致的。但是当CPU向Cache写入新的数据时,则会出现Cache与主内存之间数据不一致的情况。解决的方法有两种:1.写通(Write through)
当CPU向Cache写入数据时,同时也把数据写入主内存,或同时把数据写到一个缓冲器中,待CPU空闲时再把数据写入主内存。此方式简单可靠,但由于CPU每次写入数据时都要同时对主内存的相应数据进行刷新,因而速度较慢。
2.写回(Write back)
当CPU要进行写入操作时,只把数据写入Cache,而不直接写入主内存。这时,Cache与主内存之间会出现暂时不一致的数据块。当Cache中的不一致数据块将要被替代时,再把数据写回主内存,从而使Cache中的数据与主内存中的数据又再保持一致。在此方式下,需要在Cache中加入一个控制位(Dirty bit),若Cache中的某数据块是由CPU写入的,则控制位=1,否则控制位=0。发生块替代时,Cache先检查被替代块的控制位,若控制位=0,则无需把内容写回主内存,若控制位=1,则执行写回操作。这样做的好处是当CPU多次刷新同一数据块时,只需把最后的结果写回主内存即可,从而避免了重复写入,因而具有较高的效率。在早期版本的BIOS中,用户还可以对采用写通方式还是写回方式进行设置,但在新版本的BIOS中已取消了这一设置。
以上数据写入都是由CPU执行的,但若是DMA的系统,由于其它设备也可能向主内存写入数据,这时同样会造成Cache中的数据与主内存数据不一致。所以,目前个人计算机系统大多采用了一种称为Non-Cacheable Block(非可Cache块)的解决方法。其原理是在主内存中开辟一块专门的区域,所有对内存直接进行写入操作的设备都只能把数据写入该区域。同时,该区域中的内容不会被写入Cache中,因此Cache中的数据与Non-Cacheable Block 中的数据互不干扰,也就不会发生不一致的情况。
注:DMI(Desktop Management Interface桌面管理接口)是用来让系统保存自身及外围设备相关资料的应用程序。通过DMI可以在操作系统级查询系统配置信息,而不用进入BIOS,包括CPU、内存、I/O扩充插槽等。DMI可以将上述资料存储在BIOS中的特定位置,也可以利用DMI对资料库中系统配置情况作出修改以适应不同环境的系统需求。主板上的BIOS会尽可能地收集系统信息,将它存在主板上Flash EPROM中一个4K的小块中,DMI可以恢复数据库中的系统信息―这个数据库叫作MIFD(Management Information Format Database)。该BIOS允许动态实时更新DMI信息,DMI还允许在手工加入BIOS时不能探测到如使用者姓名、销售商、计算机编号等信息。Flash EPROM与Flash ROM的作用相类似。
上面说明了Cache的工作方式。在实际应用中,还有异步与同步Cache之分,这也是高速缓存的工作方式。在异步Cache工作方式下,CPU每次访问Cache的开始时都需要额外消耗一个时钟周期来查找特征位。同步Cache则是把按地址进行查找的过程分配到两个以上的时钟周期上完成。在第一个时钟周期内,Cache先将地址存放到一个寄存器中,而在第二个时钟周期内,Cache再把把数据传送给CPU。由于地址已被保存在一个寄存器中,所以同步Cache可以在CPU读取前一次数据的同时接收下一个数据地址,而不必另花时间来接收附加地址。目前大多数主板所采用的同步Cache称为管道突发式(Pipelined burst)Cache。能更加快速地访问从内存中读取的连续数据。
Cache可分为L1 Cache与L2 Cache两部分。这也就是BIOS设置中的Internal Cache(内部Cache)与External Cache(外部Cache)。L1 Cache介于CPU与L2 Cache 之间,而L2 Cache 则介于L1 Cache与主板之间,上面所述的Cache就是前面的L2 Cache。
注:过去L1Cache已集成到CPU内部,而L2 Cache则焊接在主板上,早期的奔腾CPU已把L2 Cache集成在芯片上,这样L2 Cache将与CPU工作在同一频率上,从而实现了真正的零等待。但在奔腾 II中,Intel采用了既兼顾成本,又考虑性能的折衷方案:将CPU与L2 Cache分开,但又焊接在同一块电路板上,并一起封装,L2 Cache的工作频率是CPU主频的一半。这就是有人把奔腾Pentium II称为奔腾pro加MMX的原因。而奔腾赛扬(Celeron)处理器为降低成本,取消了芯片上的L2 Cache,因此有人把赛扬称为简装奔腾II。而在赛杨300A中,又加入了128K L2