Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions doc/advanced_lib_extend.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ Specifically, you can following the steps:
2. If your cache eviction algorithm needs extra metadata, add a new object metadata struct in
[include/libCacheSim/cacheObj.h](/libCacheSim/include/libCacheSim/cacheObj.h).
3. Add `myCache_init()` function to [include/libCacheSim/evictionAlgo.h](/libCacheSim/include/libCacheSim/evictionAlgo.h).
4. Add mycache.c to [CMakeLists.txt](/libCacheSim/cache/eviction/CMakeLists.txt) so that it can be compiled.
5. Add command line option in [bin/cachesim/cache_init.h](/libCacheSim/bin/cachesim/cache_init.h) so that you can use `cachesim` binary. You may also want to take a look at [bin/cachesim/cli_parser.c](/libCacheSim/bin/cachesim/cli_parser.c).
4. Add `mycache.c` to [cache/CMakeLists.txt](/libCacheSim/cache/CMakeLists.txt) so that it can be compiled.
5. Add the algorithm name and init function to [cache/evictionAlgoRegister.c](/libCacheSim/cache/evictionAlgoRegister.c). This registry is used by built-in cache lookup paths such as `cachesim` and `mrcProfiler` MINISIM.
6. Remember to add a test in [test/test_evictionAlgo.c](/test/test_evictionAlgo.c) and add the algorithm to this [README](README.md).

> [!TIP]
Expand Down Expand Up @@ -84,4 +84,3 @@ Here are the steps to add a new trace reader:
3. add `myReader_setup()` to `setup_reader()`and `myReader_read_one_req()` to `read_one_req()` in [traceReader/reader.c](/libCacheSim/traceReader/reader.c).
4. add `MYREADER_TRACE` to `trace_type_str_to_enum()` in [bin/cli_reader_utils.c](/libCacheSim/bin/cli_reader_utils.c)


3 changes: 2 additions & 1 deletion doc/quickstart_mrcProfiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ mrcProfiler supports both `WSS-based` and `fixed-size` MRC generation for specif
### Profiling Non-LRU Algorithms with MINISIM

**Miniature Simulation** uses spatial sampling to downsample the workload and estimates miss ratios via scaled-down replay. It supports **non-LRU** algorithms.
For built-in eviction algorithms, MINISIM uses the same algorithm registry as `cachesim`, so names are case-insensitive, e.g., `--algo=FIFO` and `--algo=fifo` are equivalent.
In the example below, `FIX_RATE,0.01,10` sets a `1%` sampling rate and `10` threads. Note: Sampling rates above 0.5 disable sampling (full trace replay).

```bash
Expand Down Expand Up @@ -168,4 +169,4 @@ resluts:

- [x] Integrate plotting scripts.

- [ ] Implement additional profilers (e.g., FLOWS, TTLs Matter, Kosmo, AET).
- [ ] Implement additional profilers (e.g., FLOWS, TTLs Matter, Kosmo, AET).
80 changes: 7 additions & 73 deletions libCacheSim/bin/cachesim/cache_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,78 +30,8 @@ static inline cache_t *create_cache(const char *trace_path,
/* the trace provided is small */
if (trace_path != NULL && strstr(trace_path, "data/trace.") != NULL)
cc_params.hashpower -= 8;
typedef struct {
const char *name;
cache_t *(*init_func)(common_cache_params_t, const char *);
} eviction_algo_entry_t;
static const eviction_algo_entry_t simple_algos[] = {
{"2q", TwoQ_init},
{"arc", ARC_init},
{"arcv0", ARCv0_init},
{"CAR", CAR_init},
{"cacheus", Cacheus_init},
{"clock", Clock_init},
{"clock2qplus", Clock2QPlus_init},
{"clockpro", ClockPro_init},
{"fifo", FIFO_init},
{"fifo-merge", FIFO_Merge_init},
{"fifo-reinsertion", Clock_init},
{"fifomerge", FIFO_Merge_init},
{"flashProb", flashProb_init},
{"gdsf", GDSF_init},
{"lhd", LHD_init},
{"lecar", LeCaR_init},
{"lecarv0", LeCaRv0_init},
{"lfu", LFU_init},
{"lfucpp", LFUCpp_init},
{"lfuda", LFUDA_init},
{"lirs", LIRS_init},
{"lru", LRU_init},
{"lru-k", LRU_K_init},
{"lru-prob", LRU_Prob_init},
{"nop", nop_init},
// plugin cache that allows user to implement custom cache
{"pluginCache", pluginCache_init},
{"qdlp", QDLP_init},
{"random", Random_init},
{"RandomLRU", RandomLRU_init},
{"randomTwo", RandomTwo_init},
{"s3-fifo", S3FIFO_init},
{"s3-fifov0", S3FIFOv0_init},
{"s3fifo", S3FIFO_init},
{"s3fifod", S3FIFOd_init},
{"s3fifov0", S3FIFOv0_init},
{"sieve", Sieve_init},
{"size", Size_init},
{"slru", SLRU_init},
{"slruv0", SLRUv0_init},
{"twoq", TwoQ_init},
{"wtinyLFU", WTinyLFU_init},
#ifdef ENABLE_3L_CACHE
{"3LCache", ThreeLCache_init},
#endif
#ifdef ENABLE_GLCACHE
{"GLCache", GLCache_init},
{"gl-cache", GLCache_init},
#endif
#ifdef ENABLE_LRB
{"lrb", LRB_init},
#endif
};

cache_t *(*init_func)(common_cache_params_t, const char *) = NULL;
for (size_t i = 0; i < sizeof(simple_algos) / sizeof(simple_algos[0]); ++i) {
if (strcasecmp(eviction_algo, simple_algos[i].name) == 0) {
init_func = simple_algos[i].init_func;
break;
}
}

// Initializing for algorithms which require special handling (not in
// simple_algos)
if (init_func) {
cache = init_func(cc_params, eviction_params);
} else if (strcasecmp(eviction_algo, "hyperbolic") == 0) {
if (strcasecmp(eviction_algo, "hyperbolic") == 0) {
cc_params.hashpower = MAX(cc_params.hashpower - 8, 16);
cache = Hyperbolic_init(cc_params, eviction_params);
} else if (strcasecmp(eviction_algo, "tinyLFU") == 0) {
Expand Down Expand Up @@ -149,8 +79,12 @@ static inline cache_t *create_cache(const char *trace_path,
cc_params.hashpower = MAX(cc_params.hashpower - 8, 16);
cache = BeladySize_init(cc_params, eviction_params);
} else {
ERROR("do not support algorithm %s\n", eviction_algo);
abort();
cache_init_func_ptr init_func = get_builtin_cache_init(eviction_algo);
if (init_func == NULL) {
ERROR("do not support algorithm %s\n", eviction_algo);
abort();
}
cache = init_func(cc_params, eviction_params);
}

return cache;
Expand Down
1 change: 1 addition & 0 deletions libCacheSim/cache/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ set(cache_sources_c
${eviction_sources_c}
${prefetch_sources_c}
cache.c
evictionAlgoRegister.c
plugin.c
)

Expand Down
94 changes: 94 additions & 0 deletions libCacheSim/cache/evictionAlgoRegister.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <strings.h>

#include "libCacheSim/evictionAlgo.h"

// Registry for built-in eviction algorithm init functions.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
const char *name;
cache_init_func_ptr init_func;
} eviction_algo_entry_t;

cache_init_func_ptr get_builtin_cache_init(const char *const cache_alg_name) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Add a defensive check to ensure cache_alg_name is not NULL before calling strcasecmp. If cache_alg_name is NULL, strcasecmp will dereference a null pointer and cause a segmentation fault.

cache_init_func_ptr get_builtin_cache_init(const char *const cache_alg_name) {
  if (cache_alg_name == NULL) {
    return NULL;
  }

static const eviction_algo_entry_t builtin_caches[] = {
{"2q", TwoQ_init},
{"arc", ARC_init},
{"arcv0", ARCv0_init},
{"belady", Belady_init},
{"beladySize", BeladySize_init},
{"CAR", CAR_init},
{"cacheus", Cacheus_init},
{"clock", Clock_init},
{"clock2qplus", Clock2QPlus_init},
{"clockpro", ClockPro_init},
{"cr-lfu", CR_LFU_init},
{"cr_lfu", CR_LFU_init},
{"fifo", FIFO_init},
{"fifo-merge", FIFO_Merge_init},
{"fifo-reinsertion", Clock_init},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Map fifo-reinsertion to the correct initializer

Line 32 maps "fifo-reinsertion" to Clock_init, which will initialize the wrong policy for that algorithm name. This should point to FIFO_Reinsertion_init.

Suggested fix
-      {"fifo-reinsertion", Clock_init},
+      {"fifo-reinsertion", FIFO_Reinsertion_init},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{"fifo-reinsertion", Clock_init},
{"fifo-reinsertion", FIFO_Reinsertion_init},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libCacheSim/cache/evictionAlgoRegister.c` at line 32, The mapping for the
algorithm name "fifo-reinsertion" incorrectly points to Clock_init; change the
initializer to FIFO_Reinsertion_init in the registration table so the string
"fifo-reinsertion" is associated with the correct initializer function (ensure
FIFO_Reinsertion_init is declared/visible where the table is defined).

{"fifomerge", FIFO_Merge_init},
{"flashProb", flashProb_init},
{"gdsf", GDSF_init},
{"hyperbolic", Hyperbolic_init},
{"lhd", LHD_init},
{"lecar", LeCaR_init},
{"lecarv0", LeCaRv0_init},
{"lfu", LFU_init},
{"lfucpp", LFUCpp_init},
{"lfuda", LFUDA_init},
{"lirs", LIRS_init},
{"lru", LRU_init},
{"lru-k", LRU_K_init},
{"lru-prob", LRU_Prob_init},
{"lru_prob", LRU_Prob_init},
{"lruv0", LRUv0_init},
{"mru", MRU_init},
{"nop", nop_init},
{"pluginCache", pluginCache_init},
{"qdlp", QDLP_init},
{"random", Random_init},
{"RandomLRU", RandomLRU_init},
{"randomTwo", RandomTwo_init},
{"s3-fifo", S3FIFO_init},
{"s3fifo", S3FIFO_init},
{"s3fifod", S3FIFOd_init},
{"s3-fifov0", S3FIFOv0_init},
{"s3fifov0", S3FIFOv0_init},
{"s3lru", S3LRU_init},
{"sieve", Sieve_init},
{"size", Size_init},
{"slru", SLRU_init},
{"slruv0", SLRUv0_init},
{"sr-lru", SR_LRU_init},
{"sr_lru", SR_LRU_init},
{"twoq", TwoQ_init},
{"wtinyLFU", WTinyLFU_init},
Comment on lines +68 to +69

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add "tinyLFU" as an alias for WTinyLFU_init in the registry. Currently, only "wtinyLFU" is registered, but "tinyLFU" is a very common name used by users (e.g., in cachesim command line and potentially in mrcProfiler). Registering it as an alias ensures it can be resolved correctly through the unified registry.

Suggested change
{"twoq", TwoQ_init},
{"wtinyLFU", WTinyLFU_init},
{"twoq", TwoQ_init},
{"tinyLFU", WTinyLFU_init},
{"wtinyLFU", WTinyLFU_init},

#ifdef ENABLE_3L_CACHE
{"3LCache", ThreeLCache_init},
#endif
#ifdef ENABLE_GLCACHE
{"GLCache", GLCache_init},
{"gl-cache", GLCache_init},
#endif
#ifdef ENABLE_LRB
{"lrb", LRB_init},
#endif
};

for (size_t i = 0; i < sizeof(builtin_caches) / sizeof(builtin_caches[0]);
i++) {
if (strcasecmp(cache_alg_name, builtin_caches[i].name) == 0) {
return builtin_caches[i].init_func;
}
}

return NULL;
}

#ifdef __cplusplus
}
#endif
16 changes: 11 additions & 5 deletions libCacheSim/cache/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,16 @@ cache_t *create_cache_external(const char *const cache_alg_name,
cache_t *create_cache_internal(const char *const cache_alg_name,
common_cache_params_t cc_params,
void *cache_specific_params) {
cache_t *(*cache_init)(common_cache_params_t, void *) = NULL;
cache_init_func_ptr cache_init = get_builtin_cache_init(cache_alg_name);
Comment on lines 59 to +62

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Add a defensive check to ensure cache_alg_name is not NULL before proceeding. If cache_alg_name is NULL, passing it to get_builtin_cache_init or sprintf later in the function will cause a segmentation fault.

cache_t *create_cache_internal(const char *const cache_alg_name,
                               common_cache_params_t cc_params,
                               void *cache_specific_params) {
  if (cache_alg_name == NULL) {
    return NULL;
  }
  cache_init_func_ptr cache_init = get_builtin_cache_init(cache_alg_name);

if (cache_init != NULL) {
INFO("internal cache %s loaded\n", cache_alg_name);
return cache_init(cc_params, (const char *)cache_specific_params);
}

char *err = NULL;

char cache_init_func_name[256];
void *handle = dlopen(NULL, RTLD_GLOBAL);
void *handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
/* should not check err here, otherwise ubuntu will report err even though
* everything is OK */
Comment on lines +71 to 73

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a defensive check to ensure handle is not NULL after calling dlopen. If dlopen fails and returns NULL, passing it to dlsym can cause undefined behavior or a crash on some platforms.

  void *handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
  if (handle == NULL) {
    return NULL;
  }
  /* should not check err here, otherwise ubuntu will report err even though
   * everything is OK */


Expand All @@ -72,21 +77,22 @@ cache_t *create_cache_internal(const char *const cache_alg_name,
// ISO C compliant way to convert void* to function pointer
union {
void *obj_ptr;
cache_t *(*func_ptr)(common_cache_params_t, void *);
cache_init_func_ptr func_ptr;
} dlsym_ptr;

dlerror();
dlsym_ptr.obj_ptr = dlsym(handle, cache_init_func_name);
cache_init = dlsym_ptr.func_ptr;

err = dlerror();

if (cache_init == NULL) {
WARN("cannot load internal cache %s: error %s\n", cache_alg_name, err);
abort();
return NULL;
}
Comment on lines 89 to 92

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Handle the case where err is NULL gracefully. If dlerror() returns NULL, passing it directly to %s in WARN can cause undefined behavior or a crash on some platforms.

  if (cache_init == NULL) {
    WARN("cannot load internal cache %s: error %s\n", cache_alg_name, err ? err : "symbol not found");
    return NULL;
  }


INFO("internal cache %s loaded\n", cache_alg_name);
cache_t *cache = cache_init(cc_params, cache_specific_params);
cache_t *cache = cache_init(cc_params, (const char *)cache_specific_params);
return cache;
}

Expand Down
2 changes: 2 additions & 0 deletions libCacheSim/include/libCacheSim/evictionAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef struct {
int64_t n_byte_rewritten;
} Clock_params_t;

cache_init_func_ptr get_builtin_cache_init(const char *const cache_alg_name);

cache_t *ARC_init(const common_cache_params_t ccache_params,
const char *cache_specific_params);

Expand Down
1 change: 1 addition & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ python3 plot_mrc_time.py \
## Profile miss ratio curves

`mrcProfiler` enables fast profiling of miss ratio curves. With a proper parameter setting (such as `sampling_rate`, see [here](../doc/quickstart_mrcProfiler.md) for details) `mrcProfiler` can profile miss ratio curves in a fast way with acceptable accuracy.
When using the MINISIM profiler with built-in eviction algorithms, algorithm names are case-insensitive, so `lru,fifo` and `LRU,FIFO` both work.

```bash
# plot profiled miss ratio over sizes
Expand Down
18 changes: 18 additions & 0 deletions test/test_evictionAlgo.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,21 @@ static void test_WTinyLFU(gconstpointer user_data) {
// TODO: to be implemented
}

static void test_create_cache_using_plugin_lowercase(gconstpointer user_data) {
common_cache_params_t cc_params = {
.cache_size = CACHE_SIZE, .hashpower = 20, .default_ttl = DEFAULT_TTL};
cache_t *lru_cache = create_cache_using_plugin("lru", cc_params, NULL);
cache_t *fifo_cache = create_cache_using_plugin("fifo", cc_params, NULL);

g_assert_nonnull(lru_cache);
g_assert_nonnull(fifo_cache);
g_assert_cmpstr(lru_cache->cache_name, ==, "LRU");
g_assert_cmpstr(fifo_cache->cache_name, ==, "FIFO");

lru_cache->cache_free(lru_cache);
fifo_cache->cache_free(fifo_cache);
}

static void empty_test(gconstpointer user_data) { ; }

int main(int argc, char *argv[]) {
Expand Down Expand Up @@ -465,6 +480,9 @@ int main(int argc, char *argv[]) {
g_test_add_data_func("/libCacheSim/cacheAlgo_BeladySize", reader,
test_BeladySize);

g_test_add_data_func("/libCacheSim/create_cache_using_plugin_lowercase",
reader, test_create_cache_using_plugin_lowercase);

g_test_add_data_func_full("/libCacheSim/empty", reader, empty_test,
test_teardown);

Expand Down
Loading