操作系统的作业:内存管理。TLB、LRU、clock

实验内容:

1、阅读代码回答问题

(1) 当前系统下,内存大小Mainmemory是多少?

PageSize=128,  NumPhysPages=128,   Mainmemory=128*128=2^7*2^7=2^14;  内存大小是4KB

(2) 理解从空间分配,加载代码数据,取指执行的流程

空间分配:调用AddrSpace的构造函数,先为该进程分配页表,然后使用for循环建立虚拟内存和物理内存之间的对应关系。

加载代码数据:这部分功能由AddrSpace类中的load()函数实现。在这个函数中,打开了用户文件,读文件头中的信息,计算所需要的内存大小,再调用divRoundUP()函数计算所需要的页的个数。然后根据文件头中的信息,如果有代码段,写入kernel内核中的主存中,数据段也是同样的道理。

取指执行:初始化CPU寄存器,使得它指向需要指向的第一条指令。由于load()加载的数据是虚拟地址,寄存器读取的也是虚拟地址,所以正式执行前需要进行转换。初始化寄存器是AddrSpace()类中的InitRegister()方法。还需要RestoreState()函数将进程中的页表拷贝到CPU中去维护。最后调用machine中的Run()方法,使用OneInstruction函数模拟一次取指令和执行该指令的操作。

(3) PageTable表中,虚拟地址和物理地址的对应关系如何?Translate函数如何工作

① Translate()函数有4个参数:

l virtAddr:用户程序的逻辑地址;

l physAddr:转换后的实际地址;

l size:数据类型的大小;

l writing:读/写内存标志

   

② 判断用户的逻辑地址是否对齐:

l 如果size是2,virtAddr必须是2的倍数;

l 如果size是4,virtAddr必须是4的倍数。

l 没有对齐则返回AddressErrorException。

 

③  计算出虚拟地址所在页号vpn以及所在页面的偏移量

 

 

 

 

④   采用不同的转换方法做不同的处理:

l 如果采用的是线性转换表:当vpn>=pageTableSize时,虚拟页数过大,返回AddressErrorException;如果页表中显示该页无效,返回PageFaultException;一切正常得到相应的页表表项。

l 如果采用的是TLB转换表:如果查找到了,得到相应的页表表项;如果没有查找到,返回PageFaultException

⑤   如果得到的页表表项是只读,但是设置的是writing,返回ReadOnlyException

⑥ 如果物理地址大于实际内存物理地址,返回BusErrorException

⑦ 设置表项正在使用标志,如果writing标志设置,设置表项中的dirty标志

⑧ 然后在页表中查找它们所在的物理页框号,计算物理地址。

 

返回NoException。

 

 

(4) 什么情况下会产生PageFault的exception, 是否有对应处理函数?

在Translate()函数中,采用线性转化表时,如果查找的页是无效的,返回PageFaultException;采用TLB表,如果没有查到,返回PageFaultException。Translate()函数在ReadMem()函数中被调用,因而PageFaultException被返回到ReadMem()函数中进行判断,并被传入到RaiseException()函数中,这个函数会调用ExceptionHandler()函数,由它对传入的异常进行处理。

在这个函数 中,由switch语句判断传入的是异常还是系统调用,如果是系统调用再采用一个switch-case语句判断是何种系统调用;如果是异常直接打印出错信息。需要说明的是,在处理完PageFaultException之后,不需要将PC+4。因为处理完异常后,返回的最终位置是OneInStruction函数的取指阶段,取指失败后,OneInstruction会退出,再用相同PC取指令。这个时候就可以命中了。

 

2. 设计LRU策略下的TLB

(1) 在本次实验中为了减少代码量,设定TLBPageTable的关系如下所述:

TLB在系统中唯一,所有线程可用;PageTable为每个进程一个;

系统尚未实现真正意义上的虚拟内存管理,系统仅运行一个用户线程;

系统同时有TLBPageTableTLB视为对PageTable中部分代码的高速缓存;

系统开始之初,TLB为空,PageTable NachOS代码完成原来的初始化;

系统取指时,地址的翻译由函数Translate()进行,这时从TLB中的页表项查找物理地址和虚拟地址的对应关系;

如果不命中,则产生PageFault异常,转移到异常处理函数进行处理;

该处理函数需要自己写,完成从PageTable加载对应页表项到TLB

线程切换时,TLB需要清空;

加载到TLB之后,需要回到中断产生的地方,继续执行

(2) machine.h .cc中完成TLB的定义和初始化,修改数据结构增加时间记录变量

(3) 完成异常处理函数调用,以LRU方式进行TLB替换;注意必要时同步被替换项回到PageTable//加分clock算法

(4) 时间信息可以来自stats下的totalTicks(溢出情况不考虑,该值为int,有一定隐患);加入必要的信息,显示缺页异常发生,和TLB哪个页表项在进行替换,替换成哪个页表项

(5) 运行程序观测是否正常?如果不正常请跟踪代码,发现缺页异常处理返回后程序没有重新正常运行;

(6) 修改WriteMemReadMem,在缺页异常处理返回后重新调用Translate()函数

答案:

LRU运行截图:

修改的代码:

 

源码中已经给出了TLB的实现,在machine.h中增加一个宏定义,使得nachos产生一个TLB

需要注意的是,在Translate.cc中的Translate()函数中有一个判断,意思是TLBpage table不能同时存在,需要将它注释掉。

Translate.h中,在TranslateEntry中增加一个属性lastUseTime

 

Exception.cc中。判断TLB缺页,抛出的exceptionTranslateFaultException,在switch函数中进行判断,并且判断是不是TLB缺失。调用LRU算法。

machine.h,实现TLB的构造,对lastUseTime进行赋值

 

machine.cc中实现MyHandleTLB()函数:

Translate.cc中,修改WtriteMem()函数,发生exception时,先判断是不是PageFaultException,如果是,调用了RaiseException()函数后,缺页已经解决,再次调用Translate()函数。

ReadMem函数中修改方法相同

2. (选做)以CLOCK方式,仅使用use标志位

运行截图:

修改代码:

Translate.h中,在TranslateEntry中增加一个属性useTag

Translate.cc中的Translate()函数以及ReadMem()WriteMem()函数依然和LRU函数中的一样,不需要修改。

Exception.cc中。判断TLB缺页,调用clock算法

Machine.h中,在machine类中增加clock算法处理TLB缺页的函数声明:MyClockTLB(int addr);

Machine.cc中,实现这个函数。

现在文件头上增加一个全局变量cursor,这个是时钟算法中的指针。

TLB构造函数中,对useTag赋值为0

 

下面是对MyClockTLB(int addr)函数的实现

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值