6.4.6 C语言例子

6.4.6 C语言例子

下面通过分析两个C语言的程序段来分析一下高速缓存的工作效率:

程序段1:

程序段2:

在程序段1和程序段2中,M=1024、N=16,假定数组元素按行优先方式存放在主存中,主存大小为256 MB,Cache大小为4 KB,按字节编址,主存与Cache交换的块大小为64B,采用直接映射方式且Cache初始为空。则主存有4MB(222)个块,Cache有64(26)个块,主存有64KB(216)个区。现只考虑数据的存放不考虑指令的存放,每个数组元素占4个字节,数组X 在主存中的首地址为0,则数组存放在了主存中的第0~1023 块,如图6.31所示。

分析程序段1,由于Cache初始为空,故X[0][0]不在Cache中,此时在Cache中不命中,需要从主存中调,把主存中含X[0][0]的数据块调入Cache中,即数据X[0][0]~X[0][15]被调入Cache中的第0块。根据程序段1,下一个要访问的数据是X[0][1],而此数据恰好已经被调入了Cache,故在Cache中命中,直到数据X[0][14]都在Cache中命中,数据X[1][0]是第一次被访问且没有在Cache中,故在Cache中不命中,需要从主存中调块,依次类推。当主存的第64个块被调入Cache时,根据映射规则,需要将其放到Cache中的第0块,而此时这个块内不为空,需要把该块中的数据替换(映射情况如图6.31所示)。计算得到Cache的命中率为15/16,即93.75%。

分析程序段2,X[0][0]的访问同程序段1。但是下一个要访问的数据不是X[0][1],而是X[1][0],此时访问顺序不同于存储顺序;X[1][0]还没有被取到Cache中,所以此数据在Cache中不命中,依次类推,会发现,每个数据在Cache中都不命中,而包含需要访问的数据的数据块被调入Cache后,该块中的其他数据又没有被访问过,Cache的命中率为0。该程序以64个字节的跨距访问存储器,局部性不好。很明显能看出,不同的程序可以实现相同的功能,但Cache命中率会差距很大,也就会造成程序的执行时间差距很大。该程序以100个字节的跨距访问存储器,局部性不好。

图6.31 主存中数据的存储及映射到Cache的情况

为了简单地说明问题,举的例子是比较极端的情况,本例主存和Cache交换数据块大小正好是数组一行的数据;其他情况结果可能没有这么悲观(Cache的命中率可能会高一些)。

再看程序段3和程序段4,实现的功能是一样的,但是程序结构不同,程序执行时间也不同。

程序段3在对矩阵的每个元素分别作了乘2运算后,把每个元素累加,由于主存Cache的映像关系,在做完乘2运算后,Cache中的数据是x[959][0]-x[1023][15]中的数据,累加开始的时候Cache不命中,需要重新到主存中取。而程序段4在每个元素乘2后马上做累加,每个元素的被充分利用,提高了局部性,提高了Cache的命中率。

程序段3:

程序段4: