本主题的第一部分主要以TI C64x DSP为例介绍cache缓存的基本概念, 解释了为什么需要cache,cache如何和主内存进行通信以及如何优化cache的性能。第二部分主要介绍了怎么配置cache以及怎样正确的使用cache,即如何保证cache的一致性。其中有关于DMA的传输怎么影响cache以及怎么管理DMA传输的双缓存。关键字:C64x DSP Cache DMA L1P L1D 直接映射 set-associative; | |||||||||||
处理器的cache是一块存储靠近处理器数据的高速存储区。这帮助常用的指令和数据的快速访问从而提高计算性能。Cache可以视为平坦式记忆体,即认为cache是CPU靠近的可以很快访问的存储器,本篇主要是TI的C64x的处理器为例介绍cache的基本概念和cache的基本术语,接下来就是利用cache的特性来进行优化存储提高程序性能和数据吞吐率。 存储组织结构 图 1. 平坦和分层的存储架构
一个解决方法是使用分层的存储架构,有一个快速的靠近CPU的存储区,访问没有stall但是size很小,往外的内存空间很大,但是离CPU较远,访问需要比较大的stall,靠近CPU的存储区可以视为cache。 访问定位的规律
空间关联性揭示了计算机程序的创建规律:通常情况下相关的数据被编译链接到临近的连续区域。例如首先处理一个数组的第一个元素,然后处理第二个,这就是空间关联性。类似的,时间关联性主要源于程序中存在占用时间非常多的循环,通常循环的代码被连续执行非常多次,一般循环内访问的数据也相当。 图 2. 存储访问定位的规律
图3. C64x的两级cache的访问流程
当处理器从存储区请求数据访问时,首先在最高层次的cache内查找,然后再从次高级别的存储区查找。当请求在cache内时就是cache命中,否则是一次cache miss。因而Cache系统的性能将取决于cache命中的比率。对于任意级别的cache,命中率越高性能越好。比如一个内存访问的L1 cache命中率为70%,L2 20%, 其他来自L3,那么以图3所示的性能下,平均一次内存的访问时间为 (0.7 * 4) + (0.2 * 5) + (0.05 * 30) + (0.05 * 220) = 16.30 ns
考虑图4所示的TI TMS320C64x DSP的存储架构,两级的片内cache加上片外外存。一级Cache分成程序(L1P)和数据(L1D) cache,每个容量为16 Kbytes。L1缓存数据访问不会有存储stall。L2存储区分成L2 SRAM和L2 cache,无论是哪种配置,L2存储区都需要两个CPU周期完成一次数据访问。不同的DSP,L2的容量不同,如TMS320C6454 DSP,L2的大小为1Mbytes。最后是C64x DSP最大高达2GBytes的外存,外存的访问速度取决于使用的存储器类型,但一般外存的频率在100 MHz左右。图4中的所有的cache(红色)和数据通路都由cache控制器自动维护。 图 4 TMS320C64x Cache结构
图 5. 直接映射Caches.
为了保存从外存拷贝的数据信息,每个L1P的cache行包含如下信息:
当CPU开始访问地址0020h时,假设cache已经被完全被设定无效了(invalidated),即没有cache line包含有效数据。此时cache控制器开始根据当前地址的组(即地址的第5到13比特)来看对应的哪个cache line。对于地址0020h来说是cache line 1.然后cache控制器检查line 1的标签位,确认其是否对应于地址0020h到0039h,最后检查有效位,发现其值为0,即该地址的数据并不在cache内,此时cache控制器标记一次cache miss。这次的miss让控制器从外存加载整个cache line(0020h-0039h),同时更新标签tag位,并把有效位设置为1,同时加载的数据传递给CPU,此次数据访问结束。 当还需要继续访问地址0020h时,cache控制器会继续检查组号和标签域,并和存在标签RAM的值比较,同时有效位的值为1,意味着此次是一个cache hit。 组相关Set-associate caches
组级联的cache是直接映射cache的扩展,在直接映射的cache内,每个组只包含一个cache line,而组级联的cache则包含若干个行,被称为"ways."。图6是C64x DSP的L1D cache,一个2-way组级联cache。每个line 64字节,供16Kbytes容量。
图 6. 组关联(Set-associative Caches).
上述代码的性能并不高因为数据访问的跨度较大,这也就意味着当前cache line的数据被重用的可能性降低。
表2. 滤波器长度和cache效率
起始,算法的循环buffer为空,分配在L1D,用输入数据从L2空间来填充,一个填充的方法是使用预加载(pre-fetch,pre-load)函数来加载需要用到的数据。表3是使用预加载函数来进行优化得到的cache性能和不预加载的性能比较。 表3. 数据预加载能有效提高cache的效率
数据代码的组织
前面的FIR滤波器的例子里,输入数据是连续的,但是有些函数并不能原生的连续访问数据,连续访问的可能是间隔很远的两个数据,如矩阵乘法和用一个查找表进行数据调整的交织器。输入数据的随机读取,输出数据则是顺序存放。这些乱序的输入数据的读取会造成cache的颠簸,即反复的cache清除和重新访问。因此合理的组织该查找表让读连续而写乱序,因为L1D是read-allocated的,因而不会频繁的更新cache,而写数据可以直接被灌入L2。这种组织方式把cache的效率从60%提高到85%。
避免L1P的冲突conflict misses
面提到了怎么重新组织数据来提高cache的效率,类似的还有合理的代码放置会提高L1P的性能。改变函数在链接时的次序来调整函数在内存的位置。表4是一个把短时内需要连续调用的函数放置在连续内存的例子。
表4. 一个访问函数的例子 假设函数function_1和function_2在L2空间是交叠的,如图7所示。当调用function_1时,它会被分配到L1P (1)。后续的调用function_2会导致它的代码分配到L1P (2).而这部分的代码映射和function_1有冲突,那么当下一次迭代需要继续读function_1时,就会发生重新把function_1的代码加载到L1P的颠簸。这种形式的cache miss完全可以通过重新安排程序代码在内存的分配排序来避免。 图7. 不合理的代码内存分配会导致L1P cache miss 算法分割与函数组合 图8. 视频缩放函数的数据流程图
每个色彩被分成2个数据缓冲区,以亮度Y分量为例,有BufY0a和BufY0b。buffer内的数据先进行边界扩展, 结果保存到BufY1,然后调用scale_horz进行水平方向的缩放,中间结果保存到RotBufY2,再调用scale_vert进行垂直反向的缩放,结果放在Buf_Y3,最后把各个分量的组合成输出到L2空间。 除了对代码和数据进行分割外,还可以针对相同数据进行处理的算法进行组合到同一片内存区域。例如针对Y分量进行操作的函数放在同一片相邻的内存区域,同样,还可以把Y分量的数据buffer放在临近的数据空间。 通过数据和代码的分割以及函数的组合,你可以把cache的有效率提高到90%以上,即大部分的数据和代码的访问都在cache内完成的。 使用系统优化技术
图9所示的是一个复数和9个输入复数向量的点积比较。前面提到,像点积这种算法是不会重用输入数据的,总是对每个输入样点采取很少的操作,然后就把数据存储起来,这种很少的操作往往需要很少的时间运行,而为了提高数据的重用,应该让一段数据做尽可能多的操作之后再保存到存储空间。如图9中的针对复数向量的简单运算的cache有效率仅为79%,如果采用系统级的优化策略,进行合理的函数功能划分把针对同一块数据的操作组合,cache的有效率能提高到93%.
图9. 复数向量的引用
关键字:C64x DSP Cache DMA L1P L1D 直接映射 set-associative; 本主题的第一部分主要以TI C64x DSP为例介绍cache缓存的基本概念, 解释了为什么需要cache,cache如何和主内存进行通信以及如何优化cache的性能。第二部分主要介绍了怎么配置cache以及怎样正确的使用cache,即如何保证cache的一致性。其中有关于DMA的传输怎么影响cache以及怎么管理DMA传输的双缓存。 |
如何优化使用C6000系列C64x的Cache--原理,Cache种类和优化策略
最新推荐文章于 2024-01-18 03:00:00 发布