美文网首页开发者内功修炼
你能估算出你的内存的访问延时吗?

你能估算出你的内存的访问延时吗?

作者: yanfeizhang | 来源:发表于2019-05-17 09:04 被阅读0次

    任何一个开发者都知道内存比磁盘访问要快,都会用内存去cache一些东西,代替更耗时的磁盘或网络IO。但是你的内存究竟有多快,你能告诉我一个具体的时间不?1ms,1us,还是1ns?如果只知道快,而不知道多快,我觉得这没有任何意义。

    具体case:给你一个内存条,通过命令查看到其Data Width为64,Speed为1066MHz。那么访问一次该内存要多长时间?
    错误答案:估计很多同学就觉得既然该内存的speed为1066Mhz,意思就是该内存在1s内可以工作1066M次。也就是说一次内存IO的耗时需要1s/1066M = 0.93ns。

    上面这个答案错误的原因是在于厂家在销售内存的时候,往往首先强调的是自己的主频是多少,而有意无意地少宣传其它几个参数。内存还有四个很重要的延迟参数:CL,tRCD,tRP和tRAS。这四个参数的更详细的含义如下:

    • CL:CAS Latency,纵向地址脉冲反应延迟。
    • tRCD:RAS to CAS Delay,行地址到列地址的延迟
    • tRP: RAS Precharge, 行地址控制器预充电延迟
    • tRAS:Act-to-Precharge Precharge Delay,行地址控制器激活时间

    虽然这四个参数都解释了一遍,但是估计大家还是看的云里雾里。那么我们再从内存IO的过程视角出发,就能有更清晰的认识了。

    FSB和QPI

    内存IO指的是CPU对内存进行数据读写的过程。那我们首先需要了解下两种重要的cpu和内存之间的连接方式:FSB和QPI。


    图1.FSB和QPI

    在FSB总线结构的计算机体系里,CPU通过FSB总线连接到北桥芯片,然后再连接到内存。Cpu和内存之间的通信全部都要通过这一条FSB总线来进行。QPI是一种点对点互联结构,各个CPU可以独立和自己的内存进行通信。
    所谓FSB也好,QPI也好,他们都是CPU和内存的桥接方式不同而已。由于我们本次文章的主要目的是让大家来了解CPU读取内存数据的过程,所以就以最简单的FSB来进行讨论了,QPI点到为止。实际上QPI的内存IO原理也类似,只不过砍掉了中心总线,这样CPU可以独立和自己内存IO了,总体上内存IO速度就上来了。但对于单条内存来讲,速度不会有任何变化。

    FSB下的内存IO

    再介绍内存IO之前,我们先介绍一组内存相关的参数。一般所有的内存条都会给自己标上CL-tRCD-tRP-tRAS这四个参数。其中比较重要的是CL-tRCD-tRP这三个参数,所有的在售内存都会将它们标出来(第四个参数有时候会被省略)。例如经典的DDR3-1066、DDR3-1333及DDR3-1600的CL值分别为7-7-7、8-8-8及9-9-9。现在京东上一条比较流行的台式机内存金士顿(Kingston)DDR4 2400 8G,其时序是17-17-17。以上参数的含义我们会在下面的IO过程总详细介绍。

    在FSB总线的体系结构里,获取到内存数据一个完整的过程如下:

    • 1 CPU需要把内存物理地址放到总线(1个CPU周期)
    • 2 FSB把地址传递给芯片组(1个CPU周期)
    • 3 芯片组对DRAM进行寻址,和数据的读取
    • 4 把读取完的数据放到总线上,供CPU读取(1个CPU周期)

    其中这里面比较耗时,和复杂的是第三步-芯片组根据CPU提供的物理地址对DRAM进行访问的过程。一个典型的访问过程如下图:


    图2.内存IO时序图
    • 内存模块首先要确定chip(物理可见的黑色颗粒)
    • 内存模块要经过tRAS个周期,使得该chip的行地址可以被选。
    • 接下来发送行地址到指定chip下所有的bank,经过tRCD个周期,RAM可以成功锁定到要请求的内存行,并把内存行copy到行缓存中。(在tRCD的周期内,芯片同时会进行列地址选通和给地址线上放列地址,但由于这两部操作是可以并行在tRCD内完成,所以在统计耗时的角度,一般就不说这两步了)
      图3.单bank视角访问过程
    • 接下来发送列地址指定chip下所有的bank,在CL个周期内,内存电路会在所有bank(8个)的rowbuffer中找到内存颗粒大小的数据(一般是8bit)。所有bank把数据汇总起来,就是一次64bit数据的结果。。然后就可以输出数据到数据针脚了。


      图4.多bank数据合并

    以上是描述的一个相对比较完整的内存寻址过程。 假如再上述一次完整的过程之后的下一次内存IO是连续的话(行地址没变,只有列地址变了),那么下一次的内存IO只需要CL个周期即可(当然,还要外加上CPU往FSB放数据,取数据的时间)。所以说,对于内存来讲,和硬盘类似,也存在顺序IO比随机IO速度要快的效果。

    题外话:对于连续的内存IO,除了第一个请求外,后面的tRAS,tRCD周期都是不需要的,只需要CL。有的内存厂家干脆就不在产品上标示出他们tRAS周期了,但是这个tRAS往往都比较大,感觉厂家有奸诈的嫌疑。

    FSB下的内存IO

    了解了内存硬件IO的具体过程,我们回到开篇的问题

    问题:每次从内存中获取1bit的数据究竟需要多长时间?这里我们得需要再加一些条件,内存的参数如下:工作频率1066MHz,延迟参数7-7-7-24。

    情景1:和上一次内存IO的行地址不一样,需要经历的步骤

    • CPU和FSB来通信( 1个内存周期)
    • FSB和内存芯片通信( 1个内存周期)
    • tRAS行地址选通 (24个内存周期)
    • 锁定行tRCD (7个内存周期)
    • CL列地址延迟 (7个内存周期)
    • 内存芯片放数据到FSB (1个内存周期)

    总共:41个内存周期*1s/1066Mhz = 38ns

    情景2:本次内存IO和前一次行地址相同

    • CPU和FSB来通信 (1个内存周期)
    • FSB和内存芯片通信 (1个内存周期)
    • CL列地址延迟 (7个内存周期)
    • 内存芯片放数据到FSB (1内存个周期)

    总共:10个内存周期*1s/1066Mhz = 9.3ns

    结论

    内存速度到底多快,这下相信你能给出量化的数据了。

    • 在不连续IO的情况下获取连续64字节需要大约40ns左右。这个速度其实并不快。
    • 在连续IO的情况下,这个耗时下降到10ns。
    • 即使是连续IO的10ns,对于CPU来说,仍然慢的不可忍。所以操作系统上会在一级缓存、二级缓存、三级缓存中分别把可能需要内存IO的数据cache起来。尽量去避免内存IO。要知道CPU的一级缓存可是可以做到1ns以内的延迟。

    所以、程序员们,多多写出局部性好的代码吧。首先局部性好的代码让你的内存更多地进行比随机IO更高效的连续IO。其次CPU的各级缓存也能帮助你极大地减少相对低效的内存IO。

    个人公众号“开发内功管理”,打通理论与实践的任督二脉。

    相关文章

      网友评论

        本文标题:你能估算出你的内存的访问延时吗?

        本文链接:https://www.haomeiwen.com/subject/ktdbaqtx.html