《Operating System:Three Easy Pieces》阅读笔记<十一>—分页(二)(translation lookaside buffer)

154 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

分页(二)—快速转换

分页的基础方法对物理地址的查询依赖于page table,但是基于page table的查询需要两段步骤,因此速度很慢。这也就导致了分页方法带来了非常高的性能开销,为了解决这个问题,我们会增加一个内存缓冲区translation-lookaside buffer(TLB),一基于硬件的虚拟地址-物理地址转换的缓存技术。通过TLB技术,大部分的内存访问申请都会经由缓存快速的定位,使page这一技术的可用性大大提升。

你可能在其它的地方见过缓存的技术,或许你会疑惑,内存的访问速度已经很快了,为什么还需要缓存。我们可以用下面这张图来直观的解释

可以看到即使是L2缓存的读取速度也比内存读取速度块至少10倍,如果每一次内存请求都得访问内存至少两次的话,对于总体速度的影响是十分大的。

简单来讲的话,TLB就是一个离CPU十分近的存储结构,用来缓存以页表为单位的数据,一个典型的TLB有32、64、128个entry,也就是页表。在每次处理虚拟内存访问时,硬件会首先检查TLB中是否包含转换信息,如果没有,才会去查询物理内存。

TLB到底由什么组成呢?在TLB中,一个entry字段包含VPN、PFN以及其它的功能bit位。VPN和PFN的功能很明显就是不经由寄存器,直接由VPN映射PFN。我们由功能延申一下其它bit位的含义,首先是最重要的ASID位。当进行context switches时,不同进程的TLB可能会出现冲突,我们在entry字段中安放ASID字段作为进程的标识符。固定的,entry字段中还会有valid bit、protection bit、dirty bit等。

以简化版MIPS R4000系统中entry字段为例,由图可知,该系统中一个entry字段长64 bytes,包含除了我们上面说的部分以外,还有global bit、coherence bit等部分。

我们无法给每一个计算机硬件的单位内容都重新命名,因此我们用entry来描述一个结构中的基本单位,之后我们会大量的见到这种描述

具体的,我们以一个C语言程序为例子来解释一下TLB的工作原理,这个例子中page大小位16 bytes,因为一个整型变量的大小为4 bytes,40个bytes占三页,数组在地址空间中的占用情况如图所示。

我们假设一个TLB的大小是一页,每次内存访问到TLB中没有的页,就会将那一页存储到TLB中。

可以知道从程序开始到程序结束,TLB的使用情况为miss, hit, hit, miss, hit, hit, hit, miss, hit, hit。相当于70%的访问是被提前记录的,事实上,如果分页更大,变量空间占用越大,命中率还会继续提高到90%以上。

既然提到了命中率,那么没有命中的时候要怎样处理呢。这也是现代操作系统的一大分歧点,对于复杂指令集系统如CISC,例如intel x86系列,以硬件为基础来处理TLB miss的情况,也就是说,TLB miss并不会引发任何trap,硬件负责将新的TLB entry加入TLBs中,要做到这一点需要不少的硬件代价。下图是TLB参与整个内存访问的流程。

对于简单指令集系统如RISC,例如MIPS R10k,则由操作系统来处理TLB miss,这样做有两个方面的优点,一是灵活,操作系统可以基于相同的逻辑,使用任意数据结构来构建page table和TLB,易于使用也易于更改;二是简单,硬件只需要在遇到TLB miss时引发一个trap,之后让操作系统处理即可。

早期RISC系统的芯片产生时引发了很多影响,因为明显RISC更快,但是经过这些年的演变,CISC逐渐吸收了很多RISC的特点,现在两者都可以达到很快的处理速度。