'Cache Simulator in C - Why am I getting a 'hit' every time?
I am writing a simple cache simulation in c. I'm somewhat of a noob when it comes to c but I have the program almost entirely working I think. For some reason it indicates a hit for every value even when the cache is empty.
I think the problem lies within the queryCache function but I'm not sure what's wrong. The full code is below as well as an example output.
#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",m,s,e,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;
}
Output Example
./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.
where
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)
Solution 1:[1]
I found several issues with the program today when looking at it with fresh eyes. The changes that fixed the issues are as follows:
-The return statements were prematurely exiting the loop that scans through the cache.
-The format specifiers for the addresses needed to be %llX
to handle a 64 bit hex value
-The section that separates the tags and the set IDs needed to be changed as follows
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
The program now produces the output:
./cachesim -m 64 -s 4 -e 0 -b 4 -i addresses.txt -r lfu
addr size 64, sets: 16, lines: 1, block size: 16
Initializing Cache...
Mem for sets allocated.
Cache initialization complete.
123456789ABCDEF
Tag: 1234567 Set: B Miss, no evict
23F0FFFA003464F
Tag: 23F0FFF Set: 3 Miss, no evict
DC2387002FAFF
Tag: DC238 Set: 2 Miss, no evict
10F0F00FAC4A34F
Tag: 10F0F00 Set: 4 Miss, no evict
DC2387002FAFF
Tag: DC238 Set: 2 hit
602598F3AF2C12F
Tag: 602598F Set: 2 Miss, evict
81F2319543FC32C
Tag: 81F2319 Set: F Miss, no evict
10F0F00FAC4A34F
Tag: 10F0F00 Set: 4 hit
40F0F00FAC4A34F
Tag: 40F0F00 Set: 4 Miss, evict
602598F3AF2C12F
Tag: 602598F Set: 2 hit
DC2387002FAFF
Tag: DC238 Set: 2 Miss, evict
123456789ABCDEF
Tag: 1234567 Set: B hit
23F0FFFA003464F
Tag: 23F0FFF Set: 3 hit
40F0F00FAC4A34F
Tag: 40F0F00 Set: 4 hit
602598F3AF2C12F
Tag: 602598F Set: 2 Miss, evict
81F2319543FC32C
Tag: 81F2319 Set: F hit
10F0F00FAC4A34F
Tag: 10F0F00 Set: 4 Miss, evict
10F0F00FAC4A34F
Tag: 10F0F00 Set: 4 hit
40F0F00FAC4A34F
Tag: 40F0F00 Set: 4 Miss, evict
602598F3AF2C12F
Tag: 602598F Set: 2 hit
81F2319543FC32C
Tag: 81F2319 Set: F hit
10F0F00FAC4A34F
Tag: 10F0F00 Set: 4 Miss, evict
40F0F00FAC4A34F
Tag: 40F0F00 Set: 4 Miss, evict
602598F3AF2C12F
Tag: 602598F Set: 2 hit
Hits: 11, Misses: 13, Evictions: 8
Total transfers: 24
Miss Rate: 54.17
Avg access time: 55 clk cycles
Total run time: 1320 clk cycles
Deallocating mem...
Mem deallocation completed.
I will add a github link to the full code for reference when I get the chance
(If you are coming here for help on a similar program and there is no link still feel free to comment or pm. I likely forgot to add it as I am going to make some final changes before I commit)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nathan Loucks |