Skip to content

Instantly share code, notes, and snippets.

@m13253
Last active April 4, 2022 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m13253/a7017af3392f7021d8044fd11c6a16bf to your computer and use it in GitHub Desktop.
Save m13253/a7017af3392f7021d8044fd11c6a16bf to your computer and use it in GitHub Desktop.
Simple CPU L1 cache simulator to assist your operating system coursework
/*
* 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