Cache调度算法-C 程序实现

一、实验目的及要求

1.掌握 FIFO 算法原理

2.掌握 LRU 算法的原理。

3.通过编写 C 程序,实现定 FIFO 和 LRU 算法。

实践知识:

C语言基础知识

二、实验环境

计算机:

开发工具:C-Free 5

三、实验内容

当新的一块数据需要装入 Cache 时,原来存储的一个 Cache 行必 须被替换掉。对于直接映射方式,某个特定的块只能有一个对应的行, 因此不需要对将被替换的 Cache  行进行选择。而对于全相联映射方 式,由于有多个 Cache 行都可作为候选替换行,如何在这些 Cache 中

进行选择,从而提高 Cache 的命中率就需要引入替换策略。

1、先进先出算法

在发生替换时,先进先出算法(FIFO)把最先调入的那一个 Cache 行替换出去。FIFO  算法用循环或环形缓冲很容易实现,但是一般来说,采用先进先出算法也不能得到很高的 Cache 命中率。

2、最近最少使用算法

最近最少使用算法(LRU)统计那一个 Cache 行是近段时间内使 用次数最少的 Cach 行,需要替换时就将它替换出去。实际情况证明, 最近最少使用算法是一个比较好的替换算法,采用该替换算法能够得到较高的 Cache 命中率。

#include <stdio.h>
#include <stdlib.h>// malloc() free()
#define num1 4
#define num2 8
typedef struct { // 物理块结构
    int number;
    int time;
} Block;
void FIFO(int arr[num2], int size) {//先进先出算法
    int* blocks = (int*)malloc(num1 * sizeof(int));// 物理块数组
    int blockCount = 0;// 物理块数量
    int currentIndex = 0;// 当前物理块索引

    for (int i = 0; i < size; i++) {// 遍历输入数组
        int found = 0;// 物理块是否找到
        for (int j = 0; j < blockCount; j++) {// 遍历物理块数组
            if (blocks[j] == arr[i]) {
                found = 1;
                printf("输入的%d物理块号存在,命中并覆盖原来的\n", blocks[j]);
                break;
            }
        }
        if (!found) {// 未找到物理块
            if (blockCount < num1) {
                blocks[blockCount] = arr[i];
                printf("cache块未满,直接添加物理块号%d\n", blockCount + 1);
                blockCount++;
            }
            else {// 物理块数量大于等于4,替换最早进入的块
                blocks[currentIndex] = arr[i];
                printf("cache块已满,替换物理块号%d\n", currentIndex + 1);
                currentIndex = (currentIndex + 1) % num1;// 循环移动
            }
        }
    }
    // 打印结果
    printf("FIFO替换结果:");
    for (int i = 0; i < num1; i++) {
        printf("%d", blocks[i]);// 物理块数组
    }
    printf("\n");
    free(blocks);// 释放内存
}
void LRU(int arr[num2],int size) {//近期最少使用算法
    Block* blocks = (Block*)malloc(num1 * sizeof(Block)); // 物理块数组
    int blockCount = 0;// 物理块数量

    for (int i = 0; i < size; i++) {
        int found = 0;
        for (int j = 0; j < blockCount; j++) {
            if (blocks[j].number == arr[i]) {  // 找到物理块
                found = 1;
                printf("输入的%d物理块号存在,命中并覆盖原来的\n", blocks[j]);
                blocks[j].time = 0;
            }
            else {
                blocks[j].time++;
            }
        }
        if (!found) {  // 未找到物理块
            if (blockCount < num1) {
                blocks[blockCount].number = arr[i];// 物理块数量小于4,直接添加
                printf("cache块未满,直接添加物理块号%d\n", blockCount + 1);
                blocks[blockCount].time = 1;// 时间置1
                blockCount++;
            }
            else {    // 物理块数量大于等于4,替换最久未使用块
                int maxTime = 0;
                int replaceIndex = 0;
                for (int k = 0; k < num1; k++) {
                    if (blocks[k].time > maxTime) {
                        maxTime = blocks[k].time;
                        replaceIndex = k;
                    }
                }
                blocks[replaceIndex].number = arr[i];// 物理块数量大于等于4,替换最久未使用块
                printf("cache块已满,替换物理块号%d\n", replaceIndex + 1);
                blocks[replaceIndex].time = 1;//时间置1
            }
        }
    }
    // 打印结果
    printf("LRU替换结果:");
    for (int i = 0; i < num1; i++) {
        printf("%d",  blocks[i].number);
    }
        printf("\n");
    free(blocks);
}
void LFU(int arr1[num2], int size) {//最不经常使用算法
    int* blocks = (int*)malloc(num1 * sizeof(int));// 物理块数组
    int blockCount = 0;// 物理块数量  
    int* count = (int*)malloc(num1 * sizeof(int));// 物理块使用次数数组
    int currentIndex = 0;// 当前物理块索引
    for (int i = 0; i < size; i++) {// 遍历输入数组
        int found = 0;
        for (int j = 0; j < blockCount; j++) {// 遍历物理块数组
            if (blocks[j] == arr1[i]) {
                found = 1;
                printf("输入的%d物理块号存在,命中并覆盖原来的\n", blocks[j]);
                count[j]++;
                break;
            }
        }
        if (!found) {// 未找到物理块
            if (blockCount < num1) {
                blocks[blockCount] = arr1[i];
                printf("cache块未满,直接添加物理块号%d\n", blockCount + 1);
                count[blockCount] = 1;
                blockCount++;
            }
            else {// 物理块数量大于等于4,替换最少使用次数的块
                int minCount = 10;
                int replaceIndex = 0;
                for (int k = 0; k < num1; k++) {// 遍历物理块数组//替换规则修改FIFO递归  
                    if (count[k] < minCount) {
                        minCount = count[k];
                        replaceIndex = k;
                    }
                }
                blocks[replaceIndex] = arr1[i];
                printf("cache块已满,替换物理块号%d\n", replaceIndex + 1);
                count[replaceIndex] = 1;
            }
        }
    }
    // 打印结果
    printf("LFU替换结果:");
    for (int i = 0; i < num1; i++) {
        printf("%d",  blocks[i]);
    }
        printf("\n");
    free(blocks);
    free(count);
} 
int main() {
    int arr[num2];
    int i = 0;
    printf("请输入8个物理块号\n");
    for (i = 0; i < 8; i++)
        scanf("%d", &arr[i]);
    FIFO(arr, 8);
    LRU(arr, 8);
    LFU(arr, 8);
    return 0;
}

实验结果分析:

Cache调度算法中:

  1. FIFO算法先进去的cache行总是先被替换且cache的命中率不高。
  2. LRU算法总是将近期最久未被访问的cache行给替换出去且cache的命中率高。

3.LFU算法总是将访问次数最少的cache行替换,但是不能严格反应近期访问情况。

心得体会:

1.模块化设计:我将整个程序划分为多个模块,每个模块负责不同的功能,比如模拟3种替换算法和cache输出来提高代码的可读性和可维护性

2.优化性能:在代码实现过程中,我注意各个替换算法函数内部到一些可以优化的地方,比如减少不必要的内存访问、减少循环次数,以提高程序的性能

3.更加熟悉算法原理:将算法转化为代码实现,对Cache调度算法的原理和思想有了更加刻的了解,提高了自己的编程经验和独立解决问题的能力。

改进意见:1.可以通过改变增大cache块的物理块数和输入的物理块号数量进行扩展实验。

2.可以将此次cache的调度算法与其地址映射的三种方式(全相联映射,直接相联映射,组相联映射)结合起来进行实验的扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值