谈谈如何避免不必要的Cache miss

高速缓存(Cache)是介于CPU和内存(DRAM)之间的一个缓冲区,Cache的介质一般是SRAM。从存储器金字塔可以看出:寄存器访问速度 > Cache访问速度 > 内存访问速度。

在Cache出现之前,由于CPU对寄存器的访问速度远远大于对内存的访问速度,导致CPU大部分时间都在等待内存的访问。为了解决这个问题就出现了Cache,由于Cache的访问速度介于寄存器和内存之间,平时数据先从内存搬到Cache,然后CPU就通过Cache访问数据,如果数据不在Cache中,就会发生Cache miss,然后再从内存中把数据搬到Cache,所以Cache消除了寄存器和内存之间的访问速度的鸿沟。

问题1:既然Cache比内存好,为什么不全部用Cache代替内存呢?
答:因为内存有个悖论:内存越大越便宜的话,访问速度就越慢;要想访问速度快且便宜,那么容量就小。所以一般主内存的容量都很大,而Cache的容量都很小,它们的大小不对称就带来了Cache miss的问题。

问题2:既然Cache比内存小很多,那如果经常发生Cache miss,那性能岂不是比没加Cache还要糟糕吗?
答:如果经常发生Cache miss,那性能是要更糟糕,但是一般情况下不会发生这个情况,因为程序存在局部性原理。

计算机程序倾向于其他最近引用过的数据项,或者邻近于最近自我引用过的数据项,这种倾向性被称为局部性原理。局部性通常包含时间局部性和空间局部性。时间局部性指的是被引用过一次的存储器地址很可能在不久的将来再被多次引用;空间局部性指的是如果一个存储器地址被引用了一次,那么程序很可能会接下来引用附近的一个存储器地址。正因为程序的这种局部性原理,才让Cache的引入成为可能。

一个局部性良好的程序就会出现很少的Cache miss,程序性能就好,反之亦反。所以今天的题目:如何避免不必要的Cache miss,就转变成以下这个问题:
问题3:我们如何才能编写出具有良好局部性的程序呢?
答:通过观察,以下的行为具有良好的局部性:

  1. 重复引用同一个变量的程序具有良好的时间局部性
    一般程序不会只使用一个变量,所以这里可以引申为一旦从存储器中读入一个数据对象(变量、结构体、类对象),就尽可能多的集中使用它,防止在多个数据对象之间长间隔的来回交替访问;
  2. 连续的地址访问或者小步长间隔的地址访问具有良好的空间局部性
    按照数据对象存储在存储器中的地址顺序来操作数据,从而提高程序的空间局部性;
  3. 循环具有良好的时间和空间局部性
    循环体里面尽量处理连续地址空间的数据,避免进行数组的列扫描;
  4. 对单线程程序来说,要做到Cache line对齐
    Cache是以Cache line为最小单元进行数据加载的,一般Cache line为64字节或者128字节;Cache的空间非常有限,所以在设计数据结构的时候让同步操作的几个数据对齐到一个Cache line里面,这样可以节省数据访问的Cache line个数,有效提高Cache空间的利用率;如下所示:
    struct test {
      int a;
      int b;  
    }____cacheline_aligned;
    
  5. 在多线程竞争的场景下,要做到Cache line错开
    在多核CPU场景下,对多线程程序来说,最好让不同线程的访问数据错开在不同的Cache line里面,有助于减少多核间的Cache一致性同步开销;否则的话CPU1上的线程1在写数据a,CPU2上的线程2要访问数据同一个Cache line里的数据b,CPU2发现Cache line不一致了,所以会触发一个Cache line同步来保证数据跟其他核是一致的,如果经常发生这种一致性同步的话开销太大了;如果a和b错开在不同的Cache line就没有这个问题;如下所示:
    struct test {
      int a;
      int b ____cacheline_aligned; //让a和b错开在不同的Cache line
    }
    
  6. 在多核场景下,通过绑核也能提高Cache的命中率;
    多核架构的CPU的Cache往往又可以分为每核私有的Cache和所有核共享的Cache,如果不绑核的话,一个程序可能会经常在各个CPU之间切换,在切换的过程中经常发生Cache miss。如果程序只在某个CPU上运行的话,Cache的数据都在这个CPU的私有Cache,所以有效避免CPU切换带来的Cache miss;

总结

Cache的事情告诉我们做事情的时候也要利用好局部性原则,短时间内把一件事做完或者完成阶段性成果,然后再去做另一件事情,这样效率会更高一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值