程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了C 中的缓存模拟器 - 为什么我每次都会“命中”?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决C 中的缓存模拟器 - 为什么我每次都会“命中”??

开发过程中遇到C 中的缓存模拟器 - 为什么我每次都会“命中”?的问题如何解决?下面主要结合日常开发的经验,给出你关于C 中的缓存模拟器 - 为什么我每次都会“命中”?的解决方法建议,希望对你解决C 中的缓存模拟器 - 为什么我每次都会“命中”?有所启发或帮助;

我正在用 c 编写一个简单的缓存模拟。当谈到 c 时,我有点菜鸟,但我认为该程序几乎完全可以运行。出于某种原因,即使缓存为空,它也表示每个值都被命中。

我认为问题出在 queryCache 函数中,但我不确定出了什么问题。完整代码以及示例输出如下。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <math.h>
#include <getopt.h>
#include <ctype.h>

typedef struct line{
    const int b_size; //block size in bits
    unsigned long long block,tag;
    short v; //valID flag bit
    int l_rate; //use rate
}line;

typedef struct Set{
    line *lines;
    int s_rate;
}Set;

typedef struct Cache{
    Set *sets;
    int hit_c,miss_c,evic_c;
    int set_b,block_b,line_per_set;
}Cache;

//initialize cache with user input 
voID cacheInit(Cache *cache){
    printf("Initializing Cache...\n");
    //init counters
    cache->hit_c = 0;
    cache->miss_c = 0;
    cache->evic_c = 0;

    unsigned long long n_sets = pow(2,cache->set_b); // number of sets in cache = 2^s
    cache->sets = (Set *)malloc(sizeof(Set)*n_sets); //allocate mem for sets
    printf("Mem for sets allocated.\n");

    //Allocate mem for cache lines within each set.
    for(unsigned long long i=0;i<n_sets;i++){
        cache->sets[i].s_rate = 0;
        cache->sets[i].lines = (line *)malloc(sizeof(line)*cache->line_per_set);
        //printf("Mem allocated for lines within set: %llu\n",i);
        for(unsigned long long k=0;k<cache->line_per_set;k++){
            cache->sets[i].lines[k].v = 0;
        }
    }
    printf("Cache initialization complete.\n");
}

//DEALLOCATION OF MEM
voID dealloc(Cache *cache){
    printf("Deallocating mem...\n");
    unsigned long long n_sets = pow(2,cache->set_b); // number of sets in cache = 2^s
    for(unsigned long long i=0;i<n_sets;i++){
        free(cache->sets[i].lines); //free lines within set
        //printf("lines in set: %llu deallocated.\n",i);
    }
    free(cache->sets); //free sets after the lines
    printf("Mem deallocation completed.\n");
}

//query cache for an address (found in cache = 1,not found but has free space = -1,not found and no free space = 0)
int queryCache(const unsigned long long address,const Cache *cache){
    signed int result = 0;
    unsigned long long index = 0;
    unsigned long long tag_b = 64 - (cache->set_b + cache->block_b);
    unsigned long long tag = address >> (cache->set_b + cache->block_b); //extract tag
    unsigned long long set = (address << tag_b) >> (tag_b + cache->set_b);

    //search through cache
    for(unsigned long long i = 0; i < cache->line_per_set; i++){
        if(cache->sets[set].lines[i].v && cache->sets[set].lines[i].tag == tag){ //already in cache 'hit'
            cache->sets[set].lines[i].l_rate = ++cache->sets[set].s_rate;
            //printf("result = 1\n");
            return 1;
        }else if(!cache->sets[set].lines[i].v){ //valID flag unset,so free space is available
            index = i;
            cache->sets[set].lines[index].tag = tag;
            cache->sets[set].lines[index].v = 1;
            cache->sets[set].lines[index].l_rate = ++cache->sets[set].s_rate;
            return -1;
            //printf("result = -1\n");
        }else{
            //printf("result = 0\n");
            return 0;  // no empty spot,not found in cache 'miss'
        }
    }
    //return result;
}

//evict SPOT
voID evictData(const unsigned long long address,Cache *cache){
    unsigned long long index = 0;
    unsigned long long tag_b = 64 - (cache->set_b + cache->block_b);
    unsigned long long tag = address >> (cache->set_b + cache->block_b);
    unsigned long long set = (address << tag_b) >> (tag_b + cache->set_b);

    unsigned long long min_r;
    min_r = cache->sets[set].lines[0].l_rate;

    for(unsigned long long i = 0; i < cache->line_per_set; i++){
        unsigned long long this_r;
        if(min_r > this_r){
            min_r = this_r;
            index = i;
        }
    }
    cache->sets[set].lines[index].tag = tag;
    cache->sets[set].lines[index].l_rate = ++cache->sets[set].s_rate;
}

//CHECK DATA AND REPLACE IF NECESSARY
voID cacheData(const unsigned long long address,Cache *cache){
    //query cache for address

    //printf("queryResult = %i\n",queryResult);
    
    if(!queryCache(address,cache)){ //not found,cache full
        printf(" Miss,evict\n");
        evictData(address,cache);
        cache->miss_c++;
        cache->evic_c++;

    }else if(queryCache(address,cache)){// found 'hit'
        cache->hit_c++;
        printf(" hit\n");

    }else{//not found,free space
        cache->miss_c++;
        printf(" Miss,no evict\n");
    }

}

//SIMulATE CACHE WITH input List OF ADDRESSES
voID simulateCache(char *filename,Cache *cache){
    file *input = fopen(filename,"rt");
    unsigned long long address;

    while(fscanf(input,"%llu",&address) == 1){
        printf("%llu",address);
        cacheData(address,cache);
    }
    fclose(input);
}

int main(int argc,char *argv[]){
    int opt,m,s,e,b;
    char *i;
    char *r;

    Cache cache0;

    int n_hits,n_miss;

    //ensure correct num of arguments before parsing
    if(!(argc == 13)){
        printf("Error: InvalID number of arguments. Arg count: %d\n",argc);
        exit(-1);
    }

    while(-1 != (opt = getopt(argc,argv,"m:s:e:b:i:r"))){
        switch(opt){
            case 'm':
                m = atoi(optarg);
                break;
            case 's':
                s = atoi(optarg);
                cache0.set_b = s;
                break;
            case 'e':
                e = atoi(optarg);
                cache0.line_per_set = e;
                break;
            case 'b':
                b = atoi(optarg);
                cache0.block_b = b;
                break;
            case 'i':
                i = optarg;
                break;
            case 'r':
                r = optarg;
                break;
            default:
                printf("InvalID argument\n");
                break;
        }
    }
    printf("addr size %d,index bits: %d,line bits: %d,block size: %d\n",b);
    //printf("filename: %c,Mode: %c\n",i,r);

    cacheInit(&cache0);

    simulateCache(i,&cache0);
    unsigned long long r_miss = cache0.miss_c/(cache0.miss_c+cache0.hit_c); //calculate miss rate
    unsigned long long avg_access_t = 1 + (r_miss * 100); //calulate avg access time in cycles
    unsigned long long total_run_t = (cache0.miss_c+cache0.hit_c)*avg_access_t;
    printf("Avg access time: %0.2d\n",avg_access_t);
    printf("Total run time: %0.2d\n",total_run_t);


    printf("Hits: %d,Misses: %d\n",cache0.hit_c,cache0.miss_c);

    dealloc(&cache0);

    return 0;
}

输出示例

./cachesim -m 64 -s 4 -e 1 -b 4 -i adresses.txt -r lfu
addr size 64,index bits: 4,line bits: 1,block size: 4
Initializing Cache...
Mem for sets allocated.
Cache initialization complete.
10 hit
20 hit
10 hit
22 hit
Avg access time: 01
Total run time: 04
Hits: 4,Misses: 0
Deallocating mem...
Mem deallocation completed.

哪里

m           address size in bits
s           number if index bits
e           number of line bits 
b           size of block bits
file        name of file containing a List of addresses
option      method used (lfu,fifo,opt)

解决方法

我今天在重新审视该程序时发现了几个问题。解决问题的更改如下: - 返回语句过早退出了扫描缓存的循环。 -地址的格式说明符需要为 #include <iostream> #include <list> #include <algorithm> struct Data { std::string code; std::string text; std::string head; }; int main() { struct Data data1{"0010","it is text1","head3"}; struct Data data2{"0025","it is text2","head1"}; struct Data data3{"0065","it is text3","head2"}; struct Data data4{"0011","it is text4","head2"}; std::list<struct Data> data = {data1,data2,data3,data4}; std::list<std::string> rule = {"head1","head2","head3","head4"}; data.sort([&rule](const Data& first,const Data& second) { auto index_a = std::distance(rule.begin(),std::find(rule.begin(),rule.end(),first.head)); auto index_b = std::distance(rule.begin(),second.head)); return index_a < index_b; }); for (auto &it : data) std::cout << it.code << "\t" << it.text << "\t" << it.head << "\n"; return 0; } 才能处理 64 位十六进制值 - 分隔标签和设置ID的部分需要更改如下

%llX

程序现在产生输出:

unsigned long long tag_b = 64 - ((cache->s) + (cache->block_b));
unsigned long long tag = address >> (cache->set_b + cache->block_b); //extract tag
unsigned long long set = (address << (tag_b)) >> (tag_b + cache->set_b);//extract set idx

有机会我会添加完整代码的github链接以供参考

(如果你来这里寻求类似程序的帮助,但仍然没有链接,请随时发表评论或 pm。我可能忘了添加它,因为我将在提交之前进行一些最终更改)

大佬总结

以上是大佬教程为你收集整理的C 中的缓存模拟器 - 为什么我每次都会“命中”?全部内容,希望文章能够帮你解决C 中的缓存模拟器 - 为什么我每次都会“命中”?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: