1. 程式人生 > >作業系統實驗--頁面替換演算法

作業系統實驗--頁面替換演算法

作業系統實驗4–頁面替換演算法

基本資料結構

變數名 意義
pageNum 總頁面數
rsLen 引用串長度
frameNum 實體記憶體長度
rs[] 儲存引用串的陣列
frameArr[] 儲存實體記憶體的陣列
XXModeCounter XX演算法的缺頁計數器

最佳置換演算法

這裡寫圖片描述

隨機置換演算法

這裡寫圖片描述

FIFO置換演算法

這裡寫圖片描述

LRU置換演算法

這裡寫圖片描述

Clock置換演算法

這裡寫圖片描述

測試環境

作業系統:Windows 10 - x64
編譯器:MinGW
硬體:
    CPU:X86構架CPU 2.3 GHz
    記憶體:8GB 1600MHz DDR3

方案詳情

基本引數

  • 頁面總數 pageNum
  • 引用串長度 rsLen
  • 實體記憶體大小 frameNum
  • 引用串工作集 z
  • 引用串移動率 m
  • 引用串不穩定率 e

參考引數

這些引數的意義就是作為參考,在圍繞這些引數進行倍增,看看各個引數變化對缺頁率的影響是怎樣的。

  • pageNum = 100
  • rsLen = 10000
  • frameLen = 20
  • z = 5
  • m = 10
  • e = 0.2

隨機數生成方案

因為隨機數如果用時間函式作為種子就會發生1秒內的所有測試都是一樣的結果,這樣子在短時間內獲得較多的結果不太可能,所以我就使用了時間函式作為初始種子,在每一次實驗過程中都自加一

,保證了引用串生成的隨機性。

測試資料

每組引數測試100組資料,這個測試次數也可以調到更大,如果時間充足,可以測試更多組資料,但為了把測試資料的時間縮短到總共5分鐘,所以我大概估計了一下選擇了100

每組資料用時比我預想的要久,可能是因為我的最佳置換演算法每次缺頁都要比較距離,如果用一個數組把所有下一個頁面出現的位置都儲存起來會少很多工作。但因為資料結構太複雜了,我除錯了好多次都失敗了,所以就用了比較簡單直接的方法。

每組引數都儲存在不同的output_.csv檔案中,每個檔案包含100組資料。這些資料分別記錄了每種演算法的替換率,從左到右各列表示最佳置換演算法隨機置換演算法FIFO置換演算法

LRU置換演算法Clock置換演算法

下面是各組引數對應的原始資料檔案:

資料檔名 pageNum rsLen frameNum z m e
output1.csv 100 10000 20 5 10 0.2
output2.csv 500 10000 20 5 10 0.2
output3.csv 1000 10000 20 5 10 0.2
output4.csv 100 50000 20 5 10 0.2
output5.csv 100 100000 20 5 10 0.2
output6.csv 100 10000 50 5 10 0.2
output7.csv 100 10000 80 5 10 0.2
output8.csv 100 10000 20 5 10 0.5
output9.csv 100 10000 20 5 10 0.8
output10.csv 100 10000 20 5 50 0.2
output11.csv 100 10000 20 5 80 0.2
output12.csv 100 10000 20 10 10 0.2
output13.csv 100 10000 20 15 10 0.2

比較參考引數下各個置換演算法的替換率

對資料檔案output1.csv進行求平均值運算,得到各個演算法的平均替換率。

資料檔名 Best Random FIFO LRU CLOCK
output1.csv 0.099187 0.164114 0.147767 0.146462 0.298836

可以看到在引數為參考引數的時候:

  1. FIFO演算法隨機置換演算法小幅優越,優越了2%左右。LRU演算法FIFO演算法基本相當,前者優越了後者不到1%
  2. LRU演算法最佳置換演算法差距明顯,後者大幅優越於前者,大概優越了有接近20%。事實上最佳置換演算法大幅領先以上任何其他演算法,因為這個演算法是在確定引用串的情況下才能使用的,實際中基本無法實現。但我分析,在能估計到應用程式對於資源的請求順序及情況的時候,定製一套接近於最佳置換演算法的置換演算法也是可能的,比如說某些固定幾種操作的小型嵌入式系統。
  3. Clock演算法LRU演算法的差了一倍,效能甚至不如最簡單的FIFO演算法

總頁面數PageNum變化對演算法替換率的影響

對資料檔案output1.csv``output2.csv``output3.csv分別求平均值,得到各個演算法的平均替換率。

|BEST|RANDOM|FIFO|LRU|CLOCK|
|—|—|—|—|—|
0.099187|0.164114|0.147767|0.146462|0.298836|
0.141501|0.190631|0.168871|0.168571|0.360583|
0.151291|0.19409|0.171659|0.171526|0.369229|

繪製圖表。

這裡寫圖片描述

可以看到,隨著總頁面數的上升,各個演算法的替換率都開始上升,因為引用頁面更為的複雜了。

引用串長度RsLen變化對演算法替換率的影響

對資料檔案output1.csv``output4.csv``output5.csv分別求平均值,得到各個演算法的平均替換率。

|BEST|RANDOM|FIFO|LRU|CLOCK|
|—|—|—|—|—|
0.099187|0.164114|0.147767|0.146462|0.298836|
0.0996878|0.1648296|0.147628|0.1463678|0.2995668
0.0997916|0.164583|0.1476042|0.1463869|0.2999914

繪製圖表。

這裡寫圖片描述

可以看到,引用串長度變化對演算法替換率沒有影響。

實體記憶體大小FrameNum變化對演算法替換率的影響

對資料檔案output1.csv``output6.csv``output7.csv分別求平均值,得到各個演算法的平均替換率。

BEST RANDOM FIFO LRU CLOCK
0.099187 0.164114 0.147767 0.146462 0.298836
0.042269 0.097264 0.095484 0.094599 0.17822
0.01178 0.042507 0.044304 0.044083 0.076999

繪製圖表。

這裡寫圖片描述

可以看到,實體記憶體越大,各個演算法的替換率越低,說明大的實體記憶體可以顯著提升資源利用率。並且可以看到隨機置換演算法LRU演算法在越大的記憶體中替換率越接近。

引用串不穩定率e變化對演算法替換率的影響

對資料檔案output1.csv``output8.csv``output9.csv分別求平均值,得到各個演算法的平均替換率。

BEST RANDOM FIFO LRU CLOCK
0.099187 0.164114 0.147767 0.146462 0.298836
0.150565 0.249996 0.231385 0.228987 0.432876
0.200792 0.329786 0.313261 0.31067 0.524086

繪製圖表。

這裡寫圖片描述

可以看到,引用串越不穩定的取值,各個演算法的替換率越高,說明如果不集中使用某一些頁面,那麼這些演算法的效率會降低。

引用串移動率m變化對演算法替換率的影響

對資料檔案output1.csv``output10.csv``output11.csv分別求平均值,得到各個演算法的平均替換率。

BEST RANDOM FIFO LRU CLOCK
0.099187 0.164114 0.147767 0.146462 0.298836
0.020163 0.035813 0.031195 0.030738 0.062087
0.012554 0.022088 0.019648 0.019444 0.039265

繪製圖表。

這裡寫圖片描述

可以看到,漸進引用頁面的時候,移動率越大各個演算法的替換率越低。並且移動率越大各個演算法的替換率趨於相似。

引用串工作集大小z變化對演算法替換率的影響

對資料檔案output1.csv``output12.csv``output13.csv分別求平均值,得到各個演算法的平均替換率。

BEST RANDOM FIFO LRU CLOCK
0.099187 0.164114 0.147767 0.146462 0.298836
0.149553 0.257455 0.212765 0.209211 0.534551
0.194112 0.34594 0.271257 0.262488 0.644669

繪製圖表。

這裡寫圖片描述

可以看到,在工作集越來越大時,各個演算法的替換率增加了。

實驗總結

完成這次實驗之後,我對各個頁面置換演算法有了更深一步的瞭解。我發現FIFO演算法LRU演算法是比較理想的作業系統頁面置換演算法,而Clock演算法雖然執行效率高,但是替換率卻沒有任何優勢。(也有可能是我Clock演算法沒有使用改進的演算法的原因。

不解之處

  1. 為什麼Clock置換演算法的效率比其他演算法低那麼多,不是應該和LRU演算法的效率近似嗎?
  2. 參考引數應該設定到什麼樣才最能模擬正常使用的狀況呢?

參考

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "stddef.h"

#define MALLOC_ERROR -1
#define SUCCEED 0

#define BEST_RULE 1
#define RANDOM_RULE 2
#define FIFO_RULE 3
#define LRU_RULE 4
#define CLOCK_RULE 5

#define EMPTY_QUEUE_ERROR NULL

int pageNum;
int rsLen;
int frameNum;
int seed = 0;


int* pageArr;//頁面演算法中的標誌位暫存器或者佇列
int* rs;//引用串
int* frameArr;//實體記憶體幀

int bestModeCounter = 0;
int randomModeCounter = 0;
int lruModeCounter = 0;
int clockModeCounter =0;
int fifoModeCounter = 0;

typedef int RULE;

int init(int pn, int rsl, int fn){
    pageNum = pn;
    frameNum = fn;
    rsLen = rsl;

    //pageArr = (int*)malloc(sizeof(int)*pageNum);
    rs = (int*)malloc(sizeof(int)*rsLen);
    frameArr = (int*)malloc(sizeof(int)*frameNum);

    if(!( rs && frameArr)){ return MALLOC_ERROR; }

    int i = 0;
    //for(i = 0 ; i<pageNum ; i+=1){ pageArr[i] = -1;}
    for(i = 0 ; i<rsLen ; i+=1){ rs[i] = -1;}
    for(i = 0 ; i<frameNum ; i+=1){ frameArr[i] = -1;}

    return SUCCEED;
}

int recycle(){
    //free(pageArr);
    free(rs);
    free(frameArr);

    pageNum = 0;
    rsLen = 0;
    frameNum = 0;

    return SUCCEED;
}

int reInit(){
    int i;
    //for(i = 0 ; i<pageNum ; i+=1){ pageArr[i] = -1;}
    for(i = 0 ; i<frameNum ; i+=1){ frameArr[i] = -1;}
}

void enQueue(int* q, int ele){
    int i = 0;
    for(i = 0 ; i<frameNum ; i+=1){
        if(q[i]==-1){ break; }
    }
    q[i] = ele;
}

int deQueue(int* q){
    int ret = q[0];
    int i;
    for(i = 1;i<frameNum ; i+=1){
        q[i-1] = q[i];
    }
    q[frameNum-1] = -1;
    return ret;
}

int produceRs(int e, int m,double t){
    int p;//p:工作集的起始位置
    int i;
    srand(seed);
    seed+=1;
    p = rand()%pageNum;//產生0到(P-1)之間的隨機數
    //int e = 20;//工作集中包含的頁數
    //int m = 100;//工作集移動率
    //double t = 0.2;//劇烈移動在整個移動中的比率
    double r;
    int rp = 0;
    do
    {
        for(i = 0;i<m;i++)
        {
            int x = p+rand()%e;//生成p和p+e間的隨機數
            rs[rp] = x%pageNum;
            rp++;
        }
        r = rand()/(RAND_MAX+1.0);
        if((t-r)>0.0)
            p = rand()%pageNum;
        else
            p = (p+1)%pageNum;
    }while(rp < rsLen);

    return SUCCEED;
}

int bestMode()
    {
        int i,j,k;
        //int bestModeCounter = 0;

        for (i = 0 ; i<rsLen ; i+=1){
            //檢查有沒有在記憶體裡
            int ifInside = 0;
            for (j = 0 ; j<frameNum ;j+=1){
                if (rs[i]==frameArr[j]){
                    ifInside = 1;
                    break;
                }
            }

            if (ifInside==1){
                continue;
            }

            //沒有在記憶體裡面

            //先看看記憶體有空位嗎
            int ifFull = 1;
            for (j = 0; j <frameNum ; j+=1){
                if(frameArr[j]==-1){frameArr[j] = rs[i]; ifFull = 0; break;}//有的話就塞進去
            }

            if (ifFull==0){continue;}

            //沒有空位的話,就要考慮淘汰哪個頁面了

            int chosenFrame = choseToOut(i);
            frameArr[chosenFrame] = rs[i];
            bestModeCounter+=1;
            //showFrameArr(frameArr);
        }
        //System.out.println(bestModeCounter);

        return 0;
    }

    int choseToOut(int cur){
        int i,j;
        int max = -1;
        int maxIndex = -1;
        for (i = 0; i<frameNum ;i+=1){
            for (j = cur+1; j<rsLen ; j+=1){
                //System.out.println(rsLen);
                //System.out.println(j);
                if (rs[j]==frameArr[i]){ break; }
            }
            if (max<j){max = j; maxIndex = i;}
        }
        return maxIndex;
    }

int randomMode(){
    int i = 0;
    int j = 0;
    srand((int)time(NULL));
    for(i = 0; i<rsLen ; i+=1){
        int cur = rs[i];
        int ifLost = 1;
        for(j = 0; j <frameNum ; j+=1){
            if(cur==frameArr[j]){ ifLost = 0; break;}
        }
        //不缺頁
        if(!ifLost){
            continue;
        }
        else{//缺頁

            randomModeCounter+=1;

            int ifFinish = 0;

            for(j = 0 ; j<frameNum ; j+=1){//實體記憶體有空位
                if(frameArr[j]==-1){ frameArr[j] = cur; ifFinish = 1; break; }
            }

            if(ifFinish){
                continue;
            }

            //實體記憶體沒有空位
            int chosenFrame = rand()%frameNum;//確定要被替換的Frame
            frameArr[chosenFrame] = cur;//替換
        }
    }
    return SUCCEED;
}

int fifoMode(){
    int i = 0;
    int j = 0;

    int* q = (int*)malloc(sizeof(int)*frameNum);
    for(i = 0; i<frameNum ; i+=1){
        q[i] = -1;
    }

    for(i = 0; i<rsLen ; i+=1){
       // printf("\nboom1");
        int cur = rs[i];
        int ifLost = 1;
        for(j = 0; j <frameNum ; j+=1){
            if(cur==frameArr[j]){ ifLost = 0; break;}
        }
        //不缺頁
        if(!ifLost){
            continue;
        }
        else{//缺頁

            fifoModeCounter+=1;

            int ifFinish = 0;

            for(j = 0 ; j<frameNum ; j+=1){//實體記憶體有空位
                if(frameArr[j]==-1){ frameArr[j] = cur; ifFinish = 1; break; }
            }

            if(ifFinish){
                enQueue(q,j);
                continue;
            }

            //實體記憶體沒有空位
            //printf("\nboom2");
            int chosenFrame = deQueue(q);//確定要被替換的Frame
            frameArr[chosenFrame] = cur;//替換
            enQueue(q,chosenFrame);
        }
    }
    return SUCCEED;
}

int lruMode(){
    int i = 0;
    int j = 0;
    int* counter = (int*)malloc(sizeof(int)*frameNum);
    for(i = 0 ; i<frameNum ; i+=1){
        counter[i] = 0;
    }

    for(i = 0; i<rsLen ; i+=1){

        for(j = 0; j<frameNum ; j+=1){
            counter[j]+=1;
        }

        int cur = rs[i];
        int ifLost = 1;
        for(j = 0; j <frameNum ; j+=1){
            if(cur==frameArr[j]){ ifLost = 0; break;}
        }
        //不缺頁
        if(!ifLost){
            counter[j]=0;
            continue;
        }
        else{//缺頁

            lruModeCounter+=1;

            int ifFinish = 0;

            for(j = 0 ; j<frameNum ; j+=1){//實體記憶體有空位
                if(frameArr[j]==-1){ frameArr[j] = cur; ifFinish = 1; break; }
            }

            if(ifFinish){
                counter[j] = 0;
                continue;
            }

            //實體記憶體沒有空位
            int chosenFrame = 0;
            int max = counter[chosenFrame];

            //確定要被替換的Frame
            for(j = 1 ; j<frameNum ; j+=1){
                if(counter[j]>max){ chosenFrame = j; max = counter[j]; }
            }
            frameArr[chosenFrame] = cur;//替換
            counter[chosenFrame] = 0;
        }
    }
    return SUCCEED;
}

int clockMode(){
    int i = 0;
    int j = 0;
    int* flag = (int*)malloc(sizeof(int)*frameNum);
    int flagCur = 0;
    for(i = 0 ; i<frameNum ; i+=1){
        flag[i] = 0;
    }

    for(i = 0 ; i<rsLen ; i+=1){
        int cur = rs[i];
        int ifInside = 0;

        //先判斷是不是在裡面
        for(j = 0 ; j<frameNum ; j+=1){
            if(frameArr[j]==cur){ ifInside = 1; break; }
        }

        if(ifInside){
            flag[j] = 1;
            continue;
        }

        //如果不在裡面
        clockModeCounter+=1;
        while(1){
            if(flag[flagCur]==0){ break; }
            else{flag[flagCur]=0; flagCur+=1; flagCur%=frameNum;}
        }
        frameArr[flagCur] = cur;
    }
    return SUCCEED;
}

int test(){
    init(100,10000,20);
    produceRs(15,10,0.2);

    //int temp[] = {7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};
    //rs = temp;
    //printf("rslen:%d",rsLen);

    int i =0;
    //for(i = 0; i<rsLen ; i+=1){
        //printf("%d  ",rs[i]);
    //}

    //printf("\n\nStart print..");




    reInit();
    randomMode();
    //printf("\nrandomMode:%d",randomModeCounter);


    reInit();
    lruMode();
    //printf("\nLRUMode:%d",lruModeCounter);


    reInit();
    fifoMode();
    //printf("\nfifoMode:%d",fifoModeCounter);


    reInit();
    clockMode();
    //printf("\nclockMode:%d",clockModeCounter);

    reInit();
    bestMode();
    //printf("\nbestMode:%d",bestModeCounter);
    writeToFile();
    recycle();

    return 0;
}

void writeToFile(){
    FILE *file;
    file = fopen("output13.csv","a");
    //float t1,t2,t3,t4,t5;
    //t1 = (float)bestModeCounter/(float)rsLen;

    fprintf(file,"%f,%f,%f,%f,%f\n",((float)bestModeCounter/(float)rsLen),((float)randomModeCounter/(float)rsLen),((float)fifoModeCounter/(float)rsLen),((float)lruModeCounter/(float)rsLen),((float)clockModeCounter/(float)rsLen));
    //fprintf(file,"%d,%d,%d,%d,%d\n",bestModeCounter,randomModeCounter,fifoModeCounter,lruModeCounter,clockModeCounter);
    fclose(file);
}

void initCounter(){
    bestModeCounter = 0;
    lruModeCounter = 0;
    fifoModeCounter = 0;
    clockModeCounter = 0;
    randomModeCounter = 0;
}

int main(){
    printf("Start...");
    FILE *file;
    file = fopen("output13.csv","w");
    fclose(file);
    int i =0;
    int j = 0;

    for(i = 0; i<100 ;i+=1){
            initCounter();
            test();
    }
    printf("End...");
    return 0;
}