本次实验要模拟三种cache替换算法(FIFO, LRU, OPT),并且给出相应的缺页率。
首先说明一下符号定义:
int array[100]; // 请求访问的内存地址数组,需要依此访问array[0], array[1], ....
int page[100]; // 请求访问的页面数,规定一个页面大小为100,也就是说,page[0]:0-99,
// page[1]:100-199
// 因此,将第i个请求地址映射到对应的页面号的公式:page[i] = array[i]/100+1
int pageSize = 3, size; // 缓存中一共能够存储3个页面,size为请求访问的地址数目
bool bre; // 终端标志,如果缓存中发生缺页,那么bre=true
每种替换算法,采用函数的方式实现。
主函数如下:
int main()
{
int i, select;
bool judge = true;
cout << "输入地址总数和地址序列:" << endl;
cin >> size;
for (int i = 0; i < size; i ++)
{
cin >> array[i];
page[i] = array[i] / 100 + 1;
}
while(judge) // 一直循环
{
cout << "1:FIFO" << endl;
cout << "2:LRU" << endl;
cout << "3:OPT" << endl;
cin >> select; // 输入你想观察的算法编号
switch(select) // 调用相应的算法求解
{
case 1: FIFO(); break;
case 2: LRU(); break;
case 3: OPT(); break;
}
}
return 0;
}
每个算法会定义相应的cache中的缓存页队列que,表示已经缓存的页面编号,并且从队首到队尾表示最先到最近访问的页面。
(1)FIFO
void FIFO()
{
int queye = 1, i;
cout << "FIFO" << endl;
queue<int> que;
// 加载第一个访问的页面
que.push(page[0]);
// 一定会发生冷不命中
bre = true;
// 打印函数(打印当前访问的页面以及cache中缓存的页面编号)(见下一个代码段)
print(que, page[0]);
// 按照输入的顺序依此访问页面
for (i = 1; i < size; i ++)
{
// isEqual(queue<int> que, int x)函数,判断que中是否有x (见下下个代码段)
// 也就是判断cache中是否已经缓存了页面page[i],缓存了返回true,否则返回false
if(!isEqual(que, page[i])) // 缺页
{
bre = true; // 终端标志=true
if(que.size() < 3) // 如果缓存页数小于3
//(表示刚刚启动,发生的都是冷不命中,只需要将相应页加载进缓存即可)
{
que.push(page[i]);
queye++;
}
else{ // 发生的是冲突不命中,需要替换,这里是FIFO(First In First Out)
que.pop(); // 将最先加载的的弹出
// 注意**这里是将最先加载的弹出,而LRU是将最早访问的弹出**
que.push(page[i]); // push进入队列
queye++;
}
print(que, page[i]);
}
else // 命中
{
bre = false;
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size; // 计算缺页率
cout << "缺页率:" << queyelv << endl;
}
void print(queue<int> que, int p)
{
printf("调用的页面为:%d", p);
if(bre) cout << " 产生中断: ";
else cout << " 不产生中断: ";
while(que.size())
{
cout << que.front() << " ";
que.pop();
}
cout << endl;
}
bool isEqual(queue<int> que, int num)
{
while(que.size())
{
if(que.front() == num)
return true;
que.pop();
}
return false;
}
(2)LRU(Latest Recently Used)
void LRU()
{
int queye = 1, i;
cout << "LRU" << endl;
queue<int> que;
que.push(page[0]);
bre = true;
print(que, page[0]);
for (i = 1; i < size; i ++)
{
if(!isEqual(que, page[i]))
{
bre = true;
if(que.size() < 3)
{
que.push(page[i]);
queye++;
}
else
{
// 不命中,将最早访问的弹出
que.pop();
que.push(page[i]);
queye++;
}
print(que, page[i]);
}
else // 命中,但是需要更新一下队列,将这个访问页面放到队列末尾,表示最近访问
{
bre = false;
que = LRU_update(que, page[i]); // 更新队列函数(见下一个代码段)
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size;
cout << "缺页率:" << queyelv << endl;
}
queue<int> LRU_update(queue<int> que, int num)
{
queue<int> que1;
while(que.size())
{
if(que.front() != num)
{
que1.push(que.front());
}
que.pop();
}
que1.push(num);
return que1;
}
(3)OPT(optimal)
void OPT()
{
int queye = 1;
cout << "OPT" << endl;
queue<int> que;
que.push(page[0]);
bre = true;
print(que, page[0]);
for (int i = 1; i < size; i ++)
{
if(!isEqual(que, page[i]))
{
bre = true;
if(que.size() >= 3)
{
int remove_element = select_most_far(i, que); // 找到最优替换页的函数(见下一个代码段)
que = OPT_update(que, page[i], remove_element); // 更新队列
print(que, page[i]);
}
else
{
que.push(page[i]);
print(que, page[i]);
}
queye++;
}
else
{
bre = false;
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size;
cout << "缺页率:" << queyelv << endl;
}
// 比对缓存中的三个页面在未来的访问顺序中的距离(距离越大,表示未来越晚访问该页面)
// 找到未来最晚访问的已缓存页面,并return页面编号
// index表示目前正在处理哪一个访问
int select_most_far(int index, queue<int> que)
{
int a = que.front();
que.pop();
int b = que.front();
que.pop();
int c = que.front();
int dis1 = 10000000, dis2 = 10000000, dis3 = 10000000, i, max;
index ++;
for (int i = index; i < size; i ++)
{
if(page[i] == a){
dis1 = i - index;
break;
}
}
for (int i = index; i < size; i ++)
{
if(page[i] == b){
dis2 = i - index;
break;
}
}
for (int i = index; i < size; i ++)
{
if(page[i] == c){
dis3 = i - index;
break;
}
}
int result;
if(dis1 > dis2){
max = dis1;
result = a;
}
else{
max = dis2;
result = b;
}
if(max > dis3) return result;
else return c;
}
queue<int> OPT_update(queue<int> que, int insert_element, int remove_element)
{
queue<int> que1;
while(que.size())
{
if(que.front() != remove_element)
que1.push(que.front());
que.pop();
}
que1.push(insert_element);
return que1;
}
下面是完整程序代码:
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
int array[100]; // 请求访问的内存地址数组,需要依此访问array[0], array[1], ....
int page[100]; // 请求访问的页面数,规定一个页面大小为100,也就是说,page[0]:0-99,
// page[1]:100-199
// 因此,将第i个请求地址映射到对应的页面号的公式:page[i] = array[i]/100+1
int pageSize = 3, size; // 缓存中一共能够存储3个页面,size为请求访问的地址数目
bool bre; // 终端标志,如果缓存中发生缺页,那么bre=true
// 在
bool isEqual(queue<int> que, int num)
{
while(que.size())
{
if(que.front() == num)
return true;
que.pop();
}
return false;
}
void print(queue<int> que, int p)
{
printf("调用的页面为:%d", p);
if(bre) cout << " 产生中断: ";
else cout << " 不产生中断: ";
while(que.size())
{
cout << que.front() << " ";
que.pop();
}
cout << endl;
}
// Least Recently used
// make "num" the last element in queue
queue<int> LRU_update(queue<int> que, int num)
{
queue<int> que1;
while(que.size())
{
if(que.front() != num)
{
que1.push(que.front());
}
que.pop();
}
que1.push(num);
return que1;
}
// optimal
// delete remove_element
// and push insert_element into the queue(tail)
queue<int> OPT_update(queue<int> que, int insert_element, int remove_element)
{
queue<int> que1;
while(que.size())
{
if(que.front() != remove_element)
que1.push(que.front());
que.pop();
}
que1.push(insert_element);
return que1;
}
// find the remotest one in the requring page array
int select_most_far(int index, queue<int> que)
{
int a = que.front();
que.pop();
int b = que.front();
que.pop();
int c = que.front();
int dis1 = 10000000, dis2 = 10000000, dis3 = 10000000, i, max;
index ++;
for (int i = index; i < size; i ++)
{
if(page[i] == a){
dis1 = i - index;
break;
}
}
for (int i = index; i < size; i ++)
{
if(page[i] == b){
dis2 = i - index;
break;
}
}
for (int i = index; i < size; i ++)
{
if(page[i] == c){
dis3 = i - index;
break;
}
}
int result;
if(dis1 > dis2){
max = dis1;
result = a;
}
else{
max = dis2;
result = b;
}
if(max > dis3) return result;
else return c;
}
void FIFO()
{
int queye = 1, i;
cout << "FIFO" << endl;
queue<int> que;
que.push(page[0]);
bre = true;
print(que, page[0]);
for (i = 1; i < size; i ++)
{
if(!isEqual(que, page[i]))
{
bre = true;
if(que.size() < 3)
{
que.push(page[i]);
queye++;
}
else{
que.pop();
que.push(page[i]);
queye++;
}
print(que, page[i]);
}
else
{
bre = false;
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size;
cout << "缺页率:" << queyelv << endl;
}
void LRU()
{
int queye = 1, i;
cout << "LRU" << endl;
queue<int> que;
que.push(page[0]);
bre = true;
print(que, page[0]);
for (i = 1; i < size; i ++)
{
if(!isEqual(que, page[i]))
{
bre = true;
if(que.size() < 3)
{
que.push(page[i]);
queye++;
}
else
{
que.pop();
que.push(page[i]);
queye++;
}
print(que, page[i]);
}
else
{
bre = false;
que = LRU_update(que, page[i]);
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size;
cout << "缺页率:" << queyelv << endl;
}
void OPT()
{
int queye = 1;
cout << "OPT" << endl;
queue<int> que;
que.push(page[0]);
bre = true;
print(que, page[0]);
for (int i = 1; i < size; i ++)
{
if(!isEqual(que, page[i]))
{
bre = true;
if(que.size() >= 3)
{
int remove_element = select_most_far(i, que);
que = OPT_update(que, page[i], remove_element);
print(que, page[i]);
}
else
{
que.push(page[i]);
print(que, page[i]);
}
queye++;
}
else
{
bre = false;
print(que, page[i]);
}
}
double queyelv = (double) queye / (double) size;
cout << "缺页率:" << queyelv << endl;
}
int main()
{
int i, select;
bool judge = true;
cout << "输入地址总数和地址序列:" << endl;
cin >> size;
for (int i = 0; i < size; i ++)
{
cin >> array[i];
page[i] = array[i] / 100 + 1;
}
while(judge)
{
cout << "1:FIFO" << endl;
cout << "2:LRU" << endl;
cout << "3:OPT" << endl;
cin >> select;
switch(select)
{
case 1: FIFO(); break;
case 2: LRU(); break;
case 3: OPT(); break;
}
}
return 0;
}
效果截图: