操作系统笔记(7)-快速地址转换
操作系统笔记(7)-快速地址转换
简介
使用分页作为核心来实现虚拟内存,可能会带来较高的性能开销:额外的
内存引用
为了改善这个问题,我们需要硬件的帮助,它的名字叫
地址转换旁路缓冲存储器(translation-lookaside buffer)
,简称TLB
,也可以叫它地址转换缓存
TLB
在处理器核心附近,设计的访问速度很快
TLB
的工作原理
对每次内存访问,硬件先检查
TLB
,看看其中是否有期望的转换映射,如果有,就完成转换(很快),不用访问页表。因此TLB
带来了巨大的性能提升算法流程如下:
从虚拟地址中
提取页号(VPN)
检查
TLB
中是否有该VPN
对应的物理帧号PFN
如果有,
TLB
命中,转换成功如果没有,
TLB
未命中,硬件就访问页表
来寻找地址映射用找到的映射来更新
TLB
谁来处理 TLB
未命中
早期的硬件有复杂指令集,可以全权处理
TLB
未命中,然后去遍历页表
找到对应的地址映射(如x86
架构)更现代的体系结构都是精简指令集计算机,通过软件管理
TLB
,发生TLB
未命中时,硬件系统会抛出一个异常,这会暂停当前的指令流,将特权级提升至内核模式,跳转至陷阱处理程序
,然后这个程序用于处理TLB
未命中
TLB
的内容
如果想要快速地缓存,
TLB
的大小就不会很大,典型的TLB
有32
项、64
项或者128
项,如果每一项的大小是4
B,那TLB
的总大小还是很小的TLB
项的内容应该包含虚拟页号VPN
、物理帧号PFN
以及一些其它的标志位,一般TLB
会有一个有效位
用于标志该项是不是有效的地址转换,还有保护位
表示该页是否有访问权限,还有一些标志位如脏位
等
上下文切换时对 TLB
的处理
TLB
中包含的虚拟到物理地址的映射只对当前进程有效,对其它进程是没有意义的,所以在不同的进程切换时需要对TLB
进行处理,避免误读
现象假如两个进程的虚拟地址相同,那么就容易产生
误读
,因此TLB
引入了一个地址空间标识符(ASID)
用于标识不同的进程,与PID
相似,但是通常比PID
位数少通过使用
ASID
,不同的进程就可以共享TLB
了
注意 : 我们讨论的 TLB
是指的单核机器,在多核机器中,每个 CPU
都有一个 TLB
,类比即可
TLB
替换策略
前面说到,
TLB
是很小的,那么当TLB
满了之后,下一次更新之前就需要替换掉已有的一项才行一般有两种方式采用,一个是替换
最近最少使用(LRU)
的项,另一个是随机策略
,相比来说随机策略
比较好
练习:测量 TLB
未作用时每页的平均访问时间
如何测量:使用
gettimeofday()
进行时间差计算定义一个很大的数组(跨越多个页存储),然后每次访问不同的页(保证
TLB
命中率为0),计算平均访问时间查看页表大小,在
shell
使用getconf PAGE_SIZE
查看,我的是4KB
测试代码
#include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <stdlib.h> // 结果查看, 页表的大小为 4KB #define PAGESIZE 4096 int a[1024 * 1024 * 256]; int main(int argc, char* argv[]) { if (argc < 3) { printf("请给出页的数目和尝试的次数\n"); return 0; } int pagesNum = atoi(argv[1]); if (pagesNum > 1024 * 256) { printf("页的数目不能超过%d", 1024 * 256); return 0; } int cnt = atoi(argv[2]); int jump = PAGESIZE / sizeof(int); // 跳到下一页需要的步数 struct timeval start, end; gettimeofday(&start, NULL); for (int i = 0; i < cnt; i++) { for (int j = 0; j < pagesNum * jump; j += jump) { a[j] += 1; } } gettimeofday(&end, NULL); long int diff = 1000000L * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec); printf("total time is : %ldus\n", diff); printf("avg time : %lfus\n", (float)diff / (pagesNum * cnt)); return 0; }
测试结果 :这里迭代次数都是
1
,后面测试TLB
开销可以通过增加迭代次数估算结果分析 :随着访问页数的增加,平均的页访问时间
逐渐增加
,都在几毫秒的样子如果要测试
TLB
命中后的平均开销,只需要固定访问页数,然后提高迭代次数即可,当迭代次数足够高时,就能够近似得到TLB
命中后的平均访问速度了结果分析 :有了
TLB
的作用,平均访问时间提升到了纳秒级