Linux缓存之TLB

  • 1. MMU
  • 2. 页表与 TLB 结构
  • 3. TLB本质
  • 4. TLB表项
  • 5. TLB的特殊
  • 6. TLB的别名问题
  • 7. TLB的歧义问题
  • 8. 如何尽可能的避免flush TLB
  • 9. 如何管理ASID
  • 10. 多个进程共享
  • 11. 什么时候应该flush TLB
  • 12. TLB初始化
  • refer to

1. MMU

CPU 的内存管理单元叫 MMU ,MMU的作用是把虚拟地址转换成物理地址。而 MMU 包括 TLB (TranslationLookaside Buffer ,快速翻译查找表)和一系列 CP0 寄存器。 TLB 负责从虚拟地址到物理地址的转换,是内存中页表的一个子集。

MMU工作原理如图所示:

2. 页表与 TLB 结构

在介绍 TLB 结构之前,先介绍页表结构。最简单的页表结构如图所示。

这是一种单级页表格式,虚拟页号一般称为 VPNVirtualPage Number ),而物理页号一般称为 PFNPage Frame Number )或者PPNPhysical Page Number ),虚拟页和物理页的页内偏移是相等的,因此页表实际上是负责 VPNPFN 的转换。

然而单级页表是有缺点的,以32 位系统为例:虚拟地址空间有 4 GB ,考虑到每个进程都有一个页表(内核自身还有一个页表),假设页面大小为 4KB ,每个页表项占用 4B,那么每个进程需要 4MB 的内存来存放页表( 4GB/4KB=1M ,每个进程有 1M 个页表项,每项 4B ,总共占用 4MB );而系统中有成百上千个进程,使用单级页表将会占用大量的内存。

为了解决这个问题,我们引入了多级页表,下图是两级页表的结构。

它把虚拟页号划分成页目录表索引和页表索引,这样一个进程的“总页表 ”实际上就包括了一个页目录表和若干个页表。还以 32 位系统和4KB 页面为例:如果页目录表索引和页表索引各 10 位,那么页目录表自身只需占用 4KB ,而页目录表中每个有效表项对应一个 4KB 的页表。由于进程实际上不会用到 4GB 的物理内存(也就是说存在很大的虚拟地址空间),因此页目录表里面大部分都是无效项。一个无效的页目录表项不需要与之对应的页表,因此总页表并不会占用太多的内存(就算一个进程占用了 2GB 物理内存,页目录表里也有一半的无效项,因此总页表也大概只需要 2MB )。

虚拟地址和物理地址的映射关系存储在页表中,而现在页表又是分级的。64位系统一般都是3~5级。常见的配置是4级页表,就以4级页表为例说明。分别是PGDPUDPMDPTE四级页表。在硬件上会有一个叫做页表基地址寄存器,它存储PGD页表的首地址。

MMU就是根据页表基地址寄存器从PGD页表一路查到PTE,最终找到物理地址(PTE页表中存储物理地址)。这就像在地图上显示一个景区,为了找到这个景区的地址,先确定这个景区在中国,再确定是某个省,继续往下某个市,最后找到这个景区是一样的原理。一级一级找下去。

如果第一次查到这个景区的具体位置,如果记下来这个景区的名字和地址。下次查找时,是不是只需要景区的姓名是什么,就直接能够说出这个景区的地址,而不需要一级一级查找。四级页表查找过程需要四次内存访问。延时可想而知,非常影响性能。页表查找过程的示例如下图所示。以后有机会详细展开,这里了解下即可。

3. TLB本质

TLB其实就是一块高速缓存。数据cache缓存地址(虚拟地址或者物理地址)和数据。TLB缓存虚拟地址和其映射的物理地址。TLB根据虚拟地址查找cache,它没得选,只能根据虚拟地址查找。所以TLB是一个虚拟高速缓存。

硬件存在TLB后,虚拟地址到物理地址的转换过程发生了变化。虚拟地址首先发往TLB确认是否命中cache,如果cache hit直接可以得到物理地址。否则,一级一级查找页表获取物理地址。并将虚拟地址和物理地址的映射关系缓存到TLB中。既然TLB是虚拟高速缓存(VIVT),是否存在别名和歧义问题呢?如果存在,软件和硬件是如何配合解决这些问题呢?

龙芯的 TLB 也是一个表,龙芯架构下 TLB 分为两个部分,一个是所有表项的页大小相同的单一页大小 TLB (SingularPage-Size TLB, 简称 STLB),另一个是支持不同表项的页大小可以不同的多重页大小 TLB (Multiple- Page-SizeTLB,简称 MTLB)。

页大小与 STLB 所配置的页大小相同的页表项能否进入 MTLB,由实现决定,架构规范中不做限制。

在虚实地址转换过程中,STLBMTLB 同时查找。相应地,软件需保证不会出现 MTLBSTLB同时命中的情況,否则处理器行为将不可知 MTLB 采用全相联查找表的组织形式,STLB 采用多路组相联的组织形式。对于 STLB, 如果其有 2NDEX组,且配置的页大小为20节,那么硬件查询STLB 的过程中,是将虚地址的[PS+INDEx:PS]位作为素引值来访问各路信息的。

4. TLB表项

STLBMTLB 的表项格式基本一致,区别仅在于 MTLB 每个表项均包含页大小信息,而STLB因为是同一页大小所以 TLB 表项中不再需要重复存放页大小信息。对于STLB 来说,其存放的页表项的页大小是由系统软件配置在 CSR.STLBPS 寄存器的PS域。

每一个TLB 表项的格式如图所示,包含两个部分:比较部分和物理转换部分。

5. TLB的特殊

虚拟地址映射物理地址的最小单位是4KB。所以TLB其实不需要存储虚拟地址和物理地址的低12位(因为低12位是一样的,根本没必要存储)。另外,我们如果命中cache,肯定是一次性从cache中拿出整个数据。所以虚拟地址不需要offset域。index域是否需要呢?这取决于cache的组织形式。

如果是全相连高速缓存。那么就不需要index。如果使用多路组相连高速缓存,依然需要index。下图就是一个四路组相连TLB的例子。现如今64位CPU寻址范围并没有扩大到64位。64位地址空间很大,现如今还用不到那么大。因此硬件为了设计简单或者解决成本,实际虚拟地址位数只使用了一部分。这里以48位地址总线为了例说明。

6. TLB的别名问题

我先来思考第一个问题,别名是否存在。我们知道PIPT的数据cache不存在别名问题。物理地址是唯一的,一个物理地址一定对应一个数据。但是不同的物理地址可能存储相同的数据。也就是说,物理地址对应数据是一对一关系,反过来是多对一关系。

由于TLB的特殊性,存储的是虚拟地址和物理地址的对应关系。因此,对于单个进程来说,同一时间一个虚拟地址对应一个物理地址,一个物理地址可以被多个虚拟地址映射。将PIPT数据cache类比TLB,我们可以知道TLB不存在别名问题。而VIVT Cache存在别名问题,原因是VA需要转换成PA,PA里面才存储着数据。中间多经传一手,所以引入了些问题。

7. TLB的歧义问题

我们知道不同的进程之间看到的虚拟地址范围是一样的,所以多个进程下,不同进程的相同的虚拟地址可以映射不同的物理地址。这就会造成歧义问题。例如,进程A将地址0x2000映射物理地址0x4000。进程B将地址0x2000映射物理地址0x5000。当进程A执行的时候将0x2000对应0x4000的映射关系缓存到TLB中。当切换B进程的时候,B进程访问0x2000的数据,会由于命中TLB从物理地址0x4000取数据。这就造成了歧义。

如何消除这种歧义,我们可以借鉴VIVT数据cache的处理方式,在进程切换时将整个TLB无效。切换后的进程都不会命中TLB,但是会导致性能损失。

8. 如何尽可能的避免flush TLB

首先需要说明的是,这里的flush理解成使无效的意思。我们知道进程切换的时候,为了避免歧义,我们需要主动flush整个TLB。如果我们能够区分不同的进程的TLB表项就可以避免flush TLB。我们知道Linux如何区分不同的进程?每个进程拥有一个独一无二的进程ID。如果TLB在判断是否命中的时候,除了比较tag以外,再额外比较进程ID该多好呢!这样就可以区分不同进程的TLB表项。进程A和B虽然虚拟地址一样,但是进程ID不一样,自然就不会发生进程B命中进程A的TLB表项。所以,TLB添加一项ASID(Address Space ID)的匹配。ASID就类似进程ID一样,用来区分不同进程的TLB表项。这样在进程切换的时候就不需要flush TLB。但是仍然需要软件管理和分配ASID

9. 如何管理ASID

ASID和进程ID肯定是不一样的,别混淆二者。进程ID取值范围很大。但是ASID一般是8或16 bit。所以只能区分25665536个进程。我们的例子就以8位ASID说明。所以我们不可能将进程IDASID一一对应,我们必须为每个进程分配一个ASID,进程ID和每个进程的ASID一般是不相等的。每创建一个新进程,就为之分配一个新的ASID。当ASID分配完后,flush所有TLB,重新分配ASID。所以,如果想完全避免flush TLB的话,理想情况下,运行的进程数目必须小于等于256。然而事实并非如此,因此管理ASID上需要软硬结合。Linux kernel为了管理每个进程会有个task_struct结构体,我们可以把分配给当前进程的ASID存储在这里。页表基地址寄存器有空闲位也可以用来存储ASID。当进程切换时,可以将页表基地址和ASID(可以从task_struct获得)共同存储在页表基地址寄存器中。当查找TLB时,硬件可以对比tag以及ASID是否相等(对比页表基地址寄存器存储的ASID和TLB表项存储的ASID)。如果都相等,代表TLB hit。否则TLB miss。当TLB miss时,需要多级遍历页表,查找物理地址。然后缓存到TLB中,同时缓存当前的ASID

10. 多个进程共享

我们知道内核空间和用户空间是分开的,并且内核空间是所有进程共享。既然内核空间是共享的,进程A切换进程B的时候,如果进程B访问的地址位于内核空间,完全可以使用进程A缓存的TLB。但是现在由于ASID不一样,导致TLB miss

我们针对内核空间这种全局共享的映射关系称之为global映射。针对每个进程的映射称之为non-global映射。所以,我们在最后一级页表中引入一个bit(non-global (nG) bit)代表是不是global映射。

当虚拟地址映射物理地址关系缓存到TLB时,将nG bit也存储下来。当判断是否命中TLB时,当比较tag相等时,再判断是不是global映射,如果是的话,直接判断TLB hit,无需比较ASID。当不是global映射时,最后比较ASID判断是否TLB hit

11. 什么时候应该flush TLB

  1. ASID分配完的时候,需要flush全部TLB。ASID的管理可以使用bitmap管理,flush TLB后clear整个bitmap
  2. 当我们建立页表映射的时候,就需要flush虚拟地址对应的TLB表项。第一印象可能是修改页表映射的时候才需要flush TLB,但是实际情况是只要建立映射就需要flush TLB。原因是,建立映射时你并不知道之前是否存在映射。例如,建立虚拟地址A到物理地址B的映射,我们并不知道之前是否存在虚拟地址A到物理地址C的映射情况。所以就统一在建立映射关系的时候flush TLB。

12. TLB初始化

龙芯架构允许不实现 TLB 的硬件初始化,让启动阶段的软件通过执行INVTLB r0,r0来完成这一功能

refer to

  1. 夯实基本功,深入理解 TLB 原理

Linux缓存之TLB相关推荐

  1. linux如何查看tlb大小,TLB缓存是个神马鬼,如何查看TLB miss?

    介绍TLB之前,我们先来回顾一个操作系统里的基本概念,虚拟内存. 虚拟内存 在用户的视角里,每个进程都有自己独立的地址空间,A进程的4GB和B进程4GB是完全独立不相关的,他们看到的都是操作系统虚拟出 ...

  2. linux缓存代码,Linux使用的缓存

    Linux使用的缓存 6.7.1 Linux使用的缓存 不管在硬件设计还是软件设计中,高速缓存是获得高性能的常用手段.Linux 使用了多种和内存管理相关的高速缓存. 1. 缓冲区高速缓存: 缓冲区高 ...

  3. linux缓存机制buffer/cache/swap

    1)缓存机制介绍 在Linux系统中,为了提高文件系统性能,内核利用一部分物理内存分配出缓冲区,用于缓存系统操作和数据文件,当内核收到读写的请求时,内核先去缓存区找是否有请求的数据,有就直接返回,如果 ...

  4. 在linux缓存里写数据,缓存策略

    存储器的层次结构 操作系统中的存储器构成了一个金字塔,越往上的存储器速度越快,但是价格也越贵,所以也就越小.为了解决高速的处理器和低速的存储器之间的矛盾,上一层的存储器作为下一层存储器的缓存. 比如要 ...

  5. Linux 缓存释放和管理

    在Linux系统中为了提高文件系统性能,系统利会用一部分物理内存作为缓冲区使用,主要用于缓存系统操作和数据文件.当内核收到读写的请求时系统会先在缓存区找是否有请求的数据,有就直接返回,如果没有则通过驱 ...

  6. linux缓存无法写入,Linux下搭建网站提示缓存文件写入失败怎么办?

    Linux下搭建网站提示缓存文件写入失败时该怎么处理?基于ThinkPHP框架及Linux环境搭建的网站,经常会遭遇缓存文件写入失败的错误提示,即便是现在流行的P2P网站程序便是如此,具体解决方法请看 ...

  7. linux缓存无法写入,缓存文件写入失败_Linux下搭建网站提示缓存文件写入失败怎么办...

    摘要 腾兴网为您分享:Linux下搭建网站提示缓存文件写入失败怎么办,中意在线,智联招聘,优化大师,易信等软件知识,以及快易多,酷狗6,cc语音,反编译app,快捷酒店管家,2144,苏大附二院,ar ...

  8. linux缓存无法写入,Linux下搭建网站提示缓存文件写入失败解决方法?

    Linux下搭建网站提示缓存文件写入失败时该怎么处理?基于ThinkPHP框架及Linux环境搭建的网站,经常会遭遇缓存文件写入失败的错误提示,即便是现在流行的P2P网站软件便是如此,具体处理办法请看 ...

  9. linux缓存buffer,【Linux】清理缓存buffer/cache

    运行sync将dirty的内容写回硬盘 sync 通过修改proc系统的drop_caches清理free的cache echo 3 > /proc/sys/vm/drop_caches ech ...

最新文章

  1. volatile - 如何实现线程安全
  2. 商城网站前期功能设置这几项绝不能少!
  3. [日常] Go语言圣经--Channel习题
  4. 四位数码管树莓派c语言,用树莓派和四位数码管模块做一个时钟
  5. Chaos网络库(三)- 主循环及异步消息的实现
  6. InnoDB文件系统
  7. TF-IDF来源及理论推导 熵推导出
  8. node使用ffmpeg拼接音频
  9. 冷热分离和直接使用大数据库_【TBase开源版测评】深度测评TBase的shard分片和冷热分离存储特性...
  10. Vasp 石墨烯能带计算
  11. JSON Viewer 安装
  12. 6翻了 (15 分)
  13. 【深入剖析JavaScript中的对象】
  14. (转)WAVE PCM 声音文件格式
  15. 皕杰报表之小程序代码质量检测
  16. 【纪中受难记】——Day5: 改题好烦
  17. JavaWeb-06 (项目案例3)
  18. Using fallback Sshlinedraw for CID-keyed font STSong-Light
  19. 查看端口占用情况(Windows环境)
  20. 解决:Flarum完整项目拉取到本地点击任何链接都弹出“请求资源不存在”(报404)

热门文章

  1. Opencv学习笔记(二) 提取图像中的水平线和垂直线
  2. android过渡动画软件,XuiMod app
  3. SpringBoot项目拥抱Mybatis-Plus持久层框架实践
  4. C语言简单的编程技术(代码优化)
  5. 现代c++开发利器folly教程系列之:dynamic
  6. 苹果ipad有哪几款_苹果官宣11月第三波发布会,MAC电脑是亮点
  7. 2021牛客寒假算法基础集训营5 比武招亲(上)(组合数)
  8. 网络广告效果评估方法
  9. C++ 生命周期和编程范式
  10. 学猫叫计算机版教程,学猫叫手势舞教程