一、实验内容
(1)设程序中地址范围为0 到32767 ,采用随机数生成256 个指令地址,满足50%的地址是顺序执行,25%向前跳,25% 向后跳。为满足上述条件,可采取下列方法:设d0=10000,第 n个指令地址为dn,第 n+1 个指令地址为dn+1 ,n的取值范围为0 到255。每次生成一个 1 到1024范围内的随机数a,如果a落在1 到512 范围内,则dn+1 =dn+1。如果a落在513 到768范围内,则设置dn+1 为1 到dn范围内一个随机数。如果a落在769 到1024范围内,则设置dn+1 为dn到32767 范围内一个随机数。
通过随机数产生一个指令序列,共320条指令。其地址按下述原则生成:
①50%的指令是顺序执行的;
②25%的指令是均匀分布在前地址部分;
③25%的指令是均匀分布在后地址部分;
将指令序列变换为页地址流
1k 的地址大小范围为1024
页面大小的取值范围为1K,2K,4K,8K,16K 。按照页面大小将指令
地址转化为页号。对于相邻相同的页号,合并为一个。
分配给程序的内存块数取值范围为1 块,2 块,直到程序的页面数。
分别采用OPT、FIFO 和LRU算法对页号序列进行调度,计算出对应
的缺页中断率。
计算并输出下述各种算法在不同内存容量下的缺页中断率
v FIFO先进先出的算法
v LRU最近最少使用算法
v LFU最少访问页面算法
二、实验原理
(一)OPT:最佳置换算法
该算法选择淘汰的页面将是以后永远不再使用,或者是在将来最长时间内不再被访问的页面,这样产生的缺页中断次数是最少的。
(二)FIFO:先进先出置换算法
该算法认为刚被调入的页面在最近的将来被访问的可能性是很多的,而在主存中驻留时间最长的页面在最近的将来被访问的可能性最小
(三)LRU:最近最少用置换算法
该算法总是选择最近一段时间内最长时间没有被访问过的页面调出
为了记录自上一次被访问以来所经过的时间,需要在页表中增加一个引用位,每次被访问后将引用位置0,重新计时。
三、算法实现
整体实现思路:
首先根据上述产生指令的原则产生256条指令,然后通过随机数随机产生程序运行所需的320条指令序列。
根据输入的页面大小(1、2、4、8、16k),按照页面大小将320条指令地址转化为页号,每一条指令地址都对应一个页面号,这样也就获得了320个页面号组成的序列。
对上述获得的页面号序列处理,对于相邻相同的页号,合并为一个。 例如:页面号:.....12 14 14 6 8 9.... 合并后:....12 14 6 8 9 ....
根据输入的内存分配块数分配相应的内存块
OPT算法实现
FIFO算法实现
LRU算法实现
实现的过程如下:
1、数据结构---页内容
struct pageInformation
{
int ID; //页面号
int visit; //被访问标记
};
2、对于这个实验所用到的所有处理我整合成一个类,在类中处理所有的内容。--Pager类
①两个重要的数据变量
private:
int count; //页面中断次数
int blockNum; //系统分配的内存块
②相关的操作
(1)void creatInstructions();产生320条指令。其中注意产生随机数时要注意设定种子,这样重复运行时才会产生出不同的指令序列
srand((unsigned)time(NULL)); //随机数种子
(2)void convertToPage(int pageSize);根据页面大小转换指令序列成页面序列
(3)void mergence();对页面序列进行合并操作
(4)//根据分配物理块数初始化物理块
void creatBlock(int n)
{
blockNum = n;
initalPhysicalBlock();
}
void initalPhysicalBlock()
{
block = new pageInformation[blockNum];
BlockClear(blockNum);
}
//置分配的物理块的初值
void BlockClear(int blockNum)
{
for(int i=0; i<blockNum; i++)
{
block[i].ID = -1;
block[i].visit = 0;
}
}
③下面介绍三个算法的实现思路(由于代码长度,不贴了)
For循环合并后的页面序列,首先查找在内存中是否存在当前要调度的页面,如果存在就不用进行页面缺页中断处理;否则,进行缺页中断。
缺页中断分成两种情况:
1、在内存中存在空闲的位置,直接将当前调度的页面调入内存(一般出现在调度的开始时候)
2、内存中没有空闲位置,就需要选择内存的某一个页面调出,以让当前的调度页面进入内存。注意这里淘汰的依据是引用位visit的大者。
//查找应予置换的页面
int findReplace()
{
int pos = 0;
for(int i=0; i<blockNum; i++)
if(block[i].visit >= block[pos].visit)
pos = i;//找到应予置换页面,返回BLOCK中位置
return pos;
}
FIFO:淘汰的是主存中驻留时间最长的页面,所以每一次调度都需要计算(增加)内存中页面的的驻留时间。那么在进行缺页中断的时候根据这个时间就可以选择要淘汰的页面了。
实现的代码如下:
for(int j=0; j<blockNum; j++)
block[j].visit++;
LRU:淘汰最近一段时间内最长时间没有被访问过的页面,注意到,每一次调度后都有将引用位复位成0,重新计时。(这个要注意与FIFO的区别)。那么处理的方法是:在页面调度过程中,如果访问的页面在内存中,就不用进行缺页中断,但是要注意将访问引用位置为0;其次在每一次调度过程中也是要增加驻留时间。
实现的代码如下:
if(exist != -1)
{
writeToFile<<"----------------------------"<<endl;
writeToFile<<"即将访问的是页面"<<page[i].ID<<"----内存中已存在该页"<<endl;;
writeToFile<<"----------------------------"<<endl;
//每一次页面被访问后,重新计时
block[exist].visit = 0;//恢复存在的并刚访问过的BLOCK中页面visit为0
}
for(int j=0; j<blockNum; j++)
block[j].visit++;
OPT:淘汰的页面将是以后永远不再使用,或者是在将来最长时间内不再被访问的页面,那么就要对后续的页面进行预读,并将他们的访问引用位置为最早遇到的页面号,如果在后续的页面中没有出现,那么他的访问引用位就置为最大,就是肯定要被淘汰的。
实现的代码如下:(下面的代码预读所有的后续页面,同时也可以进行设置相关的预读页面数,修改下面代码中的pageNum就可以了。)
for(int k=0; k<blockNum; k++)
for(int j=i; j<pageNum; j++) //修改这里的j<pageNum 就可以改变预读后续页面的页数
{
if(block[k].ID != page[j].ID)
{
block[k].visit = 1000;
}
else
{
block[k].visit = j;
break;
}
}
④输出相关信息
在程序调度过程中会输出相关的详细调度信息,由于行数多,所有以输出到文件中。
⑤主界面处理
可以重复选择调度算法进行调度,同时页面大小和系统分配的页面块数也是通过用户输入的方式。
四、程序界面
在程序运行结束后就会在当前目录下生成对应的详细调度信息文件。
输出文件的调度信息如下
下面附上全部的代码:
//已经完成的页面调度算法 #include <iostream> #include <stdlib.h> #include <fstream> #include <ctime> using namespace std; struct pageInformation { int ID; //页面号 int visit; //被访问标记 }; pageInformation * block; //物理块 pageInformation * page; //合并后的页面号串 pageInformation * oriPage; //原生的320条指令所对应的320页 int instructions[320]; //原生的320条指令 int pageNum; //合并后的页面数 class Pager { private: int count; //页面中断次数 int blockNum; //系统分配的内存块 public: //初始化生成320条指令 void creatInstructions() { //生成256 个指令地址 Instruction address 地址范围为0 到32767 int insAdress[256]; insAdress[0] = 10000; srand((unsigned)time(NULL)); //随机数种子 for(int i=1; i<256; i++) { int random = rand()%1024+1; if(random>=1 && random<=512) { insAdress[i] = insAdress[i-1]+1; } else if(random>=513 && random<=768) { int random2 = rand()%insAdress[i-1]+1; insAdress[i] = random2; } else if(random>=769 && random<=1024) { int random3 = rand()%(32767-insAdress[i-1])+insAdress[i-1]; insAdress[i] = random3; } } //生成320条指令 for(int j=0; j<320; j++) { int r = rand()%256; instructions[j] = insAdress[r]; } } //将指令转换成页号 void convertToPage(int pageSize) { oriPage = new pageInformation[320]; //一条指令对于一页 int num = pageSize*1024; //每一页存放的指令条数 //对第一条指令做特殊处理 oriPage[0].ID = 0; for(int i=1; i<320; i++) { oriPage[i].visit = 0; int a = instructions[i]/num; int b = instructions[i]%num; if(b) oriPage[i].ID = a; else oriPage[i].ID = a+1; } } //对于相邻相同的页号,合并为一个。 void mergence() { pageNum = 0; page = new pageInformation[320]; //解决思路:依次扫描oriPage数组,和page中的最后一个数组比较,如果不同就写入page,相同就不用写入。 page[0] = oriPage[0]; for(int i=1; i<320; i++) { //如果不同就写入mergePage if(page[pageNum].ID != oriPage[i].ID) { pageNum++; page[pageNum] = oriPage[i]; } } } //初始化物理块 void creatBlock(int n) { blockNum = n; initalPhysicalBlock(); } void initalPhysicalBlock() { block = new pageInformation[blockNum]; BlockClear(blockNum); } //置分配的物理块的初值 void BlockClear(int blockNum) { for(int i=0; i<blockNum; i++) { block[i].ID = -1; block[i].visit = 0; } } //查找是否有空闲内存块 int findSpace() { for(int i=0; i<blockNum; i++) if(block[i].ID == -1) return i;//找到空闲内存,返回BLOCK中位置 return -1; } //查找内存中是否有该页面 int findExist(int curpage) { for(int i=0; i<blockNum; i++) if(block[i].ID == page[curpage].ID) return i;//找到内存中有该页面,返回BLOCK中位置 return -1; } //查找应予置换的页面 int findReplace() { int pos = 0; for(int i=0; i<blockNum; i++) if(block[i].visit >= block[pos].visit) pos = i;//找到应予置换页面,返回BLOCK中位置 return pos; } //显示 void display(ofstream &fileStream) { fileStream<<"----------------------------"<<endl; for(int i=0; i<blockNum; i++) if(block[i].ID != -1) fileStream<<block[i].ID<<" "; fileStream<<endl; fileStream<<"----------------------------"<<endl; } //FIFO算法 void FIFO() { ofstream writeToFile("FIFO-Manager.txt"); count=0; int exist,space,position ; for(int i=0; i<pageNum; i++) { //查找内存中是否存在该页 exist = findExist(i); if(exist != -1) { writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"----内存中已存在该页"<<endl; writeToFile<<"----------------------------"<<endl; } //内存块中不存在,进行缺页中断的调度 else { count++; space = findSpace(); //在内存块中找到空闲的位置,这个时候也是要中断的 if(space != -1) { block[space] = page[i]; display(writeToFile); } else { position = findReplace(); writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"将被置换出的是页面"<<block[position].ID<<endl; writeToFile<<"----------------------------"<<endl; block[position] = page[i]; display(writeToFile); } } //计算页面在内存块中驻留的时间,每一次都+1,如果越大,说明驻留时间最长,就淘汰他 for(int j=0; j<blockNum; j++) block[j].visit++;//BLOCK中所有页面visit++ } writeToFile.close(); cout<<"调度过程请看文件 FIFO-Manager.txt"<<endl; cout<<"缺页次数:"<<count<<endl; cout<<"FIFO算法的缺页率是:"<<(float)count/pageNum<<endl; } //LRU算法 void LRU() { ofstream writeToFile("LRU-Manager.txt"); int exist,space,position; count=0; for(int i=0; i<pageNum; i++) { exist = findExist(i); if(exist != -1) { writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"----内存中已存在该页"<<endl;; writeToFile<<"----------------------------"<<endl; //每一次页面被访问后,重新计时 block[exist].visit = 0;//恢复存在的并刚访问过的BLOCK中页面visit为0 } else { count++; space = findSpace(); if(space != -1) { block[space] = page[i]; display(writeToFile); } else { position = findReplace(); writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"将被置换出的是页面"<<block[position].ID<<endl; writeToFile<<"----------------------------"<<endl; block[position] = page[i]; display(writeToFile); } } //计时 for(int j=0; j<blockNum; j++) { block[j].visit++; } } writeToFile.close(); cout<<"调度过程请看文件 LRU-Manager.txt"<<endl; cout<<"缺页次数:"<<count<<endl; cout<<"FIFO算法的缺页率是:"<<(float)count/pageNum<<endl; } //OPT算法 void OPT() { ofstream writeToFile("OPT-Manager.txt"); int exist,space,position ; count=0; for(int i=0; i<pageNum; i++) { exist = findExist(i); //页已经在内存块中 if(exist != -1) { writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"----内存中已存在该页"<<endl; writeToFile<<"----------------------------"<<endl; } else { count++; space = findSpace(); if(space != -1) { block[space] = page[i]; display(writeToFile); } else { for(int k=0; k<blockNum; k++) for(int j=i; j<pageNum; j++) //修改这里的j<pageNum 就可以改变预读后续页面的页数 { if(block[k].ID != page[j].ID) { block[k].visit = 1000; } else { block[k].visit = j; break; } } position = findReplace(); writeToFile<<"----------------------------"<<endl; writeToFile<<"即将访问的是页面"<<page[i].ID<<"将被置换出的是页面"<<block[position].ID<<endl; writeToFile<<"----------------------------"<<endl; block[position] = page[i]; display(writeToFile); } } } writeToFile.close(); cout<<"调度过程请看文件 OPT-Manager.txt"<<endl; cout<<"缺页次数:"<<count<<endl; cout<<"FIFO算法的缺页率是:"<<(float)count/pageNum<<endl; } }; int main() { while(1) { int selection; cout<<"----请输入调度算法:1:OPT 2:FIFO 3:LRU---->>"; cin>>selection; int pSize,num; cout<<"----请输入页面大小:(1、2、4、8、16K):"; cin>>pSize; cout<<"----请输入系统分配的内存块数:"; cin>>num; Pager test; test.creatInstructions(); test.convertToPage(pSize); test.mergence(); test.creatBlock(num); if(selection == 1) { test.OPT(); } else if(selection == 2) { test.FIFO(); } else if(selection == 3) { test.LRU(); } delete page; delete oriPage; delete block; cout<<endl; } return 0; }