操作系统实验报告2.docx
- 文档编号:4123463
- 上传时间:2022-11-28
- 格式:DOCX
- 页数:14
- 大小:21.92KB
操作系统实验报告2.docx
《操作系统实验报告2.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告2.docx(14页珍藏版)》请在冰豆网上搜索。
操作系统实验报告2
Nachos虚存实验报告
一、实验名称:
Nachos虚存
二、实验目的:
本实验牵涉到Nachos虚存子系统的部分实现,也是第一次用到Nachos的虚拟机。
测试代码是一组覆盖了绝大部分虚存空间的数组操作,该虚存空间被映射到20个物理页中。
地址转换和页表结构已给出。
本实验的目的是要实现缺页处理程序,这需要在适当的时候将某些页面替换出/入。
为了减少缺页和将页面从内存淘汰到磁盘的次数,要求实现以下五种页面替换算法:
ØNRU(NotRecentlyUsed)算法
ØSC(SecondChance)算法
ØClock算法
ØWorkingSet算法
ØAging算法
三、实验步骤
1.预备
(1)素材:
本实验的源代码是/home/nachos/mp3.tar文件。
复制到本地目录后解包,要在userprog子目录下工作,也需阅读文件filesys/filesys.h,filesys/openfile.h,machine/translate.h,machine/timer.h,和bin/noff.h。
本实验需修改文是memmanager.h和memmanager.cpp。
(2)分析代码:
每个地址空间都有相应的页表,页表中的每一项称为页表条目。
在本实验中,我们会牵涉到其中的三个主要字段:
USE、DIRTY和VALID,它们在machine/translate.h中有详细描述。
AddrSpace结构包含了Nachos进程地址空间的所有信息:
页表、页表长度等,以及操作地址空间的函数。
当创建了一个新的进程时,该结构也就随之产生并初始化。
所提供的代码已实现了页面调度机制,在该机制中,仅在一个执行进程访问页面时,才将它从可执行的源文件中读入物理内存。
所以,在进程刚创建时,页表中的所有条目都是初始化为无效的(所有页表条目的有效位都置为false)。
然而,访问这样的页面(不属于任何程序段)一般来说是不合法的。
当初始化一个页表时,要生成一个报告,该报告说明哪些页面的访问是合法的,而哪些页面的访问是不合法的(Legal字段)。
每个可执行程序都以一个头开始,它指定程序中所有程序段的虚存范围。
开始时,调用AddrSpace:
:
ReadSourcePage()函数来从可执行文件中读一个页面到物理内存。
注意,该函数仅在进程第一次访问虚页时调用。
至于后续的访问,如果页面不在物理内存中,则搜索替换文件而不是源文件。
替换文件由类似与MainMemory的内存帧组成,只不过它们存储在磁盘上。
一组称为“SwapOwners”的TranslationEntry指针用来跟踪指向替换文件中页面的页表条目,一个类似的结构“CoreOwners”则用来跟踪指向内存中页面的页表条目。
在执行阶段,仿真程序将在TranslationEntrys中设置适当的位,如:
当出现写操作时置DIRTY=TRUE、当出现写或读操作时置USE=TRUE。
如果仿真器处理了这样一个TranslationEntry中的存储器请求:
LEGAL=TRUE但VALID=FALSE,它将自陷到MemManager:
:
faultIn()中去,这就是你要实现的地方:
给定缺页的TranslationEntry,用PageIn()、PageOut()以及你要实现的将适当的缓冲页面调入物理页的方法,更新TranslationEntry并将控制权返回给虚拟机。
阅读代码MemManager:
:
PageFaultExceptionHandler(),它由ExceptionHandler()在接收到一个缺页异常时调用。
关于如何实现MemManager:
:
faultIn()的一些细节和几点提示都以注释的方式在MemManager:
:
PageFaultExceptionHandler()中给出。
注意:
在此函数中,程序计数器的值不应加一。
在处理完异常且控制权返回给缺页进程后,引起缺页的那条指令将重新执行。
2.页面替换算法的实现
本次实验对页面替换算法的实现主要是通过一个MemManagerr类来实现的,类中主要的函数有以下几个:
●faultIn是“handler”,而其它各种方法则聚合成了重要的功能:
●PageOut负责将页面写到备份存储中,它只处理脏页,因为其它的页面已在备份存储中或是与原始状态相比没有变化,所以其它的页面可以覆盖它;
●PageIn负责将页面读入指定的物理页,若该页不在备份存储中,则从原始文件中装载;
●MakeFreeFrame负责在没有空闲页时用适当的页面替换算法来选择一个牺牲页;
●doUpdation是一个定时中断处理程序(在memmanager.cc文件中),它修改translationEntries中适当的位来更新历史信息。
整个实验修改的代码如下所示:
(红色部分为修改的代码)
intMemManager:
:
makeFreeFrame()
{
//victimisthenumberofthephysicalpagetobeswappedout
intvictim=0;
switch(policy)
{
casePAGEREPL_NRU:
//4.4.2-NotRecentlyUsed
{
#ifdefCHANGE
inti;
boolfind=false;
for(i=0;(i!
=NumPhysPages)&&(!
find);i++)
{
if((!
coreOwners[i]->use)&&(!
coreOwners[i]->dirty))
{
victim=i;
find=true;
}
}
for(i=0;(i!
=NumPhysPages)&&(!
find);i++)
{
if((!
coreOwners[i]->use)&&(coreOwners[i]->dirty))
{
victim=i;
find=true;
}
}
for(i=0;(i!
=NumPhysPages)&&(!
find);i++)
{
if((coreOwners[i]->use)&&(!
coreOwners[i]->dirty))
{
victim=i;
find=true;
}
}
#endif
break;
}
casePAGEREPL_FIFO:
//4.4.3-FIFO
{
int*ptr=fifoList->Remove();
victim=*ptr;
#ifdefCHANGE
if(ptr!
=NULL)
deleteptr;
#endif
break;
}
casePAGEREPL_SC:
//4.4.4-SecondChance
{
#ifdefCHANGE
int*ptr=fifoList->Remove();
while(coreOwners[*ptr]->use)
{
coreOwners[*ptr]->use=false;
fifoList->Append(ptr);
ptr=fifoList->Remove();
}
victim=*ptr;
if(ptr!
=NULL)
deleteptr;
#endif
break;
}
casePAGEREPL_CLOCK:
//4.4.5-Clock
{
#ifdefCHANGE
while(coreOwners[clock_hand]->use)
{
coreOwners[clock_hand]->use=false;
clock_hand=(clock_hand+1)%NumPhysPages;
}
victim=clock_hand;
clock_hand=(clock_hand+1)%NumPhysPages;
#endif
break;
}
casePAGEREPL_WS:
//4.4.8-WorkingSet
{
intv_timestamp=stats->totalTicks;
#ifdefCHANGE
for(inti=0;i!
=NumPhysPages;i++)
{
if(coreOwners[i]->timeStamp { v_timestamp=coreOwners[i]->timeStamp; victim=i; } } #endif break; } casePAGEREPL_AGING: //4.4.7-Aging { unsignedintv_bitmask=0xFFFF; #ifdefCHANGE for(inti=0;i! =NumPhysPages;i++) { if(history[i] { v_bitmask=history[i]; victim=i; } } #endif break; } voidMemManager: : doUpdation(intarg) { inti; //MP3-makeanyneededchangestothisfunction if(someVerbose) printf("(update)%c",(++formatCount%5==0? '\n': ',')); switch(policy) { casePAGEREPL_NRU: //NotRecentlyUsedSection4.4.2 { #ifdefCHANGE inti; for(i=0;i! =NumPhysPages;i++) { if(coreFreeMap->Test(i)) coreOwners[i]->use=false; } #endif break; } casePAGEREPL_AGING: //AgingSection4.4.7 { #ifdefCHANGE for(i=0;i! =NumPhysPages;i++) { if(coreFreeMap->Test(i)) { history[i]=history[i]>>1; if(coreOwners[i]->use) { history[i]=history[i]|(1<<(hbits-1)); coreOwners[i]->use=FALSE; } } } #endif break; } //thefollowingdon'tusethetimerinterrupt casePAGEREPL_FIFO: //notused casePAGEREPL_SC: //notused casePAGEREPL_CLOCK: //notused casePAGEREPL_WS: //notused default: break; }//endswitch return; } voidMemManager: : pageIn(TranslationEntry*PTEntry,intphysFrame) { ……………………………… //MP3-youneedtomakechangestothehistorykeepingalgorithmshere //FIFOandSecondChancehavebeenimplementedforyou switch(policy) { casePAGEREPL_FIFO: //4.4.3-FIFO casePAGEREPL_SC: //4.4.4-SC { int*ptr=newint; *ptr=physFrame; fifoList->Append(ptr); break; } casePAGEREPL_AGING: //4.4.7-AGING { #ifdefCHANGE history[physFrame]=bitmask; #endif break; } casePAGEREPL_NRU: //4.4.2-NRU casePAGEREPL_CLOCK: //4.4.5-CLOCK casePAGEREPL_WS: //4.4.8-WS default: break; } return; } (1)NRU算法的实现: 此算法是用R位和M位来构造的,R位在每次时间中断是被清零,以区别最近没有被访问和被访问的页面,在系统中,R位和M位分别对应TranslationEntrys中的use和dirty字段,每次中断时,系统会调用doUpdation来进行中断处理,因此我们必须在doUpdation中将内存中所有页面的R位清零,也就是将use字段设为false。 具体实现是在switch语句中的casePAGEREPL_NRU中加入: inti; for(i=0;i! =NumPhysPages;i++) { if(coreFreeMap->Test(i)) coreOwners[i]->use=false; } 要注意的是,在设置use字段时,如果此时coreOwners[i]指向的内存页面为空就会发生严重的错误,所以我们必须在设置之前加入一个判断语句if(coreFreeMap->Test(i)),通过测试空闲位图的第i位(0为空,1为非空),来判断此页是否为空。 当页面发生失效时,根据页面的R位和M位将其分为4类: ●第0类: use=false,dirty=false ●第1类: use=false,dirty=true ●第2类: use=true,dirty=false ●第3类: use=true,dirty=true 我们将从最小编号的非空类中,选择第一个页面将其淘汰,具体实现是在makeFreeFrame中switch语句的casePAGEREPL_NRU中加入3个for循环: inti; boolfind=false; for(i=0;(i! =NumPhysPages)&&(! find);i++) { if((! coreOwners[i]->use)&&(! coreOwners[i]->dirty)) { victim=i; find=true; } } for(i=0;(i! =NumPhysPages)&&(! find);i++) { if((! coreOwners[i]->use)&&(coreOwners[i]->dirty)) { victim=i; find=true; } } for(i=0;(i! =NumPhysPages)&&(! find);i++) { if((coreOwners[i]->use)&&(! coreOwners[i]->dirty)) { victim=i; find=true; } } 这三个for循环依次寻找第0,1,2类页面,如果找到符合条件的页面,victim的值被置为i,即符合条件的页面号,此页面将被置换掉,同时将find变量置为true,之后的循环便不再执行。 当三个for循环执行完后,仍未找到符合条件的页面,那么所有页面都属于第3类,victim的值是默认的0,即第一个页面。 在实现这个算法的过程中,我曾考虑过用两个循环来实现,第一个循环检查每一类中是否有符合条件的页面,第二个循环在最小类中寻找一个符合条件的页面,由于在第一个循环中,无论编号较小的类中是否有页面,循环都必须继续,平均代价比三个for循环更大,所以最终决定用三个for循环来实现。 (2)SC算法的实现: SC算法只是对FIFO算法进行简单的修改: 检查最老页面的use字段,如果为false,就置换此页面;如果为true,就将它置为false,并将此页面放到FIFO列表的末端。 具体实现是在makeFreeFrame中switch语句的casePAGEREPL_SC中加入: int*ptr=fifoList->Remove(); while(coreOwners[*ptr]->use) { coreOwners[*ptr]->use=false; fifoList->Append(ptr); ptr=fifoList->Remove(); } victim=*ptr; if(ptr! =NULL) deleteptr; 我们用fifoList->Remove()取出FIFO链表头的页面号,即最老的页面号,用一个int指针指向该页面号,并判断该页面的use字段,如果为true,就将它置为false,并就调用fifoList->Append(ptr)函数将此页面号插入到FIFO链表的末端,继续取下一个链表头的页面号;如果为false,就将此页面号赋给victim,将此页面置换掉。 最后将ptr指针指向的内存区域清空。 (3)CLOCK算法的实现: Clock算法和SC算法的区别仅是实现上的不同,它将所有页面保存在一个类似钟面的环形链表中,用一个指针指向最老的页面,以减少SC算法在链表中移动页面的代价。 我们用coreOwners数组和求模操作来模拟环形链表,用一个clock_hand的正型变量来模拟表针。 具体实现是在makeFreeFrame中switch语句的casePAGEREPL_CLOCK中加入: while(coreOwners[clock_hand]->use) { coreOwners[clock_hand]->use=false; clock_hand=(clock_hand+1)%NumPhysPages; } victim=clock_hand; clock_hand=(clock_hand+1)%NumPhysPages; clock_hand的值初始化为0,我们先判断第一个页面的use字段,如果true,表示它最近被使用到,将use设为false,并将clock_hand的值置为(clock_hand+1)%NumPhysPages,进入下一次循环。 这里的求模操作是一个关键,它保证了clock_hand的值在0到NumPhysPages之间循环,类似于一个表针。 如果clock_hand所指的页面use字段为false,循环结束,将victim的值赋为clock_hand,此页面将被置换掉,并将表针向前移动一格,也就是将clock_hand的值设为(clock_hand+1)%NumPhysPages。 (4)WorkingSet算法的实现: 这个算法中,我们认为最早被访问的那个页面不在工作集中,将它置换出去,也就是说,我们要在内存中寻找最后一次访问时间最小的那个页面。 页面中与最后访问时间相对应的是timeStamp字段,每次访问一个页面时,timeStamp都会被更新为访问时的时间。 具体实现是在makeFreeFrame中switch语句的casePAGEREPL_WS中加入: for(inti=0;i! =NumPhysPages;i++) { if(coreOwners[i]->timeStamp { v_timestamp=coreOwners[i]->timeStamp; victim=i; } } v_timestamp的初始值是当前系统时间,所有页面的最后访问时间都小于当前系统时间,所以可以将v_timestamp作为一个临时变量,在遍历所有页面的时候储存最小的最后访问时间,我们用一个for循环遍历内存中的所有页面,并将每个页面的timeStamp与v_timestamp比较,如果小于v_timestamp,就将v_timestamp的值设为当前页面的timeStamp,并将victim的值置为当前页面号。 这样,当遍历完所有页面时,v_timestamp值为所有页面的timeStamp的最小值,而victim的值也恰好是最小timeStamp值对应的页面,此页面将被置换出去。 (5)Aging算法的实现: 在此算法中,每一个内存页面都分配了一个特定位数的计数器,每次时钟中断时,将所有计数器值右移一位,然后将计数器的最高位设为R位的值,发生页面失效时,淘汰计数器值最小的页面。 用一个无符号整形变量来表示一个计数器,无符号整形数组history的每一项代表一个页面的计数器,我们需要在调入页面的时候初始化计数器的值,具体实现是在pageIn的switch语句的casePAGEREPL_AGING中加入: history[physFrame]=bitmask; 整形变量bitmask的值为(1< 因为我们要置换的是计数器值最小的页面,所以在页面刚刚调入时,我们必须将其计数器的值初始化为最大值,如果初始化为0,有可能出现页面刚刚被调入,又立刻被置换出去的情况,不符合要求。 每次时间中断时,我们必须将计数器右移一位,将指定位数的计数器最高位设为页面的R位,即use字段,并将所有页面的use字段设为false。 具体实现是在doUpdations的witch语句中的casePAGEREPL_AGING加入: for(i=0;i! =NumPhysPages;i++) { if(coreFreeMap->Test(i)) { history[i]=history[i]>>1; if(coreOwners[i]->use) { history[i]=history[i]|(1<<(hbits-1)); coreOwners[i]->use=FALSE; } } } 我们用一个for循环遍历内存的每个页面。 在对计数器修改之前,要先判断页面是否为空,如果为空,我们并不需要修改它的计数器。 如果不为空,我们用history[i]=history[i]>>1将其计数器的值右移一位。 然后,我们继续判断该页面的use字段,如果为false,无需改变,因为右移一位后,最高位
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 实验 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)