大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > C技巧 > 充分利用CPU高速缓存,提高程序效率(原理篇)

充分利用CPU高速缓存,提高程序效率(原理篇)(1)

关键词:高速缓存效率  阅读(3191) 赞(20)

[摘要]本文是对充分利用CPU高速缓存,提高程序效率(原理篇)的讲解,与大家分享。

  提高程序效率应该充分利用CPU的高速缓存。要想编写出对CPU缓存友好的程序就得先明白CPU高速缓存的运行机制。

 i5-2400S:

      1、有三级缓存分别为 32k(数据、指令缓存分开,分为32k),256K,6144K(四个CPU之间共享);

      2、主频为2.5G,则一个时钟周期为1/2.5x10^9=0.4ns(主频=1/时钟周期)。

 CPI:

  CPU中每条指令执行所需的机器周期不同CPI:平均每条指令的平均时钟周期个数,注:一个机器周期等于若干个时钟周期,如一个机器周期等于5个时钟周期

 MIPS:

  MIPS = 每秒执行百万条指令数 = 1/(CPI×时钟周期)= 主频/CPI,通过 cat /proc/cpuinfo | grep bogomips 命令可以查看linux系统的mips,对于i5-2400s CPU 其mips=4988.85

从而我们可以算出平均执行一个指令所需时间 T = 1/(4988.85x10^6)=0.2ns,注意:每个CPU时钟内可并行处理多条指令。

 内存体系:

  核心到主存的延迟变化范围很大,大约在10-100纳秒。在100ns内,一个2.5GH的CPU可以处理多达100/T=500条指令,所以CPU使用缓存子系统避免了处理核心访问主存的时延,从而使CPU更加高效的处理指令。所以在程序设计中提供程序高速缓存的命中率对于程序性能的提高帮助很大。尤其是要着重考虑主要数据结构的设计。

  Cache概述,一下转自博文:http://www.cnblogs.com/liloke/archive/2011/11/20/2255737.html

 

1. cache概述

cache,中译名高速缓冲存储器,其作用是为了更好的利用局部性原理,减少CPU访问主存的次数。简单地说,CPU正在访问的指令和数据,其可能会被以后多次访问到,或者是该指令和数据附近的内存区域,也可能会被多次访问。因此,第一次访问这一块区域时,将其复制到cache中,以后访问该区域的指令或者数据时,就不用再从主存中取出。

2. cache结构

假设内存容量为M,内存地址为m位:那么寻址范围为000…00~FFF…F(m位)

倘若把内存地址分为以下三个区间:

截图01《深入理解计算机系统》p305 英文版 beta draft

tag, set index, block offset三个区间有什么用呢?再来看看Cache的逻辑结构吧:

截图02

将此图与上图做对比,可以得出各参数如下:

B = 2^b

S = 2^s

现在来解释一下各个参数的意义:

一个cache被分为S个组,每个组有E个cacheline,而一个cacheline中,有B个存储单元,现代处理器中,这个存储单元一般是以字节(通常8个位)为单位的,也是最小的寻址单元。因此,在一个内存地址中,中间的s位决定了该单元被映射到哪一组,而最低的b位决定了该单元在cacheline中的偏移量。valid通常是一位,代表该cacheline是否是有效的(当该cacheline不存在内存映射时,当然是无效的)。tag就是内存地址的高t位,因为可能会有多个内存地址映射到同一个cacheline中,所以该位是用来校验该cacheline是否是CPU要访问的内存单元。

当tag和valid校验成功是,我们称为cache命中,这时只要将cache中的单元取出,放入CPU寄存器中即可。

当tag或valid校验失败的时候,就说明要访问的内存单元(也可能是连续的一些单元,如int占4个字节,double占8个字节)并不在cache中,这时就需要去内存中取了,这就是cache不命中的情况(cache miss)。当不命中的情况发生时,系统就会从内存中取得该单元,将其装入cache中,与此同时也放入CPU寄存器中,等待下一步处理。注意,以下这一点对理解linux cache机制非常重要:

当从内存中取单元到cache中时,会一次取一个cacheline大小的内存区域到cache中,然后存进相应的cacheline中。

例如:我们要取地址 (t, s, b) 内存单元,发生了cache miss,那么系统会取 (t, s, 00…000) 到 (t, s, FF…FFF)的内存单元,将其放入相应的cacheline中。

下面看看cache的映射机制:

当E=1时, 每组只有一个cacheline。那么相隔2^(s+b)个单元的2个内存单元,会被映射到同一个cacheline中。(好好想想为什么?)

当1<E<C/B时,每组有E个cacheline,不同的地址,只要中间s位相同,那么就会被映射到同一组中,同一组中被映射到哪个cacheline中是依赖于替换算法的。

当E=C/B,此时S=1,每个内存单元都能映射到任意的cacheline。带有这样cache的处理器几乎没有,因为这种映射机制需要昂贵复杂的硬件来支持。

不管哪种映射,只要发生了cache miss,那么必定会有一个cacheline大小的内存区域,被取到cache中相应的cacheline。

现代处理器,一般将cache分为2~3级,L1, L2, L3。L1一般为CPU专有,不在多个CPU中共享。L2 cache一般是多个CPU共享的,也可能装在主板上。L1 cache还可能分为instruction cache, data cache. 这样CPU能同时取指令和数据。

下面来看看现实中cache的参数,以Intel Pentium处理器为例:

E B S C
L1 i-cache 4 32B 128 16KB
L1 d-cache 4 32B 128 16KB
L2 4 32B 1024~16384 128KB~2MB

3. cache miss的代价

cache可能被分为L1, L2, L3, 越往外,访问时间也就越长,但同时也就越便宜。

L1 cache命中时,访问时间为1~2个CPU周期。

L1 cache不命中,L2 cache命中,访问时间为5~10个CPU周期

当要去内存中取单元时,访问时间可能就到25~100个CPU周期了。

所以,我们总是希望cache的命中率尽可能的高。

«上一页12下一页»


相关评论