diff --git a/doc/advanced_lib_extend.md b/doc/advanced_lib_extend.md index d91ac92c..0a3b9620 100644 --- a/doc/advanced_lib_extend.md +++ b/doc/advanced_lib_extend.md @@ -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] @@ -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) - diff --git a/doc/quickstart_mrcProfiler.md b/doc/quickstart_mrcProfiler.md index 86b437a2..4df1229b 100644 --- a/doc/quickstart_mrcProfiler.md +++ b/doc/quickstart_mrcProfiler.md @@ -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 @@ -168,4 +169,4 @@ resluts: - [x] Integrate plotting scripts. -- [ ] Implement additional profilers (e.g., FLOWS, TTLs Matter, Kosmo, AET). \ No newline at end of file +- [ ] Implement additional profilers (e.g., FLOWS, TTLs Matter, Kosmo, AET). diff --git a/libCacheSim/bin/cachesim/cache_init.h b/libCacheSim/bin/cachesim/cache_init.h index 34d85aae..c460035b 100644 --- a/libCacheSim/bin/cachesim/cache_init.h +++ b/libCacheSim/bin/cachesim/cache_init.h @@ -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) { @@ -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; diff --git a/libCacheSim/cache/CMakeLists.txt b/libCacheSim/cache/CMakeLists.txt index 0d1ef854..1626984b 100644 --- a/libCacheSim/cache/CMakeLists.txt +++ b/libCacheSim/cache/CMakeLists.txt @@ -134,6 +134,7 @@ set(cache_sources_c ${eviction_sources_c} ${prefetch_sources_c} cache.c + evictionAlgoRegister.c plugin.c ) diff --git a/libCacheSim/cache/evictionAlgoRegister.c b/libCacheSim/cache/evictionAlgoRegister.c new file mode 100644 index 00000000..35f2ba94 --- /dev/null +++ b/libCacheSim/cache/evictionAlgoRegister.c @@ -0,0 +1,94 @@ +#include + +#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) { + 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}, + {"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}, +#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 diff --git a/libCacheSim/cache/plugin.c b/libCacheSim/cache/plugin.c index 4751aae3..744453f3 100644 --- a/libCacheSim/cache/plugin.c +++ b/libCacheSim/cache/plugin.c @@ -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); + 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 */ @@ -72,9 +77,10 @@ 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; @@ -82,11 +88,11 @@ cache_t *create_cache_internal(const char *const cache_alg_name, if (cache_init == NULL) { WARN("cannot load internal cache %s: error %s\n", cache_alg_name, err); - abort(); + 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; } diff --git a/libCacheSim/include/libCacheSim/evictionAlgo.h b/libCacheSim/include/libCacheSim/evictionAlgo.h index 922c65e4..4b1caa32 100644 --- a/libCacheSim/include/libCacheSim/evictionAlgo.h +++ b/libCacheSim/include/libCacheSim/evictionAlgo.h @@ -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); diff --git a/scripts/README.md b/scripts/README.md index 5775bf55..779ffe9e 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -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 diff --git a/test/test_evictionAlgo.c b/test/test_evictionAlgo.c index cd5f989c..f59d85c9 100644 --- a/test/test_evictionAlgo.c +++ b/test/test_evictionAlgo.c @@ -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[]) { @@ -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);