关于linux:TLB缓存是个神马鬼如何查看TLB-miss

6次阅读

共计 2725 个字符,预计需要花费 7 分钟才能阅读完成。

介绍 TLB 之前,咱们先来回顾一个操作系统里的基本概念,虚拟内存。

虚拟内存

在用户的视角里,每个过程都有本人独立的地址空间,A 过程的 4GB 和 B 过程 4GB 是齐全独立不相干的,他们看到的都是操作系统虚构进去的地址空间。然而呢,虚拟地址最终还是要落在理论内存的物理地址上进行操作的。操作系统就会通过页表的机制来实现过程的虚拟地址到物理地址的翻译工作。其中每一页的大小都是固定的。这一段我不想介绍的太过于具体,对这个概念不相熟的同学回去翻一下操作系统的教材。

页表治理有两个关键点,别离是页面大小和页表级数

  • 1. 页面大小

在 Linux 下,咱们通过如下命令能够查看到以后操作系统的页大小

# getconf PAGE_SIZE
4096  

能够看到以后我的 Linux 机器的页表是 4KB 的大小。

  • 2. 页表级数

    • 页表级数越少,虚拟地址到物理地址的映射会很快,然而须要治理的页表项会很多,能反对的地址空间也无限。
    • 相同页表级数越多,须要的存储的页表数据就会越少,而且能反对到比拟大的地址空间,然而虚拟地址到物理地址的映射就会越慢。

32 位零碎的虚拟内存实现:二级页表

为了帮忙大家回顾这段常识,我举个例子。如果想反对 32 位的操作系统下的 4GB 过程虚拟地址空间,假如页表大小为 4K,则共有 2 的 20 次方页面。如果采纳速度最快的 1 级页表,对应则须要 2 的 20 次方个页表项。一个页表项如果 4 字节,那么一个过程就须要(1048576*4=)4M 的内存来存页表项。
如果是采纳 2 级页表,如图 1,则创立过程时只须要有一个页目录就能够了,占用 (1024*4)=4KB 的内存。剩下的二级页表项只有用到的时候才会再去申请。

64 位零碎的虚拟内存实现:四级页表

当初的操作系统须要反对的可是 48 位地址空间(实践上能够反对 64 位,但其实当初只反对到了 48 位,也足够用了),而且要反对成千盈百的过程,如果不采纳分级页表的形式,则创立过程时就须要为其保护一个 2 的 36 次方个页表项(64 位 Linux 目前只应用了地址中的 48 位的,在这外面,最初 12 位都是页内地址,只有前 36 位才是用来寻找页表的),2^36 *4Byte=32GB,这个更不能忍了。也必须和 32 位零碎一样,进一步提高页表的级数。

Linux 在 v2.6.11 当前,最终采纳的计划是 4 级页表,别离是:

  • PGD:page Global directory(47-39), 页全局目录
  • PUD:Page Upper Directory(38-30),页下级目录
  • PMD:page middle directory(29-21),页两头目录
  • PTE:page table entry(20-12),页表项

这样,一个 64 位的虚拟空间,初始创立的时候只须要保护一个 2^9 大小的一个页全局目录就够了,当初的页表数据结构被扩大到了 8byte。这个页全局目录仅仅须要 (2^9 *8=)4K,剩下的两头页目录、页表项只须要在应用的时候再调配就好了。Linux 就是通过这种形式反对起 (2^48 =)256T 的过程地址空间的。

页表带来的问题

下面终于吃力扒了半天 Linux 虚拟内存的实现,我终于能够开始说我想说的重点了。
尽管创立一个反对 256T 的地址空间的过程在初始的时候只须要 4K 的页全局目录, 然而,这也带来了额定的问题,页表是存在内存里的。那就是一次内存 IO 光是虚拟地址到物理地址的转换就要去内存查 4 次页表,再算上真正的内存拜访,最坏状况下须要 5 次内存 IO 能力获取一个内存数据!!

TLB 应运而生

和 CPU 的 L1、L2、L3 的缓存思维统一,既然进行地址转换须要的内存 IO 次数多,且耗时。那么罗唆就在 CPU 里把页表尽可能地 cache 起来不就行了么,所以就有了 TLB(Translation Lookaside Buffer),专门用于改良虚拟地址到物理地址转换速度的缓存。其访问速度十分快,和寄存器相当,比 L1 拜访还快。

我原本想理论看一下 TLB 的信息,但翻遍了 Linux 的各种命令,也没有找到像 sysfs 这么不便查看 L1、L2、L3 大小的办法。仅仅提供下图供大家参考吧!(谁要是找到了查看 TLB 的命令,别忘了分享给飞哥啊,谢谢!)

有了 TLB 之后,CPU 拜访某个虚拟内存地址的过程如下

  • 1.CPU 产生一个虚拟地址
  • 2.MMU 从 TLB 中获取页表,翻译成物理地址
  • 3.MMU 把物理地址发送给 L1/L2/L3/ 内存
  • 4.L1/L2/L3/ 内存将地址对应数据返回给 CPU

因为第 2 步是相似于寄存器的访问速度,所以如果 TLB 能命中,则虚拟地址到物理地址的工夫开销简直能够疏忽。如果想理解 TLB 更具体的工作机制,请参考《深刻了解计算机系统 - 第 9 章虚拟内存》

工具

既然 TLB 缓存命中很重要,那么有什么工具可能查看你的零碎里的命中率呢?还真有

# perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses -p $PID
 Performance counter stats for process id '21047':  

           627,809 dTLB-loads  
             8,566 dTLB-load-misses          #    1.36% of all dTLB cache hits  
         2,001,294 iTLB-loads  
             3,826 iTLB-load-misses          #    0.19% of all iTLB cache hits  

扩大

因为 TLB 并不是很大,只有 4k,而且当初逻辑核又造成会有两个过程来共享。所以可能会有 cache miss 的状况呈现。而且一旦 TLB miss 造成的结果可比物理地址 cache miss 结果要重大一些,最多可能须要进行 5 次内存 IO 才行。倡议你先用下面的 perf 工具查看一下你的程序的 TLB 的 miss 状况,如果的确不命中率很高,那么 Linux 容许你应用大内存页,很多大牛包含 PHP7 作者鸟哥也这样倡议。这样将会大大减少页表项的数量,所以天然也会升高 TLB cache miss 率。所要承当的代价就是会造成肯定水平的内存节约。在 Linux 里,大内存页默认是不开启的。



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

  • 1. 你认为你的多核 CPU 都是真核吗?多核“假象”
  • 2. 据说你只知内存,而不知缓存?CPU 示意很伤心!
  • 3.TLB 缓存是个神马鬼,如何查看 TLB miss?
  • 4. 过程 / 线程切换到底须要多少开销?
  • 5. 协程到底比线程牛在什么中央?
  • 6. 软中断会吃掉你多少 CPU?
  • 7. 一次零碎调用开销到底有多大?
  • 8. 一次简略的 php 申请 redis 会有哪些开销?
  • 9. 函数调用太多了会有性能问题吗?

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

正文完
 0