结构设计
设置物理页框个数为6,设置页面大小为32,虚拟页个数至多320个。设置有一个访问序列vis,该序列长度为3200000。
对于物理页框的结构,由于其需要存储该单元的新数据被加载的时间、最近一次命中的时间以及该单元内存放的虚拟页的页号,因此使用如下结构体:
const int phy_page_num = 6;
const int page_size = 320;
const int visit_time = 3200000; //访问次数
struct cmd{
int pos; //虚拟页号
int last_hit; //上一次命中的时间
int in_time; //最新的加载进内存的时间
}cmd[phy_page_num];
int vis[visit_size];
初始化
使用rand()
函数生成访问序列vis。在每次序列进行加载前,对物理页框进行初始化。具体如下:
void init_visit(){ //生成访问序列
srand((unsigned)time(NULL)); //利用随机数模拟访问顺序
for(int i = 0; i < visit_time; ++i){
vis[i] = rand() % page_size;
}
}
void init_phy(){ //初始化物理页
for(int i = 0; i < phy_page_num; ++i){
cmd[i].pos = -1;
cmd[i].last_hit = -1; //表示该内存中没有加载数据
cmd[i].in_time = -1;
}
}
FIFO算法
遍历内存中的所有物理块:当内存中存储的虚拟页号与要访问的页号相同时,此时命中,更新最近一次命中时间并退出循环。当内存中的物理块中记录的加载时间为-1
时表示该物理块未使用,此时记录该物理块号并退出循环。当物理块中记录的加载时间小于遍历到当前为止加载时间的最短时间时,记录该物理块号,继续循环。
遍历物理块后,若命中,则命中次数cnt
递增1,否则更新所记录的物理块的信息。
当遍历完整个访问序列后,计算命中率。具体代码实现如下:
double FIFO(){ //FIFO算法
int id, cnt = 0;
bool get_it;
for(int i = 0; i < visit_time; ++i){
id = 0; //指向应该被替换的物理页号
get_it = false;
for(int j = 0; j < phy_page_num; ++j){
if(cmd[j].pos == vis[i]){
get_it = true;
cmd[j].last_hit = i;
break;
}
else if(cmd[j].in_time == -1){
id = j;
break;
}
else if(cmd[j].in_time < cmd[id].in_time) id = j;
}
if(!get_it){
cmd[id].pos = vis[i];
cmd[id].last_hit = i;
cmd[id].in_time = i;
}
else cnt++;
}
double res = (double)cnt / (double)visit_time * 100.0;
return res;
}
LRU算法
遍历内存中的所有物理块:当内存中存储的虚拟页号与要访问的页号相同时,此时命中,更新最近一次命中时间并退出循环。当内存中的物理块中记录的加载时间为-1
时表示该物理块未使用,此时记录该物理块号并退出循环。当物理块中记录的最近命中时间小于遍历到当前为止最近命中时间的最短时间时,记录该物理块号,继续循环。
遍历物理块后,若命中,则命中次数cnt
递增1,否则更新所记录的物理块的信息。
当遍历完整个访问序列后,计算命中率。具体代码实现如下:
double LRU(){ //最近最少使用算法
int id, cnt = 0;
bool get_it;
for(int i = 0; i < visit_time; ++i){
id = 0;
get_it = false;
for(int j = 0; j < phy_page_num; ++j){
if(cmd[j].pos == vis[i]){
get_it = true;
cmd[j].last_hit = i;
break;
}
else if(cmd[j].in_time == -1){
id = j;
break;
}
else if(cmd[j].last_hit < cmd[id].last_hit) id = j;
}
if(!get_it){
cmd[id].pos = vis[i];
cmd[id].last_hit = i;
cmd[id].in_time = i;
}
else cnt++;
}
double res = (double)cnt / (double)visit_time * 100.0;
return res;
}
main函数实现
对两个算法测试5次,生成5个不同的访问序列,每次测试之间间隔1秒。代码如下:
int main(){
int cnt = 5;
while(cnt--){
init_visit(); //初始化虚拟页号的访问顺序和物理页的记录状态等
init_phy();
printf("FIFO Hit Rate : %.6lf%\n", FIFO()); //先进先出算法模拟
init_phy();
printf("LRU Hit Rate : %.6lf%\n", LRU()); //最近最少使用算法模拟
putchar('\n');
Sleep(1000);
}
return 0;
}
测试及结果
观察到对于随机的访问序列,两者的命中率大致相同,这与理论保持一致;在5次模拟测试中,命中率结果在1.8%左右小幅波动。