深入理解缓存 TLB 原理

今天分享一篇TLB的好文章,希望大家夯实基本功,让我们一起深入理解计算机系统。
TLB 是 translation lookaside buffer 的简称。首先,我们知道 MMU 的作用是把虚拟地址转换成物理地址。

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

Linux分页机制
MMU 就是根据页表基地址寄存器从 PGD 页表一路查到 PTE,最终找到物理地址(PTE页表中存储物理地址)。这就像在地图上显示你的家在哪一样,我为了找到你家的地址,先确定你是中国,再确定你是某个省,继续往下某个市,最后找到你家是一样的原理。一级一级找下去。这个过程你也看到了,非常繁琐。如果第一次查到你家的具体位置,我如果记下来你的姓名和你家的地址。下次查找时,是不是只需要跟我说你的姓名是什么,我就直接能够告诉你地址,而不需要一级一级查找。
四级页表查找过程需要四次内存访问。延时可想而知,非常影响性能。页表查找过程的示例如下图所示。以后有机会详细展开,这里了解下即可。

page table walk
TLB 的本质是什么
TLB 其实就是一块高速缓存。
数据 cache 缓存地址(虚拟地址或者物理地址)和数据。TLB 缓存虚拟地址和其映射的物理地址。TLB 根据虚拟地址查找 cache,它没得选,只能根据虚拟地址查找。
所以 TLB 是一个虚拟高速缓存。硬件存在 TLB 后,虚拟地址到物理地址的转换过程发生了变化。虚拟地址首先发往 TLB 确认是否命中 cache,如果 cache hit 直接可以得到物理地址。
否则,一级一级查找页表获取物理地址。并将虚拟地址和物理地址的映射关系缓存到 TLB 中。既然 TLB 是虚拟高速缓存(VIVT),是否存在别名和歧义问题呢?如果存在,软件和硬件是如何配合解决这些问题呢?
TLB 的特殊
虚拟地址映射物理地址的最小单位是 4KB。所以 TLB 其实不需要存储虚拟地址和物理地址的低 12 位(因为低 12 位是一样的,根本没必要存储)。
另外,我们如果命中 cache,肯定是一次性从 cache 中拿出整个数据。所以虚拟地址不需要 offset 域。index 域是否需要呢?这取决于cache的组织形式。
如果是全相连高速缓存。那么就不需要 index。如果使用多路组相连高速缓存,依然需要index。
下图就是一个四路组相连 TLB 的例子。现如今 64 位 CPU 寻址范围并没有扩大到 64 位。64 位地址空间很大,现如今还用不到那么大。
因此硬件为了设计简单或者解决成本,实际虚拟地址位数只使用了一部分。这里以 48 位地址总线为例说明。

TLB 的别名问题
我先来思考第一个问题,别名是否存在。我们知道 PIPT 的数据 cache 不存在别名问题。物理地址是唯一的,一个物理地址一定对应一个数据。但是不同的物理地址可能存储相同的数据。
也就是说,物理地址对应数据是一对一关系,反过来是多对一关系。由于 TLB 的特殊性,存储的是虚拟地址和物理地址的对应关系。
因此,对于单个进程来说,同一时间一个虚拟地址对应一个物理地址,一个物理地址可以被多个虚拟地址映射。
将 PIPT 数据 cache 类比 TLB,我们可以知道TLB 不存在别名问题。而 VIVT Cache 存在别名问题,原因是 VA 需要转换成PA,PA 里面才存储着数据。中间多经传一手,所以引入了些问题。
TLB的歧义问题
我们知道不同的进程之间看到的虚拟地址范围是一样的,所以多个进程下,不同进程的相同的虚拟地址可以映射不同的物理地址。这就会造成歧义问题。
例如,进程A将地址 0x2000 映射物理地址 0x4000。进程 B 将地址 0x2000 映射物理地址 0x5000。当进程 A 执行的时候将 0x2000 对应0x4000 的映射关系缓存到 TLB 中。当切换 B 进程的时候,B 进程访问 0x2000 的数据,会由于命中 TLB 从物理地址0x4000取数据。
这就造成了歧义。如何消除这种歧义,我们可以借鉴 VIVT 数据 cache 的处理方式,在进程切换时将整个 TLB 无效。切换后的进程都不会命中 TLB,但是会导致性能损失。
资料直通车:Linux内核源码技术学习路线+视频教程内核源码
学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈
如何尽可能地避免 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。

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

什么时候应该flush TLB
我们再来最后的总结,什么时候应该 flush TLB。
- 当 ASID 分配完的时候,需要 flush 全部 TLB,ASID 的管理可以使用 bitmap 管理,flush TLB 后 clear 整个 bitmap。
- 当我们建立页表映射的时候,就需要 flush 虚拟地址对应的 TLB 表项。第一印象可能是修改页表映射的时候才需要 flush TLB,但是实际情况是只要建立映射就需要 flush TLB。原因是,建立映射时你并不知道之前是否存在映射,例如,建立虚拟地址 A 到物理地址 B 的映射,我们并不知道之前是否存在虚拟地址 A 到物理地址 C 的映射情况,所以就统一在建立映射关系的时候 flush TLB。
原文作者:【 一起学嵌入式

相关文章:
深入理解缓存 TLB 原理
今天分享一篇TLB的好文章,希望大家夯实基本功,让我们一起深入理解计算机系统。 TLB 是 translation lookaside buffer 的简称。首先,我们知道 MMU 的作用是把虚拟地址转换成物理地址。 MMU工作原理 虚拟地址和物理地址的映射关系存储在页表…...
获取k8s scale资源对象的命令
kubectl get --raw /apis/<apiGroup>/<apiVersion>/namespaces/<namespaceName>/<resourceKind>/<resourceName>/scale 说明:scale资源对象用来水平扩展k8s资源对象的副本数,它是作为一种k8s资源对象的子资源存在…...
基于ChatYuan-large-v2 语言模型 Fine-tuning 微调训练 广告生成 任务
一、ChatYuan-large-v2 ChatYuan-large-v2是一个开源的支持中英双语的功能型对话语言大模型,与其他 LLM 不同的是模型十分轻量化,并且在轻量化的同时效果相对还不错,仅仅通过0.7B参数量就可以实现10B模型的基础效果,正是其如此的…...
SpringBoot集成Logback日志
SpringBoot集成Logback日志 文章目录 SpringBoot集成Logback日志一、什么是日志二、Logback简单介绍三、SpringBoot项目中使用Logback四、概念介绍一、日志记录器Logger1.1、日志记录器对象生成1.2、记录器的层级结构1.3、过滤器1.4、logger设置日志级别1.5、java代码演示1.6、…...
MATLAB(R2023a)添加工具箱TooLbox的方法-以GPOPS为例
一、找到工具箱存放位置 首先我们需要找到工具箱的存放位置,点击这个设置路径可以看到 我们的matlab工具箱的存放位置 C:\Program Files\MATLAB\R2023a\toolbox\matlab 从资源管理器中打开这个位置,可以看到里面各种工具箱 二、放入工具箱 解压我们…...
助力618-Y的混沌实践之路 | 京东云技术团队
一、写在前面 1、混沌是什么? 混沌工程(Chaos Engineering)的概念由 Netflix 在 2010 年提出,通过主动向系统中引入异常状态,并根据系统在各种压力下的行为表现确定优化策略,是保障系统稳定性的新型手段。…...
Python系统学习1-4-物理行、逻辑行、选择语句
一、行 (1) 物理行:程序员编写代码的行。 (2) 逻辑行:python解释器需要执行的指令。 (3) 建议: 一个逻辑行在一个物理行上。 如果一个物理行中使用多个逻辑行,需要使用分号;隔开。 (4) 换行: 如果…...
学习系统编程No.35【基于信号量的CP问题】
引言: 北京时间:2023/8/2/12:52,时间飞逝,恍惚间已经来到了八月,给我的第一感觉就是快开学了,别的感觉其实没有,哈哈!看着身边的好友网络相关知识都要全部学完了,就好像…...
词嵌入、情感分类任务
目录 1.词嵌入(word embedding) 对单词使用one-hot编码的缺点是难以看出词与词之间的关系。 所以需要使用更加特征化的表示(featurized representation),如下图所示,我们可以得到每个词的向量表达。 假设…...
TypeScript使用技巧
文章目录 使用技巧TypeScript内置的工具类型keyofextends 限定泛型interface 与 type 区别 TypeScript作为JavaScript的超集,通过提供静态类型系统和对ES6新特性的支持,使JavaScript开发变得更加高效和可维护。掌握TypeScript的使用技巧,可以帮助我们更好地开发和组织JavaScrip…...
MySQL — InnoDB事务
文章目录 事务定义事务特性事务隔离级别READ UNCOMMITTEDREPEATABLE READREAD COMMITTEDSERIALIZABLE 事务存在的问题脏读(Dirty Read)不可重复读(Non-repeatable Read)幻读(Phantom Read) 事务定义 数据库…...
LeetCode 42. 接雨水(动态规划 / 单调栈)
题目: 链接:LeetCode 42. 接雨水 难度:困难 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2…...
顺序表、链表刷题指南(力扣OJ)
目录 前言 题目一:删除有序数组中的重复项 思路: 题解: 题目二:合并两个有序数组 思路: 分析: 题解: 题目三:反转链表 思路: 分析: 题解: 题目四&…...
Lambda表达式总结
Lambda作为Java8的新特性,本篇文章主要想总结一下常用的一下用法和api 1.接口内默认方法实现 public interface Formula {double calculate(int a);// 默认方法default double sqrt(int a) {return Math.sqrt(a);} }public static void main(String[] args) {Form…...
岛屿的最大面积
给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。 岛屿的面积是岛上值为 1 …...
迭代器模式(Iterator)
迭代器模式是一种行为设计模式,可以在不暴露底层实现(列表、栈或树等)的情况下,遍历一个聚合对象中所有的元素。 Iterator is a behavior design pattern that can traverse all elements of an aggregate object without exposing the internal imple…...
Goland搭建远程Linux开发
Windows和Linux都需要先构建好go环境,启用ssh服务。 打开Windows上的Goland,建立项目。 点击添加配置,选择go构建 点击运行于,选择ssh 填上Linux机器的IP地址和用户名 输入密码 没有问题 为了不让每次运行程序和调试程序都生…...
react中PureComponent的理解与使用
一、作用 它是一个纯组件,会做一个数据的浅比较,当props和state没改变的时候,不会render重新渲染, 改变后才会render重新渲染,提高性能。 二、使用 三、注意 它不能和shouldComponentUpdate生命周期同时使用。因为它…...
洛谷——P5714 【深基3.例7】肥胖问题
文章目录 题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 AC代码 题目 题目描述 BMI 指数是国际上常用的衡量人体胖瘦程度的一个标准,其算法是 m h 2 \dfrac{m}{h^2} h2m,其中 m m m 是指体重&am…...
Mac隐藏和显示文件
由于之前没有使用过Mac本,所以很多地方都不太清楚,在下载git项目的时候,发现没有.git文件, 一开始还以为下载错了,但是git命令是可以看到远端分支以及当前分支的,之后在一次解压文件的时候发现,…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
