操作系统实验报告2.docx

上传人:b****6 文档编号:4123463 上传时间:2022-11-28 格式:DOCX 页数:14 大小:21.92KB
下载 相关 举报
操作系统实验报告2.docx_第1页
第1页 / 共14页
操作系统实验报告2.docx_第2页
第2页 / 共14页
操作系统实验报告2.docx_第3页
第3页 / 共14页
操作系统实验报告2.docx_第4页
第4页 / 共14页
操作系统实验报告2.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

操作系统实验报告2.docx

《操作系统实验报告2.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告2.docx(14页珍藏版)》请在冰豆网上搜索。

操作系统实验报告2.docx

操作系统实验报告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,无需改变,因为右移一位后,最高位

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 职业教育 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1