Last active
April 4, 2022 19:01
-
-
Save m13253/a7017af3392f7021d8044fd11c6a16bf to your computer and use it in GitHub Desktop.
Simple CPU L1 cache simulator to assist your operating system coursework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This library is licensed under WTFPL version 2. | |
* | |
* May contain undiscovered bugs. | |
* I am willing to fix bugs but will not be responsible for them. | |
* | |
* I suggest you cross-check with another library, for example: | |
* https://github.com/RRZE-HPC/pycachesim | |
*/ | |
#ifndef INCLUDE_GUARD_5F0CB9F1_1E2D_40FA_BA4E_5F8D398CB82E | |
#define INCLUDE_GUARD_5F0CB9F1_1E2D_40FA_BA4E_5F8D398CB82E | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct cache_sim_t | |
{ | |
size_t *cache; | |
size_t num_lines; | |
size_t num_ways; | |
size_t block_size; | |
size_t miss_count; | |
size_t access_count; | |
} cache_sim_t; | |
static inline cache_sim_t cache_new(size_t num_lines, size_t num_ways, size_t block_size) | |
{ | |
if (num_lines == 0 || num_ways == 0 || block_size == 0) | |
{ | |
printf("Invalid cache parameters.\n"); | |
exit(1); | |
} | |
size_t cache_size; | |
if (__builtin_mul_overflow(num_lines, num_ways, &cache_size) || __builtin_mul_overflow(cache_size, block_size, &cache_size)) | |
{ | |
printf("Cache size overflow\n"); | |
exit(1); | |
} | |
cache_sim_t cache; | |
cache.cache = (size_t *) calloc(cache_size, sizeof *cache.cache); | |
if (!cache.cache) | |
{ | |
printf("Cache allocation failed\n"); | |
exit(1); | |
} | |
cache.num_lines = num_lines; | |
cache.num_ways = num_ways; | |
cache.block_size = block_size; | |
cache.miss_count = 0; | |
cache.access_count = 0; | |
return cache; | |
} | |
static inline void cache_reset(cache_sim_t *cache) | |
{ | |
size_t cache_size_bytes; | |
if (__builtin_mul_overflow(cache->num_lines * cache->num_ways * cache->block_size, (size_t) sizeof *cache->cache, &cache_size_bytes)) | |
{ | |
printf("Cache size overflow\n"); | |
exit(1); | |
} | |
memset(cache->cache, 0, cache_size_bytes); | |
cache->miss_count = 0; | |
cache->access_count = 0; | |
} | |
static inline void cache_free(cache_sim_t *cache) | |
{ | |
free(cache->cache); | |
} | |
static inline void cache_access(cache_sim_t *cache, size_t address) | |
{ | |
size_t tag = address / cache->block_size; | |
size_t line = tag % cache->num_lines; | |
size_t num_ways = cache->num_ways; | |
if (tag == ~(size_t) 0) | |
{ | |
printf("Address overflow.\n"); | |
exit(1); | |
} | |
for (size_t way = 0; way < num_ways; way++) | |
{ | |
if (cache->cache[line * num_ways + way] == ~tag) | |
{ | |
if (__builtin_add_overflow(cache->access_count, (size_t) 1, &cache->access_count)) | |
{ | |
printf("Access count overflow.\n"); | |
exit(1); | |
} | |
if (way != 0) | |
{ | |
// LRU rule, slower but easier to implement | |
memmove(&cache->cache[line * num_ways + 1], &cache->cache[line * num_ways], way * sizeof *cache->cache); | |
cache->cache[line * num_ways] = ~tag; | |
} | |
return; | |
} | |
} | |
if (__builtin_add_overflow(cache->access_count, (size_t) 1, &cache->access_count)) | |
{ | |
printf("Access count overflow.\n"); | |
exit(1); | |
} | |
if (__builtin_add_overflow(cache->miss_count, (size_t) 1, &cache->miss_count)) | |
{ | |
printf("Miss count overflow.\n"); | |
exit(1); | |
} | |
if (num_ways != 1) | |
{ | |
memmove(&cache->cache[line * num_ways + 1], &cache->cache[line * num_ways], (num_ways - 1) * sizeof *cache->cache); | |
} | |
cache->cache[line * num_ways] = ~tag; | |
} | |
static inline double cache_miss_rate(const cache_sim_t *cache) | |
{ | |
return (double) cache->miss_count / cache->access_count; | |
} | |
static inline void cache_print_stats(const cache_sim_t *cache, const char *name) | |
{ | |
if (name) | |
{ | |
printf("%s: miss=%zu access=%zu miss rate=%lf\n", name, cache->miss_count, cache->access_count, cache_miss_rate(cache)); | |
} | |
else | |
{ | |
printf("miss=%zu access=%zu miss rate=%lf\n", cache->miss_count, cache->access_count, cache_miss_rate(cache)); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment