大佬教程收集整理的这篇文章主要介绍了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,请注明来意。