概述
- CPU的Cache是一种又小又快的存储器,现在一般的cpu主流的cache是用sram,因为CPU的性能比Memory快得多,所以使用cache来拟补之间的差距
计算机系统中,CPU高速缓存是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。
当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据;如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。
缓存之所以有效,主要是因为程序运行时对内存的访问呈现 局部性(Locality)特征。这种局部性既包括 空间局部性(Spatial Locality),也包括 时间局部性(Temporal Locality) 。有效利用这种局部性,缓存可以达到极高的命中率。
在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。
cache miss的代价
在线主流的CPU中一般分为3级缓存,分别是L1,L2,L3,
- L1缓存分为L1i(存储指令)和L1d(存储数据) L1缓存较小
- L2,它不分指令和数据
- L3,L3是最大的是所有核心公用的
cache被分为L1, L2, L3, 越往外,访问时间也就越长,但同时也就越便宜。
L1 cache命中时,访问时间为1~2个CPU周期。
L1 cache不命中,L2 cache命中,访问时间为5~10个CPU周期
当要去内存中取单元时,访问时间可能就到25~100个CPU周期了。
所以,我们总是希望cache的命中率尽可能的高。
Cache Line
CacheLine 是CPU高速缓存中的最小单位
当从内存中取单元到cache中时,会一次取一个cacheline大小的内存区域到cache中,然后存进相应的cacheline中。
Cache友好的代码
- 减小cache miss率
- 在多核环境下,减小乃至消除“伪共享”问题发生的概率。
cache友好代码:
int sumarrayrows(char a[M][N])
{
int i, j, sum = 0;
for (i = 0; i < M; i++)
for (j = 0; j < N; j++)
sum += a[i][j];
return sum;
}
- 由于一般的机器中,C语言数组都是按行优先存储的。
cache不友好代码:
int sumarraycols(char a[M][N])
{
int i, j, sum = 0;
for (j = 0; j < N; j++)
for (i = 0; i < M; i++)
sum += a[i][j];
return sum;
}
- 这个代码是按列优先访问的,情况要复杂一些。