乐趣区

关于linux:内存随机访问也比顺序慢带你深入理解内存IO过程

平时大家都晓得内存拜访很快,明天来让咱们来把刨根问底的精力施展到极致,来思考两个问题

问题 1: 内存拜访延时到底是多少?你是否会进行大略的估算?
例如笔者的内存条的 Speed 显示是 1066MHz,那是否能够推算出内存 IO 延时是 1s/1066MHz=0.93ns?
这种算法大错特错。

问题 2: 内存存在随机 IO 比程序 IO 慢的问题吗?
咱们都晓得磁盘的随机 IO 要比程序 IO 慢的多(操作系统底层还专门实现了电梯调度算法来缓解这个问题),那么内存的随机 IO 会比程序 IO 慢吗?

要想彻底弄明确以上两个问题,我想咱们得从内存 IO 的物理过程中来寻找答案。

先给你讲个图书管理员的故事

在开始介绍干燥的内存工作原理之前。我想先给你讲一个故事,并带你去意识一个人,图书馆的管理员。

在咱们的这个故事中,你是故事的配角。你有一所房子,房子里有一个佣人,他每天帮你解决各种各样的图书数据。然而北京房价太贵,所以你的这个房子很小,只能放的下 64 本书。你家的马路对面,就是北京图书馆(你家房子尽管小然而地段还不错),你所须要的所有的图书在那里都能够找到。图书馆有个管理员,他负责帮你把你想要的书找进去。

好接下来,导演喊了 action,场景开始!

  • 场景 1:

你发现你须要编号为 0 的书的计算结果,你的佣人穿过马路通知了图书管理员,通知他请帮我把第 0 -63 本书取出来。图书管理员帮你在电脑前查得该书在二楼。于是他,花了点工夫坐电梯到了二楼。等到了二楼,他又花了点工夫帮你找了进去。而后你的佣人抱着 64 本书放到了客厅,拿起第 0 本书帮你解决了起来。

  • 场景 2:

你发现你须要编号为 1 的书的计算结果,通知你的佣人。你的佣人间接从客厅拿进去就能够解决了,这次你等的工夫最短。

  • 场景 3:

你发现须要编号为 65 的书,你又通知你的佣人。你的佣人穿过马路又去找了图书管理员。图书管理员还在二楼呢,据说这次须要 65-127,这次他不必再花工夫找楼层了。只是花工夫找书就能够了。你的佣人把 65-127 的书放到了客厅(以前的 0 -63 就都扔了),并帮你开始解决起 65 号书来。

  • 场景 4:

你发现你须要编号为 10000 的书,你通知了你的佣人。你的佣人穿过马路去图书馆,找到了管理员。这次管理员查得你须要的书是在 10 楼,他得花点工夫坐电梯过来。去了之后,他又得花点工夫帮你找进去。

这四个场景里,我感觉你肯定发现了不同情景下耗时的差别。

  • 场景 1 和场景 4 破费的工夫最多。因为图书管理员须要花工夫坐电梯找楼层,须要花工夫在楼内找书。
  • 场景 3 次之,因为图书管理员间接就在楼层内,只须要花工夫在楼内找书既可
  • 场景 2 最快,因为只须要佣人帮你从客厅拿过去就好,连马路都不须要过。

之所以假造这么一个例子,是因为内存的工作形式和它太像了。接下来咱们进入内存的理论剖析。

内存的物理构造

在《带你了解内存对齐最底层原理!》中咱们理解了内存颗粒的物理结构以及 IO 过程,明天咱们再来温习一下。

内存是由 chip 形成。每个 chip 外部,是由 8 个 bank 组成的。其结构如下图:

而每一个 bank 是一个二维立体上的矩阵,后面文章中咱们说到过。矩阵中每一个元素中都是保留了 1 个字节,也就是 8 个 bit。

每当 CPU 向内存申请数据的时候,内存芯片总是 8 个 bank 并行一起工作。每个 bank 在定位到行地址后,把对应的行 copy 到 row buffer。再依据列地址把对应的元素中的数据取出来,8 个 bank 把数据拼接一下,一个 64 位宽的数据就能够返回给 CPU 了。

依据下面几张图咱们能够大抵理解内存的 IO 过程,在这个过程中每一步操作之间都有一些提早,让咱们来持续理解这些提早。

内存 IO 提早

在《从 DDR 倒退到 DDR4,内存外围频率指标其实基本上就没太大的提高。》里的结尾处,你应该记得咱们提到了内存有 CL-tRCD-tRP-tRAS 四个参数。咱们明天来具体了解一下这四个参数的含意:

  • CL(Column Address Latency):发送一个列地址到内存与数据开始响应之间的周期数
  • tRCD(Row Address to Column Address Delay):关上一行内存并拜访其中的列所需的最小时钟周期数
  • tRP(Row Precharge Time):收回预充电命令与关上下一行之间所需的最小时钟周期数。
  • tRAS(Row Active Time):行流动命令与收回预充电命令之间所需的最小时钟周期数。也就是对下一次预充电工夫进行限度。

要留神除了 CL 是固定周期数以外,其它的三个都是最小周期。另外下面的参数都是以时钟周期为单位的。因为古代的内存都是一个时钟周期高低沿别离各传输一次数据,所以用 Speed/ 2 就能够得出,例如笔者的机器的 Speed 是 1066MHz,则时钟周期为 533MHz。你本人的机器能够通过 dmidecode 命令查看:

# dmidecode | grep -P -A16 "Memory Device"  
Memory Device   
        ......
        Speed: 1067 MHz  
        ......

和“图书管理员”相似,内存芯片也有相似的工作场景:

  • 场景 1:

你的过程须要内存地址 0x0000 为的一个字节的数据,CPU 这时候向内存控制器发出请求,内存控制器进行行地址的预充电,须要期待 tRP 个时钟周期。再收回关上一行内存的命令,又须要期待 tRCD 个时钟周期。接着发送列地址,再期待 CL 个周期。最终将 0x0000-0x0007 的数据全副返回给了 CPU。CPU 把这些数据放入到了本人的 cache 里,并帮你开始对 0x0000 的数据进行运算。

  • 场景 2:

你的过程须要内存地址 0x0003 的一个字节数据,CPU 发现发现它在本人的 cache 里存在,间接应用就好了。这个场景里其实基本就没有内存 IO 产生。

  • 场景 3:

你的过程须要内存地址 0x0008 的一个字节数据,CPU 的 cache 并没有命中,于是向内存控制器申请。内存控制器发现行地址和上一次工作的行地址统一,这次只须要发送列地址后期待 CL 个周期,就能够拿到 0x0008-0x0015 的数据并返回给 CPU 了。

  • 场景 4:

你的过程须要内存地址 0xf000 的一个字节数据,同样 CPU 的 cache 并不命中,向内存控制器申请。内存控制器一看(心田有些许的郁闷),这次行地址又变了,得,和场景 1 一样。持续期待 tRP+tRCD+CL 个周期后,才可能取到数据并返回。

理论的计算机的内存 IO 过程中还须要进行逻辑地址和物理地址的转换,这里疏忽不表。

论断

其中场景 1 和场景 4 是随机 IO 的状况,场景 2 无内存 IO 产生,场景 3 是程序 IO,。通过下面的过程形容咱们能够失去论断。内存也存在和磁盘一样,随机 IO 比程序 IO 要慢的问题。如果行地址同上一次拜访的不统一,则须要从新拷贝 row buffer,提早周期须要 tRP+tRCD+CL。而如果是程序 IO 的话(行地址不变),只须要 CL 个周期既可实现。

咱们接着估算下内存的延时, 笔者的机器上的内存参数 Speed 为 1066MHz(通过 dmidecode 查得),该值除以 2 就是时钟周期的频率 =1066/2=533Mhz。其提早周期为 7 -7-7-24。

  • 程序 IO

这种情况下须要 tRP+tRCD+CL 个时钟周期,7+7+7=21 个周期。然而还有个 tRAS 的限度,两次行地址预充电不得小于 24。所以咱们得按 24 来计算,24*(1s/533Mhz) = 45ns

  • 随机 IO

这种情况下只须要 CL 个时钟周期 7\*(1s/533Mhz)=13ns

扩大:回顾 CPU 的 Cache Line

因为对于内存来说,随机 IO 一次开销比程序 IO 高好几倍。所以操作系统在工作的时候,会尽量让内存通过程序 IO 的形式来进行。做法要害就是Cache Line。当 CPU 发现缓存不命中的时候,实际上从来不会向内存去申请 1 个字节,8 个字节这种。而是一次性就要 64 字节,而后放到本人的 Cache 中存起来。

用下面的例子来看,

  • 如果随机申请 8 字节:耗时是 45ns
  • 如果随机申请 64 字节:耗时是 45+7\*13 = 136ns

开销也没贵多少,因为只有第一个字节是随机 IO,前面的 7 个字节都是程序 IO。数据是 8 倍,然而 IO 耗时只有 3 倍,而且取出来的数据前面大概率要用,所以计算机外部就这么搞了,通过这种形式帮你防止一些随机 IO!

另外,内存也反对 burst(突发传输)模式,在这种模式下能够只传入一次行列地址,就命令内存返回该内存结尾的间断字节数据,比方 64 字节。这种模式下,只有第一次的 8 字节须要真正的行列拜访提早,前面的 7 个字节能够间接按内存的数据频率给吐出来,耗时更短。



开发内功修炼之内存篇专辑:

  • 1. 带你深刻了解内存对齐最底层原理
  • 2. 内存随机也比程序拜访慢,带你深刻了解内存 IO 过程
  • 3. 从 DDR 到 DDR4,内存外围频率其实基本上就没太大的提高
  • 4. 理论测试内存在程序 IO 和随机 IO 时的拜访延时差别
  • 5. 揭穿内存厂家“谎话”,实测内存带宽实在体现
  • 6.NUMA 架构下的内存拜访提早区别!
  • 7.PHP7 内存性能优化的思维精华
  • 8. 一次内存性能晋升的我的项目实际
  • 9. 挑战 Redis 单实例内存最大极限,“遭逢”NUMA 陷阱!

我的公众号是「开发内功修炼」,在这里我不是单纯介绍技术实践,也不只介绍实践经验。而是把实践与实际联合起来,用实际加深对实践的了解、用实践进步你的技术实际能力。欢送你来关注我的公众号,也请分享给你的好友~~~

退出移动版