From cd0abe057be54354e488fd2bc73f1faf6113882b Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 17 Feb 2023 22:06:12 -0500 Subject: [PATCH 1/2] prepare for public version --- libCacheSim/bin/cachesim/cli.c | 42 -- libCacheSim/cache/eviction/CMakeLists.txt | 29 - libCacheSim/cache/eviction/fifo/LP_ARC.c | 558 ------------------ libCacheSim/cache/eviction/fifo/LP_SFIFO.c | 451 -------------- libCacheSim/cache/eviction/fifo/LP_TwoQ.c | 383 ------------ libCacheSim/cache/eviction/fifo/SFIFO.c | 553 ----------------- libCacheSim/cache/eviction/fifo/SFIFOv0.c | 474 --------------- libCacheSim/cache/eviction/priv/LRU_Prob.c | 290 --------- libCacheSim/cache/eviction/priv/MClock.c | 483 --------------- libCacheSim/cache/eviction/priv/MyClock.c | 293 --------- libCacheSim/cache/eviction/priv/QDLP.c | 514 ---------------- libCacheSim/cache/eviction/priv/QDLPv1.c | 413 ------------- libCacheSim/cache/eviction/priv/QDLPv2.c | 485 --------------- libCacheSim/cache/eviction/priv/SFIFO_Merge.c | 469 --------------- .../cache/eviction/priv/SFIFO_Reinsertion.c | 473 --------------- libCacheSim/cache/eviction/priv/myMQv1.c | 376 ------------ .../include/libCacheSim/evictionAlgo.h | 56 +- 17 files changed, 3 insertions(+), 6339 deletions(-) delete mode 100644 libCacheSim/cache/eviction/fifo/LP_ARC.c delete mode 100644 libCacheSim/cache/eviction/fifo/LP_SFIFO.c delete mode 100644 libCacheSim/cache/eviction/fifo/LP_TwoQ.c delete mode 100644 libCacheSim/cache/eviction/fifo/SFIFO.c delete mode 100644 libCacheSim/cache/eviction/fifo/SFIFOv0.c delete mode 100644 libCacheSim/cache/eviction/priv/LRU_Prob.c delete mode 100644 libCacheSim/cache/eviction/priv/MClock.c delete mode 100644 libCacheSim/cache/eviction/priv/MyClock.c delete mode 100644 libCacheSim/cache/eviction/priv/QDLP.c delete mode 100644 libCacheSim/cache/eviction/priv/QDLPv1.c delete mode 100644 libCacheSim/cache/eviction/priv/QDLPv2.c delete mode 100644 libCacheSim/cache/eviction/priv/SFIFO_Merge.c delete mode 100644 libCacheSim/cache/eviction/priv/SFIFO_Reinsertion.c delete mode 100644 libCacheSim/cache/eviction/priv/myMQv1.c diff --git a/libCacheSim/bin/cachesim/cli.c b/libCacheSim/bin/cachesim/cli.c index aa5df535..783d9137 100644 --- a/libCacheSim/bin/cachesim/cli.c +++ b/libCacheSim/bin/cachesim/cli.c @@ -299,10 +299,6 @@ void parse_cmd(int argc, char *argv[], struct arguments *args) { cache = SLRU_init(cc_params, args->eviction_params); } else if (strcasecmp(args->eviction_algo, "slruv0") == 0) { cache = SLRUv0_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "sfifo") == 0) { - cache = SFIFO_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "sfifov0") == 0) { - cache = SFIFOv0_init(cc_params, args->eviction_params); } else if (strcasecmp(args->eviction_algo, "hyperbolic") == 0) { cc_params.hashpower = MAX(cc_params.hashpower - 8, 16); cache = Hyperbolic_init(cc_params, args->eviction_params); @@ -350,44 +346,6 @@ void parse_cmd(int argc, char *argv[], struct arguments *args) { #ifdef ENABLE_LRB } else if (strcasecmp(args->eviction_algo, "lrb") == 0) { cache = LRB_init(cc_params, args->eviction_params); -#endif -#ifdef INCLUDE_PRIV - } else if (strcasecmp(args->eviction_algo, "myclock") == 0) { - cache = MyClock_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "mclock") == 0) { - cache = MClock_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "lp-sfifo") == 0) { - cache = LP_SFIFO_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "lp-arc") == 0) { - cache = LP_ARC_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "lp-twoq") == 0) { - cache = LP_TwoQ_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "sfifomerge") == 0 || - strcasecmp(args->eviction_algo, "sfifo-merge") == 0) { - cache = SFIFO_Merge_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "sfifo-reinsertion") == 0) { - cache = SFIFO_Reinsertion_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "lru-prob") == 0) { - cache = LRU_Prob_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "qdlp") == 0) { - cache = QDLP_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "qdlpv1") == 0) { - cache = QDLPv1_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "qdlpv2") == 0) { - cache = QDLPv2_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "myMQv1") == 0) { - cache = myMQv1_init(cc_params, args->eviction_params); - } else if (strcasecmp(args->eviction_algo, "lru-belady") == 0) { - if (strstr(args->trace_path, ".zst") != NULL) { - ERROR("lru-belady only supports uncompressed trace files\n"); - } - ERROR("not implemented\n"); - // reader_t *reader = clone_reader(args->reader); - cache = LRU_init(cc_params, args->eviction_params); - // cache->future_stack_dist = get_stack_dist( - // reader, FUTURE_STACK_DIST, &(cache->future_stack_dist_array_size)); - // assert(get_num_of_req(reader) == cache->future_stack_dist_array_size); - // close_reader(reader); #endif } else { ERROR("do not support algorithm %s\n", args->eviction_algo); diff --git a/libCacheSim/cache/eviction/CMakeLists.txt b/libCacheSim/cache/eviction/CMakeLists.txt index c80733bd..dd45ae72 100644 --- a/libCacheSim/cache/eviction/CMakeLists.txt +++ b/libCacheSim/cache/eviction/CMakeLists.txt @@ -25,35 +25,6 @@ set(sourceC Size.c ) -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/priv") - set(sourceC ${sourceC} - priv/SFIFO_Merge.c - priv/SFIFO_Reinsertion.c - - priv/LRU_Prob.c - - priv/MyClock.c - priv/QDLP.c - - priv/QDLPv1.c - priv/QDLPv2.c - - priv/myMQv1.c - - priv/MClock.c - ) -endif() - -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/fifo") - set(sourceC ${sourceC} - fifo/LP_SFIFO.c - fifo/LP_TwoQ.c - fifo/LP_ARC.c - fifo/SFIFO.c - fifo/SFIFOv0.c - ) -endif() - set(sourceCPP cpp/LFU.cpp cpp/GDSF.cpp diff --git a/libCacheSim/cache/eviction/fifo/LP_ARC.c b/libCacheSim/cache/eviction/fifo/LP_ARC.c deleted file mode 100644 index ba8a13b7..00000000 --- a/libCacheSim/cache/eviction/fifo/LP_ARC.c +++ /dev/null @@ -1,558 +0,0 @@ -// -// LP_ARC cache replacement algorithm -// https://www.usenix.org/conference/fast-03/LP_ARC-self-tuning-low-overhead-replacement-cache -// -// -// the LRU queues are replaced with FIFO or others -// -// -// libCacheSim -// -// Created by Juncheng on 09/28/20. -// Copyright © 2020 Juncheng. All rights reserved. -// - -#include - -#include "../../dataStructure/hashtable/hashtable.h" -#include "../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct LP_ARC_params { - // L1_data is T1 in the paper, L1_ghost is B1 in the paper - cache_t *T1; - cache_t *B1; - cache_t *T2; - cache_t *B2; - - double p; - bool curr_obj_in_L1_ghost; - bool curr_obj_in_L2_ghost; - int64_t vtime_last_req_in_ghost; - request_t *req_local; -} LP_ARC_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void LP_ARC_parse_params(cache_t *cache, - const char *cache_specific_params); -static void LP_ARC_free(cache_t *cache); -static bool LP_ARC_get(cache_t *cache, const request_t *req); -static cache_obj_t *LP_ARC_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *LP_ARC_insert(cache_t *cache, const request_t *req); -static cache_obj_t *LP_ARC_to_evict(cache_t *cache, const request_t *req); -static void LP_ARC_evict(cache_t *cache, const request_t *req); -static bool LP_ARC_remove(cache_t *cache, const obj_id_t obj_id); -static int64_t LP_ARC_get_occupied_byte(const cache_t *cache); -static int64_t LP_ARC_get_n_obj(const cache_t *cache); - -/* internal functions */ - -/* this is the case IV in the paper */ -static void _LP_ARC_evict_miss_on_all_queues(cache_t *cache, - const request_t *req); -static void _LP_ARC_replace(cache_t *cache, const request_t *req); -static cache_obj_t *_LP_ARC_to_evict_miss_on_all_queues(cache_t *cache, - const request_t *req); -static cache_obj_t *_LP_ARC_to_replace(cache_t *cache, const request_t *req); - -static bool LP_ARC_get_debug(cache_t *cache, const request_t *req); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *LP_ARC_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("LP_ARC", ccache_params); - cache->cache_init = LP_ARC_init; - cache->cache_free = LP_ARC_free; - cache->get = LP_ARC_get; - cache->find = LP_ARC_find; - cache->insert = LP_ARC_insert; - cache->evict = LP_ARC_evict; - cache->remove = LP_ARC_remove; - cache->to_evict = LP_ARC_to_evict; - cache->can_insert = cache_can_insert_default; - cache->get_occupied_byte = LP_ARC_get_occupied_byte; - cache->get_n_obj = LP_ARC_get_n_obj; - cache->init_params = cache_specific_params; - - if (ccache_params.consider_obj_metadata) { - // two pointer + ghost metadata - cache->obj_md_size = 8 * 2 + 8 * 3; - } else { - cache->obj_md_size = 0; - } - - cache->eviction_params = my_malloc_n(LP_ARC_params_t, 1); - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - params->p = 0; - - common_cache_params_t ccache_params_local = ccache_params; - params->T1 = Clock_init(ccache_params_local, NULL); - params->B1 = LRU_init(ccache_params_local, NULL); - params->T2 = Clock_init(ccache_params_local, NULL); - params->B2 = LRU_init(ccache_params_local, NULL); - - params->curr_obj_in_L1_ghost = false; - params->curr_obj_in_L2_ghost = false; - params->vtime_last_req_in_ghost = -1; - params->req_local = new_request(); - - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "LP-ARC-Clock"); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void LP_ARC_free(cache_t *cache) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - params->T1->cache_free(params->T1); - params->T2->cache_free(params->T2); - params->B1->cache_free(params->B1); - params->B2->cache_free(params->B2); - - free_request(params->req_local); - my_free(sizeof(LP_ARC_params_t), params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool LP_ARC_get(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - return LP_ARC_get_debug(cache, req); - // return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *LP_ARC_find(cache_t *cache, const request_t *req, - const bool update_cache) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - cache_obj_t *obj_t1 = params->T1->find(params->T1, req, false); - cache_obj_t *obj_t2 = params->T2->find(params->T2, req, false); - DEBUG_ASSERT(obj_t1 == NULL || obj_t2 == NULL); - cache_obj_t *obj = obj_t1 ? obj_t1 : obj_t2; - - if (!update_cache) { - return obj; - } - - cache_obj_t *obj_b1 = params->B1->find(params->B1, req, false); - cache_obj_t *obj_b2 = params->B2->find(params->B2, req, false); - DEBUG_ASSERT(obj_b1 == NULL || obj_b2 == NULL); - cache_obj_t *obj_ghost = obj_b1 ? obj_b1 : obj_b2; - DEBUG_ASSERT(obj == NULL || obj_ghost == NULL); - - if (obj == NULL && obj_ghost == NULL) { - return NULL; - } - - params->curr_obj_in_L1_ghost = false; - params->curr_obj_in_L2_ghost = false; - - int64_t b1_size = params->B1->get_occupied_byte(params->B1); - int64_t b2_size = params->B2->get_occupied_byte(params->B2); - - if (obj_ghost != NULL) { - params->vtime_last_req_in_ghost = cache->n_req; - // cache miss, but hit on thost - if (obj_b1 != NULL) { - params->curr_obj_in_L1_ghost = true; - // case II: x in L1_ghost - double delta = MAX((double)b2_size / b1_size, 1); - params->p = MIN(params->p + delta, cache->cache_size); - bool removed = params->B1->remove(params->B1, obj_b1->obj_id); - DEBUG_ASSERT(removed); - } else { - params->curr_obj_in_L2_ghost = true; - // case III: x in L2_ghost - double delta = MAX((double)b1_size / b2_size, 1); - params->p = MAX(params->p - delta, 0); - bool removed = params->B2->remove(params->B2, obj_b2->obj_id); - DEBUG_ASSERT(removed); - } - } else { - // cache hit, case I: x in L1_data or L2_data - if (obj_t1 != NULL) { - params->T1->remove(params->T1, obj_t1->obj_id); - params->T2->get(params->T2, req); - DEBUG_ASSERT(params->B2->find(params->B2, req, false) == NULL); - } else { - // move to LRU2 head - cache_obj_t *obj_tmp = params->T2->find(params->T2, req, true); - assert(obj_tmp == obj_t2); - } - } - - return obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *LP_ARC_insert(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - cache_obj_t *obj = NULL; - - if (params->vtime_last_req_in_ghost == cache->n_req && - (params->curr_obj_in_L1_ghost || params->curr_obj_in_L2_ghost)) { - // insert to L2 data head - obj = params->T2->insert(params->T2, req); - DEBUG_ASSERT(params->B2->find(params->B2, req, false) == NULL); - - params->curr_obj_in_L1_ghost = false; - params->curr_obj_in_L2_ghost = false; - params->vtime_last_req_in_ghost = -1; - } else { - // insert to L1 data head - obj = params->T1->insert(params->T1, req); - } - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *LP_ARC_to_evict(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - cache->to_evict_candidate_gen_vtime = cache->n_req; - if (params->vtime_last_req_in_ghost == cache->n_req && - (params->curr_obj_in_L1_ghost || params->curr_obj_in_L2_ghost)) { - cache->to_evict_candidate = _LP_ARC_to_replace(cache, req); - } else { - cache->to_evict_candidate = _LP_ARC_to_evict_miss_on_all_queues(cache, req); - } - return cache->to_evict_candidate; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void LP_ARC_evict(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - if (params->vtime_last_req_in_ghost == cache->n_req && - (params->curr_obj_in_L1_ghost || params->curr_obj_in_L2_ghost)) { - _LP_ARC_replace(cache, req); - } else { - _LP_ARC_evict_miss_on_all_queues(cache, req); - } - cache->to_evict_candidate_gen_vtime = -1; -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool LP_ARC_remove(cache_t *cache, const obj_id_t obj_id) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - bool removed = false; - removed |= params->T1->remove(params->T1, obj_id); - removed |= params->T2->remove(params->T2, obj_id); - - return removed; -} - -static int64_t LP_ARC_get_occupied_byte(const cache_t *cache) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - return params->T1->get_occupied_byte(params->T1) + - params->T2->get_occupied_byte(params->T2); -} - -static int64_t LP_ARC_get_n_obj(const cache_t *cache) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - return params->T1->get_n_obj(params->T1) + params->T2->get_n_obj(params->T2); -} - -// *********************************************************************** -// **** **** -// **** cache internal functions **** -// **** **** -// *********************************************************************** -/* finding the eviction candidate in _LP_ARC_replace but do not perform eviction - */ -static cache_obj_t *_LP_ARC_to_replace(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - cache_obj_t *obj = NULL; - int64_t t1_size = params->T1->get_occupied_byte(params->T1); - - if (t1_size > 0 && (t1_size > params->p || - (t1_size == params->p && params->curr_obj_in_L2_ghost))) { - // delete the LRU in L1 data, move to L1_ghost - obj = params->T1->to_evict(params->T1, req); - } else { - // delete the item in L2 data, move to L2_ghost - obj = params->T2->to_evict(params->T2, req); - } - DEBUG_ASSERT(obj != NULL); - return obj; -} - -/* the REPLACE function in the paper */ -static void _LP_ARC_replace(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - int64_t t1_size = params->T1->get_occupied_byte(params->T1); - int64_t t2_size = params->T2->get_occupied_byte(params->T2); - - bool cond1 = t1_size > 0; - bool cond2 = t1_size > params->p; - bool cond3 = t1_size == params->p && params->curr_obj_in_L2_ghost; - bool cond4 = t2_size == 0; - - if ((cond1 && (cond2 || cond3)) || cond4) { - // delete the LRU in L1 data, move to L1_ghost - cache_obj_t *obj = params->T1->to_evict(params->T1, req); - DEBUG_ASSERT(obj != NULL); - copy_cache_obj_to_request(params->req_local, obj); - bool in_g = params->B1->get(params->B1, params->req_local); - DEBUG_ASSERT(in_g == false); - params->T1->evict(params->T1, req); - } else { - // delete the item in L2 data, move to L2_ghost - cache_obj_t *obj = params->T2->to_evict(params->T2, req); - DEBUG_ASSERT(obj != NULL); - copy_cache_obj_to_request(params->req_local, obj); - bool in_g = params->B2->get(params->B2, params->req_local); - DEBUG_ASSERT(in_g == false); - params->T2->evict(params->T2, req); - } -} - -/* finding the eviction candidate in _LP_ARC_evict_miss_on_all_queues, but do - * not perform eviction */ -static cache_obj_t *_LP_ARC_to_evict_miss_on_all_queues(cache_t *cache, - const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - int64_t t1_size = params->T1->get_occupied_byte(params->T1); - int64_t b1_size = params->B1->get_occupied_byte(params->B1); - - int64_t incoming_size = req->obj_size + cache->obj_md_size; - if (t1_size + b1_size + incoming_size > cache->cache_size) { - // case A: L1 = T1 U B1 has exactly c pages - if (b1_size > 0) { - return _LP_ARC_to_replace(cache, req); - } else { - // T1 >= c, L1 data size is too large, ghost is empty, so evict from L1 - // data - return params->T1->to_evict(params->T1, req); - } - } else { - return _LP_ARC_to_replace(cache, req); - } -} - -/* this is the case IV in the paper */ -static void _LP_ARC_evict_miss_on_all_queues(cache_t *cache, - const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - int64_t t1_size = params->T1->get_occupied_byte(params->T1); - int64_t b1_size = params->B1->get_occupied_byte(params->B1); - - int64_t incoming_size = req->obj_size + cache->obj_md_size; - if (t1_size + b1_size + incoming_size > cache->cache_size) { - // case A: L1 = T1 U B1 has exactly c pages - if (b1_size > 0) { - // if T1 < c (ghost is not empty), - // delete the LRU of the L1 ghost, and replace - // we do not use t1_size < cache->cache_size - // because it does not work for variable size objects - params->B1->evict(params->B1, req); - return _LP_ARC_replace(cache, req); - } else { - // T1 >= c, L1 data size is too large, ghost is empty, so evict from L1 - // data - return params->T1->evict(params->T1, req); - } - } else { - int64_t t2_size = params->T2->get_occupied_byte(params->T2); - DEBUG_ASSERT(t1_size + b1_size < cache->cache_size); - while (t1_size + b1_size + t2_size + - params->B2->get_occupied_byte(params->B2) >= - cache->cache_size * 2) { - // delete the LRU end of the L2 ghost - params->B2->evict(params->B2, req); - } - return _LP_ARC_replace(cache, req); - } -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *LP_ARC_current_params(LP_ARC_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "\n"); - return params_str; -} - -static void LP_ARC_parse_params(cache_t *cache, - const char *cache_specific_params) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "print") == 0) { - printf("parameters: %s\n", LP_ARC_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** debug functions **** -// **** **** -// *********************************************************************** -static void print_cache(cache_t *cache) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - printf("T1: "); - params->T1->print_cache(params->T1); - printf("T2: "); - params->T2->print_cache(params->T2); - printf("B1: "); - params->B1->print_cache(params->B1); - printf("B2: "); - params->B2->print_cache(params->B2); -} - -static bool LP_ARC_get_debug(cache_t *cache, const request_t *req) { - LP_ARC_params_t *params = (LP_ARC_params_t *)(cache->eviction_params); - - cache->n_req += 1; - - // printf("%ld obj_id %ld: p %.2lf\n", cache->n_req, req->obj_id, params->p); - // print_cache(cache); - // printf("==================================\n"); - - cache_obj_t *obj = cache->find(cache, req, true); - - if (obj != NULL) { - return true; - } - - while (cache->get_occupied_byte(cache) + req->obj_size + cache->obj_md_size > - cache->cache_size) { - cache->evict(cache, req); - } - - cache->insert(cache, req); - - return false; -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/fifo/LP_SFIFO.c b/libCacheSim/cache/eviction/fifo/LP_SFIFO.c deleted file mode 100644 index 7274c420..00000000 --- a/libCacheSim/cache/eviction/fifo/LP_SFIFO.c +++ /dev/null @@ -1,451 +0,0 @@ -// -// segmented fifo implemented using multiple lists instead of multiple fifos -// this has a better performance than LP_SFIFOv0, but it is very hard to -// implement -// -// LP_SFIFO.c -// libCacheSim -// -// - -#include "../../dataStructure/hashtable/hashtable.h" -#include "../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define LP_SFIFO_MAX_N_SEG 16 - -typedef struct LP_SFIFO_params { - cache_t **fifos; - int64_t *per_seg_max_size; - int n_seg; - request_t *req_local; -} LP_SFIFO_params_t; - -static const char *DEFAULT_PARAMS = "n-seg=4,seg-size=1:1:1:1"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** -static void LP_SFIFO_parse_params(cache_t *cache, - const char *cache_specific_params); -static void LP_SFIFO_parse_params(cache_t *cache, - const char *cache_specific_params); -static void LP_SFIFO_free(cache_t *cache); -static bool LP_SFIFO_get(cache_t *cache, const request_t *req); -static cache_obj_t *LP_SFIFO_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *LP_SFIFO_insert(cache_t *cache, const request_t *req); -static cache_obj_t *LP_SFIFO_to_evict(cache_t *cache, const request_t *req); -static void LP_SFIFO_evict(cache_t *cache, const request_t *req); -static bool LP_SFIFO_remove(cache_t *cache, const obj_id_t obj_id); - -static inline bool LP_SFIFO_can_insert(cache_t *cache, const request_t *req); -static inline int64_t LP_SFIFO_get_occupied_byte(const cache_t *cache); -static inline int64_t LP_SFIFO_get_n_obj(const cache_t *cache); -static void LP_SFIFO_demote(cache_t *cache, const request_t *req, int seg_id); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** -/** - * @brief initialize a LP_SFIFO cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params LP_SFIFO specific parameters, e.g., "n-seg=4" - */ -cache_t *LP_SFIFO_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("LP-SFIFO", ccache_params); - cache->cache_init = LP_SFIFO_init; - cache->cache_free = LP_SFIFO_free; - cache->get = LP_SFIFO_get; - cache->find = LP_SFIFO_find; - cache->insert = LP_SFIFO_insert; - cache->evict = LP_SFIFO_evict; - cache->remove = LP_SFIFO_remove; - cache->to_evict = LP_SFIFO_to_evict; - cache->init_params = cache_specific_params; - cache->get_occupied_byte = LP_SFIFO_get_occupied_byte; - cache->get_n_obj = LP_SFIFO_get_n_obj; - cache->can_insert = LP_SFIFO_can_insert; - - cache->obj_md_size = 0; - - cache->eviction_params = (LP_SFIFO_params_t *)malloc(sizeof(LP_SFIFO_params_t)); - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - memset(params, 0, sizeof(LP_SFIFO_params_t)); - params->req_local = new_request(); - - // prepare the default parameters - LP_SFIFO_parse_params(cache, DEFAULT_PARAMS); - if (cache_specific_params != NULL) { - LP_SFIFO_parse_params(cache, cache_specific_params); - } - - common_cache_params_t ccache_params_local = ccache_params; - ccache_params_local.hashpower -= 2; - params->fifos = malloc(sizeof(cache_t *) * params->n_seg); - - for (int i = 0; i < params->n_seg; i++) { - ccache_params_local.cache_size = params->per_seg_max_size[i]; - params->fifos[i] = FIFO_init(ccache_params_local, NULL); - } - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void LP_SFIFO_free(cache_t *cache) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - free_request(params->req_local); - for (int i = 0; i < params->n_seg; i++) { - params->fifos[i]->cache_free(params->fifos[i]); - } - free(params->fifos); - free(params->per_seg_max_size); - free(params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool LP_SFIFO_get(cache_t *cache, const request_t *req) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - // printf("%ld %ld %ld %ld %ld\n", cache->n_req, - // params->fifos[0]->get_n_obj(params->fifos[0]), - // params->fifos[1]->get_n_obj(params->fifos[1]), - // params->fifos[2]->get_n_obj(params->fifos[2]), - // params->fifos[3]->get_n_obj(params->fifos[3])); - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *LP_SFIFO_find(cache_t *cache, const request_t *req, - const bool update_cache) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - cache_obj_t *obj = NULL; - for (int i = 0; i < params->n_seg; i++) { - obj = params->fifos[i]->find(params->fifos[i], req, false); - if (obj != NULL) { - // TODO: can distinguish hits on different segments - if (i == 0) { - if (obj->SFIFO.freq == 0) { - obj->SFIFO.freq = 1; - } - } else { - obj->SFIFO.freq += 1; - } - - return obj; - } - } - - return NULL; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -cache_obj_t *LP_SFIFO_insert(cache_t *cache, const request_t *req) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - - // Find the lowest fifo with space for insertion - int nth_seg = -1; - for (int i = 0; i < params->n_seg; i++) { - if (params->fifos[i]->get_occupied_byte(params->fifos[i]) + req->obj_size + - cache->obj_md_size <= - params->per_seg_max_size[i]) { - nth_seg = i; - break; - } - } - - if (nth_seg == -1) { - // No space for insertion - while (cache->occupied_byte + req->obj_size + cache->obj_md_size > - cache->cache_size) { - cache->evict(cache, req); - } - nth_seg = 0; - } - - // cache_obj_t *obj = hashtable_insert(cache->hashtable, req); - cache_obj_t *obj = - params->fifos[nth_seg]->insert(params->fifos[nth_seg], req); - obj->SFIFO.freq = 0; - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *LP_SFIFO_to_evict(cache_t *cache, const request_t *req) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - for (int i = 0; i < params->n_seg; i++) { - if (params->fifos[i]->get_occupied_byte(params->fifos[i]) > 0) { - return params->fifos[i]->to_evict(params->fifos[i], req); - } - } -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void LP_SFIFO_evict(cache_t *cache, const request_t *req) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - - cache_obj_t *obj = NULL; - assert(params->fifos[0]->get_occupied_byte(params->fifos[0]) > 0); - - obj = params->fifos[0]->to_evict(params->fifos[0], req); - if (obj->SFIFO.freq > 0) { - // insert to the next segment - int seg_id_to_upsert = obj->SFIFO.freq; - if (seg_id_to_upsert >= params->n_seg) { - seg_id_to_upsert = params->n_seg - 1; - } - copy_cache_obj_to_request(params->req_local, obj); - params->fifos[0]->evict(params->fifos[0], req); - // if (seg_id_to_upsert != 1) - // printf("insert to %d\n", seg_id_to_upsert); - - cache_t *fifo_insert = params->fifos[seg_id_to_upsert]; - obj = fifo_insert->insert(fifo_insert, params->req_local); - obj->SFIFO.freq = 0; - - if (fifo_insert->get_occupied_byte(fifo_insert) > - params->per_seg_max_size[seg_id_to_upsert]) - LP_SFIFO_demote(cache, req, seg_id_to_upsert); - } else { - params->fifos[0]->evict(params->fifos[0], req); - } -} - -static void LP_SFIFO_demote(cache_t *cache, const request_t *req, int seg_id) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - cache_obj_t *obj = NULL; - - if (seg_id == 0) { - assert(cache->get_occupied_byte(cache) <= cache->cache_size); - return; - } - - cache_t *curr_fifo = params->fifos[seg_id]; - cache_t *next_fifo = params->fifos[seg_id - 1]; - - while (curr_fifo->get_occupied_byte(curr_fifo) > - params->per_seg_max_size[seg_id]) { - obj = curr_fifo->to_evict(curr_fifo, req); - int freq = obj->SFIFO.freq; - copy_cache_obj_to_request(params->req_local, obj); - curr_fifo->evict(curr_fifo, req); - - obj = next_fifo->insert(next_fifo, params->req_local); - obj->SFIFO.freq = freq; - } - if (next_fifo->get_occupied_byte(next_fifo) > - params->per_seg_max_size[seg_id - 1]) { - return LP_SFIFO_demote(cache, req, seg_id - 1); - } -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool LP_SFIFO_remove(cache_t *cache, const obj_id_t obj_id) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)(cache->eviction_params); - - for (int i = 0; i < params->n_seg; i++) { - if (params->fifos[i]->remove(params->fifos[i], obj_id)) { - return true; - } - } - - return false; -} - -// *********************************************************************** -// **** **** -// **** setup functions **** -// **** **** -// *********************************************************************** -static const char *LP_SFIFO_current_params(cache_t *cache, - LP_SFIFO_params_t *params) { - static __thread char params_str[128]; - int n = - snprintf(params_str, 128, "n-seg=%d;seg-size=%d\n", params->n_seg, - (int)(params->per_seg_max_size[0] * 100 / cache->cache_size)); - - for (int i = 1; i < params->n_seg; i++) { - n += snprintf(params_str + n, 128 - n, ":%d", - (int)(params->per_seg_max_size[i] * 100 / cache->cache_size)); - } - snprintf(cache->cache_name + n, 128 - n, ")"); - - return params_str; -} - -static void LP_SFIFO_parse_params(cache_t *cache, - const char *cache_specific_params) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "n-seg") == 0) { - params->n_seg = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "seg-size") == 0) { - int n_seg = 0; - int64_t seg_size_sum = 0; - int64_t seg_size_array[LP_SFIFO_MAX_N_SEG]; - char *v = strsep((char **)&value, ":"); - while (v != NULL) { - seg_size_array[n_seg++] = (int64_t)strtol(v, &end, 0); - seg_size_sum += seg_size_array[n_seg - 1]; - v = strsep((char **)&value, ":"); - } - params->n_seg = n_seg; - if (params->per_seg_max_size != NULL) { - free(params->per_seg_max_size); - } - params->per_seg_max_size = calloc(params->n_seg, sizeof(int64_t)); - for (int i = 0; i < n_seg; i++) { - params->per_seg_max_size[i] = (int64_t)( - (double)seg_size_array[i] / seg_size_sum * cache->cache_size); - } - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", LP_SFIFO_current_params(cache, params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** internal functions **** -// **** **** -// *********************************************************************** - -/* LP_SFIFO cannot an object larger than segment size */ -static inline bool LP_SFIFO_can_insert(cache_t *cache, const request_t *req) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)cache->eviction_params; - bool can_insert = cache_can_insert_default(cache, req); - return can_insert && - (req->obj_size + cache->obj_md_size <= params->fifos[0]->cache_size); -} - -static inline int64_t LP_SFIFO_get_occupied_byte(const cache_t *cache) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)cache->eviction_params; - int64_t occupied_byte = 0; - for (int i = 0; i < params->n_seg; i++) { - occupied_byte += params->fifos[i]->get_occupied_byte(params->fifos[i]); - } - return occupied_byte; -} - -static inline int64_t LP_SFIFO_get_n_obj(const cache_t *cache) { - LP_SFIFO_params_t *params = (LP_SFIFO_params_t *)cache->eviction_params; - int64_t n_obj = 0; - for (int i = 0; i < params->n_seg; i++) { - n_obj += params->fifos[i]->get_occupied_byte(params->fifos[i]); - } - return n_obj; -} - - -#ifdef __cplusplus -extern "C" -} -#endif \ No newline at end of file diff --git a/libCacheSim/cache/eviction/fifo/LP_TwoQ.c b/libCacheSim/cache/eviction/fifo/LP_TwoQ.c deleted file mode 100644 index b17117b4..00000000 --- a/libCacheSim/cache/eviction/fifo/LP_TwoQ.c +++ /dev/null @@ -1,383 +0,0 @@ -// -// Quick demotion + lazy promoition v1 -// -// 20% Ain + ARC -// insert to ARC when evicting from Ain -// -// -// LP_TwoQ.c -// libCacheSim -// -// Created by Juncheng on 12/4/18. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../dataStructure/hashtable/hashtable.h" -#include "../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_t *Ain; - cache_t *Aout; - cache_t *Am; - bool hit_on_ghost; - - int64_t Ain_cache_size; - int64_t Aout_cache_size; - int64_t Am_cache_size; - double Ain_size_ratio; - double Aout_size_ratio; - char Am_type[32]; - - request_t *req_local; -} LP_TwoQ_params_t; - -static const char *DEFAULT_CACHE_PARAMS = - "Ain-size-ratio=0.25,Aout-size-ratio=0.5"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** -cache_t *LP_TwoQ_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); -static void LP_TwoQ_free(cache_t *cache); -static bool LP_TwoQ_get(cache_t *cache, const request_t *req); - -static cache_obj_t *LP_TwoQ_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *LP_TwoQ_insert(cache_t *cache, const request_t *req); -static cache_obj_t *LP_TwoQ_to_evict(cache_t *cache, const request_t *req); -static void LP_TwoQ_evict(cache_t *cache, const request_t *req); -static bool LP_TwoQ_remove(cache_t *cache, const obj_id_t obj_id); -static inline int64_t LP_TwoQ_get_occupied_byte(const cache_t *cache); -static inline int64_t LP_TwoQ_get_n_obj(const cache_t *cache); -static inline bool LP_TwoQ_can_insert(cache_t *cache, const request_t *req); -static void LP_TwoQ_parse_params(cache_t *cache, - const char *cache_specific_params); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** -/** - * @brief initialize cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *LP_TwoQ_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("LP-TwoQv2", ccache_params); - cache->cache_init = LP_TwoQ_init; - cache->cache_free = LP_TwoQ_free; - cache->get = LP_TwoQ_get; - cache->find = LP_TwoQ_find; - cache->insert = LP_TwoQ_insert; - cache->evict = LP_TwoQ_evict; - cache->remove = LP_TwoQ_remove; - cache->to_evict = LP_TwoQ_to_evict; - cache->init_params = cache_specific_params; - cache->get_n_obj = LP_TwoQ_get_n_obj; - cache->get_occupied_byte = LP_TwoQ_get_occupied_byte; - cache->can_insert = LP_TwoQ_can_insert; - - cache->obj_md_size = 0; - - cache->eviction_params = malloc(sizeof(LP_TwoQ_params_t)); - memset(cache->eviction_params, 0, sizeof(LP_TwoQ_params_t)); - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - params->req_local = new_request(); - params->hit_on_ghost = false; - - LP_TwoQ_parse_params(cache, DEFAULT_CACHE_PARAMS); - if (cache_specific_params != NULL) { - LP_TwoQ_parse_params(cache, cache_specific_params); - } - - params->Ain_cache_size = ccache_params.cache_size * params->Ain_size_ratio; - params->Aout_cache_size = ccache_params.cache_size * params->Aout_size_ratio; - params->Am_cache_size = ccache_params.cache_size - params->Ain_cache_size; - - common_cache_params_t ccache_params_local = ccache_params; - ccache_params_local.cache_size = params->Ain_cache_size; - params->Ain = FIFO_init(ccache_params_local, NULL); - - ccache_params_local.cache_size = params->Aout_cache_size; - params->Aout = FIFO_init(ccache_params_local, NULL); - - ccache_params_local.cache_size = params->Am_cache_size; - // params->Am = LRU_init(ccache_params_local, NULL); - params->Am = Clock_init(ccache_params_local, NULL); - - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "LP-TwoQ-Clock"); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void LP_TwoQ_free(cache_t *cache) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - free_request(params->req_local); - params->Ain->cache_free(params->Ain); - params->Aout->cache_free(params->Aout); - params->Am->cache_free(params->Am); - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool LP_TwoQ_get(cache_t *cache, const request_t *req) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - DEBUG_ASSERT(params->Ain->get_occupied_byte(params->Ain) + - params->Am->get_occupied_byte(params->Am) <= - cache->cache_size); - bool cache_hit = cache_get_base(cache, req); - return cache_hit; -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *LP_TwoQ_find(cache_t *cache, const request_t *req, - const bool update_cache) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - - cache_obj_t *obj = params->Ain->find(params->Ain, req, false); - - // if update cache is false, we only check the Ain and Am - if (!update_cache) { - if (obj != NULL) { - return obj; - } - obj = params->Am->find(params->Am, req, false); - if (obj != NULL) { - return obj; - } - return NULL; - } - - /* update cache is true from now */ - params->hit_on_ghost = false; - if (obj != NULL) { - return obj; - } - - if (params->Aout->remove(params->Aout, req->obj_id)) { - // if object in Aout, remove will return true - params->hit_on_ghost = true; - } - - obj = params->Am->find(params->Am, req, update_cache); - - return obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *LP_TwoQ_insert(cache_t *cache, const request_t *req) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - cache_obj_t *obj = NULL; - - if (params->hit_on_ghost) { - /* insert into the ARC */ - params->hit_on_ghost = false; - params->Am->get(params->Am, req); - } else { - /* insert into the Ain */ - obj = params->Ain->insert(params->Ain, req); - } - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *LP_TwoQ_to_evict(cache_t *cache, const request_t *req) { - assert(false); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void LP_TwoQ_evict(cache_t *cache, const request_t *req) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - - cache_t *Ain = params->Ain; - cache_t *Aout = params->Aout; - cache_t *Am = params->Am; - - if (Ain->get_occupied_byte(Ain) > params->Ain_cache_size) { - // evict from Ain cache - cache_obj_t *obj = Ain->to_evict(Ain, req); - assert(obj != NULL); - // need to copy the object before it is evicted - copy_cache_obj_to_request(params->req_local, obj); - Aout->get(Aout, params->req_local); - Ain->evict(Ain, req); - } else { - // // evict from Am and insert into Aout - // cache_obj_t *obj = Am->to_evict(Ain, req); - // assert(obj != NULL); - // // need to copy the object before it is evicted - // copy_cache_obj_to_request(params->req_local, obj); - // Aout->get(Aout, params->req_local); - // evict from Am - Am->evict(Am, req); - } -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool LP_TwoQ_remove(cache_t *cache, const obj_id_t obj_id) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - bool removed = false; - removed = removed || params->Ain->remove(params->Ain, obj_id); - removed = removed || params->Aout->remove(params->Aout, obj_id); - removed = removed || params->Am->remove(params->Am, obj_id); - - return removed; -} - -static inline int64_t LP_TwoQ_get_occupied_byte(const cache_t *cache) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - return params->Ain->get_occupied_byte(params->Ain) + - params->Am->get_occupied_byte(params->Am); -} - -static inline int64_t LP_TwoQ_get_n_obj(const cache_t *cache) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - return params->Ain->get_n_obj(params->Ain) + - params->Am->get_n_obj(params->Am); -} - -static inline bool LP_TwoQ_can_insert(cache_t *cache, const request_t *req) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)cache->eviction_params; - - return req->obj_size <= params->Ain->cache_size; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *LP_TwoQ_current_params(LP_TwoQ_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "Ain-size-ratio=%.2lf,Aout-size-ratio=%.2lf\n", - params->Ain_size_ratio, params->Aout_size_ratio); - return params_str; -} - -static void LP_TwoQ_parse_params(cache_t *cache, - const char *cache_specific_params) { - LP_TwoQ_params_t *params = (LP_TwoQ_params_t *)(cache->eviction_params); - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "Ain-size-ratio") == 0) { - params->Ain_size_ratio = strtod(value, NULL); - } else if (strcasecmp(key, "Aout-size-ratio") == 0) { - params->Aout_size_ratio = strtod(value, NULL); - } else if (strcasecmp(key, "print") == 0) { - printf("parameters: %s\n", LP_TwoQ_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/fifo/SFIFO.c b/libCacheSim/cache/eviction/fifo/SFIFO.c deleted file mode 100644 index 5d51f4c4..00000000 --- a/libCacheSim/cache/eviction/fifo/SFIFO.c +++ /dev/null @@ -1,553 +0,0 @@ -// -// segmented fifo implemented using multiple lists instead of multiple fifos -// this has a better performance than SFIFOv0, but it is very hard to implement -// -// SFIFO.c -// libCacheSim -// -// - -#include "../../dataStructure/hashtable/hashtable.h" -#include "../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// #define DEBUG_MODE - -// *********************************************************************** -// **** **** -// **** debug macros **** -// **** **** -// *********************************************************************** -#ifdef DEBUG_MODE -#define DEBUG_PRINT_CACHE_STATE(cache, params, req) \ - do { \ - if (cache->n_req > 0) { \ - printf("%ld %ld %s: %s: ", cache->n_req, req->obj_id, __func__, \ - (char *)cache->last_request_metadata); \ - for (int i = 0; i < params->n_seg; i++) { \ - printf("%ld/%ld/%p/%p, ", params->fifo_n_objs[i], \ - params->fifo_n_bytes[i], params->fifo_heads[i], \ - params->fifo_tails[i]); \ - } \ - printf("\n"); \ - _SFIFO_verify_fifo_size(cache); \ - } \ - } while (0) - -#define DEBUG_PRINT_CACHE(cache, params) \ - do { \ - for (int i = params->n_seg - 1; i >= 0; i--) { \ - cache_obj_t *obj = params->fifo_heads[i]; \ - while (obj != NULL) { \ - printf("%lu(%u)->", obj->obj_id, obj->obj_size); \ - obj = obj->queue.next; \ - } \ - printf(" | "); \ - } \ - printf("\n"); \ - } while (0) -#else -#define DEBUG_PRINT_CACHE_STATE(cache, params, req) -#define DEBUG_PRINT_CACHE(cache, params) -#endif - -typedef struct SFIFO_params { - cache_obj_t **fifo_heads; - cache_obj_t **fifo_tails; - int64_t *fifo_n_bytes; - int64_t *fifo_n_objs; - int64_t per_seg_max_size; - int n_seg; -} SFIFO_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** -static void SFIFO_parse_params(cache_t *cache, - const char *cache_specific_params); -static void SFIFO_parse_params(cache_t *cache, const char *cache_specific_params); -static void SFIFO_free(cache_t *cache); -static bool SFIFO_get(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFO_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *SFIFO_insert(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFO_to_evict(cache_t *cache, const request_t *req); -static void SFIFO_evict(cache_t *cache, const request_t *req); -static bool SFIFO_remove(cache_t *cache, const obj_id_t obj_id); - -/* internal functions */ -static bool SFIFO_can_insert(cache_t *cache, const request_t *req); -static void SFIFO_promote_to_next_seg(cache_t *cache, const request_t *req, - cache_obj_t *obj); -static void SFIFO_demote_to_prev_seg(cache_t *cache, const request_t *req, - cache_obj_t *obj); -static void SFIFO_cool(cache_t *cache, const request_t *req, const int id); - -/* debug functions */ -static void _SFIFO_verify_fifo_size(cache_t *cache); -bool SFIFO_get_debug(cache_t *cache, const request_t *req); - -static inline bool seg_too_large(cache_t *cache, int seg_id) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - return params->fifo_n_bytes[seg_id] > params->per_seg_max_size; -} - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** -static void SFIFO_free(cache_t *cache) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - free(params->fifo_heads); - free(params->fifo_tails); - free(params->fifo_n_objs); - free(params->fifo_n_bytes); - cache_struct_free(cache); -} - -/** - * @brief initialize a SFIFO cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params SFIFO specific parameters, e.g., "n-seg=4" - */ -cache_t *SFIFO_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("SFIFO", ccache_params); - cache->cache_init = SFIFO_init; - cache->cache_free = SFIFO_free; - cache->get = SFIFO_get; - cache->find = SFIFO_find; - cache->insert = SFIFO_insert; - cache->evict = SFIFO_evict; - cache->remove = SFIFO_remove; - cache->to_evict = SFIFO_to_evict; - cache->init_params = cache_specific_params; - cache->get_occupied_byte = cache_get_occupied_byte_default; - cache->get_n_obj = cache_get_n_obj_default; - cache->can_insert = SFIFO_can_insert; - - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 8 * 2; - } else { - cache->obj_md_size = 0; - } - - cache->eviction_params = (SFIFO_params_t *)malloc(sizeof(SFIFO_params_t)); - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - params->n_seg = 4; - - if (cache_specific_params != NULL) { - SFIFO_parse_params(cache, cache_specific_params); - } - - params->per_seg_max_size = ccache_params.cache_size / params->n_seg; - params->fifo_heads = - (cache_obj_t **)malloc(sizeof(cache_obj_t *) * params->n_seg); - params->fifo_tails = - (cache_obj_t **)malloc(sizeof(cache_obj_t *) * params->n_seg); - params->fifo_n_objs = (int64_t *)malloc(sizeof(int64_t) * params->n_seg); - params->fifo_n_bytes = (int64_t *)malloc(sizeof(int64_t) * params->n_seg); - - for (int i = 0; i < params->n_seg; i++) { - params->fifo_heads[i] = NULL; - params->fifo_tails[i] = NULL; - params->fifo_n_objs[i] = 0; - params->fifo_n_bytes[i] = 0; - } - - return cache; -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool SFIFO_get(cache_t *cache, const request_t *req) { -#ifdef DEBUG_MODE - return SFIFO_get_debug(cache, req); -#else - return cache_get_base(cache, req); -#endif -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *SFIFO_find(cache_t *cache, const request_t *req, - const bool update_cache) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - cache_obj_t *obj = hashtable_find(cache->hashtable, req); - - if (obj == NULL || !update_cache) { - return obj; - } - - obj->SFIFO.freq++; - SFIFO_promote_to_next_seg(cache, req, obj); - while (params->fifo_n_bytes[obj->SFIFO.fifo_id] > params->per_seg_max_size) { - SFIFO_cool(cache, req, obj->SFIFO.fifo_id); - } - - return obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -cache_obj_t *SFIFO_insert(cache_t *cache, const request_t *req) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - // Find the lowest fifo with space for insertion - int nth_seg = -1; - for (int i = 0; i < params->n_seg; i++) { - if (params->fifo_n_bytes[i] + req->obj_size + cache->obj_md_size <= - params->per_seg_max_size) { - nth_seg = i; - break; - } - } - - if (nth_seg == -1) { - // No space for insertion - while (cache->occupied_byte + req->obj_size + cache->obj_md_size > - cache->cache_size) { - cache->evict(cache, req); - } - nth_seg = 0; - } - - // cache_obj_t *obj = hashtable_insert(cache->hashtable, req); - cache_obj_t *obj = cache_insert_base(cache, req); - obj->SFIFO.freq = 0; - obj->SFIFO.fifo_id = nth_seg; - obj->SFIFO.last_access_vtime = cache->n_req; - - prepend_obj_to_head(¶ms->fifo_heads[nth_seg], - ¶ms->fifo_tails[nth_seg], obj); - params->fifo_n_bytes[nth_seg] += req->obj_size + cache->obj_md_size; - params->fifo_n_objs[nth_seg]++; - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *SFIFO_to_evict(cache_t *cache, const request_t *req) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - for (int i = 0; i < params->n_seg; i++) { - if (params->fifo_n_bytes[i] > 0) { - return params->fifo_tails[i]; - } - } -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void SFIFO_evict(cache_t *cache, const request_t *req) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - int nth_seg = -1; - for (int i = 0; i < params->n_seg; i++) { - if (params->fifo_tails[i] != NULL) { - nth_seg = i; - break; - } - } - - cache_obj_t *obj = params->fifo_tails[nth_seg]; - DEBUG_ASSERT(obj != NULL); - - params->fifo_n_bytes[nth_seg] -= obj->obj_size + cache->obj_md_size; - params->fifo_n_objs[nth_seg]--; - - remove_obj_from_list(¶ms->fifo_heads[nth_seg], - ¶ms->fifo_tails[nth_seg], obj); - cache_evict_base(cache, obj, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool SFIFO_remove(cache_t *cache, const obj_id_t obj_id) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - - if (obj == NULL) { - return false; - } - - cache->occupied_byte -= (obj->obj_size + cache->obj_md_size); - cache->n_obj -= 1; - remove_obj_from_list(&(params->fifo_heads[obj->SFIFO.fifo_id]), - &(params->fifo_tails[obj->SFIFO.fifo_id]), obj); - hashtable_delete(cache->hashtable, obj); - - return true; -} - -// *********************************************************************** -// **** **** -// **** setup functions **** -// **** **** -// *********************************************************************** -static const char *SFIFO_current_params(SFIFO_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "n-seg=%d\n", params->n_seg); - return params_str; -} - -static void SFIFO_parse_params(cache_t *cache, - const char *cache_specific_params) { - SFIFO_params_t *params = (SFIFO_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "n-seg") == 0) { - params->n_seg = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", SFIFO_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** internal functions **** -// **** **** -// *********************************************************************** -/* SFIFO cannot insert an object larger than segment size */ -bool SFIFO_can_insert(cache_t *cache, const request_t *req) { - SFIFO_params_t *params = (SFIFO_params_t *)cache->eviction_params; - bool can_insert = cache_can_insert_default(cache, req); - return can_insert && - (req->obj_size + cache->obj_md_size <= params->per_seg_max_size); -} - -/** - * @brief move an object from ith fifo into (i-1)th fifo, cool - * (i-1)th fifo if it is full, where the n_seg th fifo is the most recent - * - * @param cache - * @param i - */ -static void SFIFO_cool(cache_t *cache, const request_t *req, const int id) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - if (id == 0) return SFIFO_evict(cache, req); - - cache_obj_t *obj = params->fifo_tails[id]; - DEBUG_ASSERT(obj != NULL && obj->SFIFO.fifo_id == id); - remove_obj_from_list(¶ms->fifo_heads[id], ¶ms->fifo_tails[id], obj); - prepend_obj_to_head(¶ms->fifo_heads[id - 1], ¶ms->fifo_tails[id - 1], - obj); - obj->SFIFO.fifo_id = id - 1; - obj->SFIFO.freq = 0; - params->fifo_n_bytes[id] -= obj->obj_size; - params->fifo_n_objs[id]--; - params->fifo_n_bytes[id - 1] += obj->obj_size; - params->fifo_n_objs[id - 1]++; - - // If lower fifos are full - while (params->fifo_n_bytes[id - 1] > params->per_seg_max_size) { - SFIFO_cool(cache, req, id - 1); - } -} - -static void SFIFO_demote_to_prev_seg(cache_t *cache, const request_t *req, - cache_obj_t *obj) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - assert(obj->SFIFO.fifo_id > 0); - DEBUG_ASSERT(obj->SFIFO.freq == 0); - - int id = obj->SFIFO.fifo_id; - int new_id = id - 1; - remove_obj_from_list(¶ms->fifo_heads[id], ¶ms->fifo_tails[id], obj); - params->fifo_n_bytes[id] -= obj->obj_size; - params->fifo_n_bytes[new_id] += obj->obj_size; - - obj->SFIFO.fifo_id = new_id; - obj->SFIFO.freq = 0; - prepend_obj_to_head(¶ms->fifo_heads[new_id], ¶ms->fifo_tails[new_id], - obj); - params->fifo_n_objs[id]--; - params->fifo_n_objs[new_id]++; -} - -/** - * @brief promote the object from the current segment to the next (i+1) segment - */ -static void SFIFO_promote_to_next_seg(cache_t *cache, const request_t *req, - cache_obj_t *obj) { - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - if (obj->SFIFO.fifo_id == params->n_seg - 1) return; - - int id = obj->SFIFO.fifo_id; - remove_obj_from_list(¶ms->fifo_heads[id], ¶ms->fifo_tails[id], obj); - params->fifo_n_bytes[id] -= obj->obj_size + cache->obj_md_size; - params->fifo_n_objs[id]--; - - obj->SFIFO.fifo_id += 1; - obj->SFIFO.freq = 0; - prepend_obj_to_head(¶ms->fifo_heads[id + 1], ¶ms->fifo_tails[id + 1], - obj); - params->fifo_n_bytes[id + 1] += obj->obj_size + cache->obj_md_size; - params->fifo_n_objs[id + 1]++; -} - -// *********************************************************************** -// **** **** -// **** debug functions **** -// **** **** -// *********************************************************************** -static void _SFIFO_verify_fifo_size(cache_t *cache) { - SFIFO_params_t *params = (SFIFO_params_t *)cache->eviction_params; - for (int i = 0; i < params->n_seg; i++) { - int64_t n_objs = 0; - int64_t n_bytes = 0; - cache_obj_t *obj = params->fifo_heads[i]; - while (obj != NULL) { - n_objs += 1; - n_bytes += obj->obj_size; - obj = obj->queue.next; - } - assert(n_objs == params->fifo_n_objs[i]); - assert(n_bytes == params->fifo_n_bytes[i]); - } -} - -bool SFIFO_get_debug(cache_t *cache, const request_t *req) { - cache->n_req += 1; - - SFIFO_params_t *params = (SFIFO_params_t *)(cache->eviction_params); - cache->last_request_metadata = "none"; - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - bool cache_hit = cache->find(cache, req, true) != NULL; - if (cache_hit) { - cache->last_request_metadata = "hit"; - } else { - cache->last_request_metadata = "miss"; - } - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - if (cache_hit) { - return cache_hit; - } - - if (cache->can_insert(cache, req) == false) { - return cache_hit; - } - - if (!cache_hit) { - while (cache->occupied_byte + req->obj_size + cache->obj_md_size > - cache->cache_size) { - cache->evict(cache, req); - } - - cache->insert(cache, req); - } - - DEBUG_PRINT_CACHE_STATE(cache, params, req); - - return cache_hit; -} - -#ifdef __cplusplus -extern "C" -} -#endif \ No newline at end of file diff --git a/libCacheSim/cache/eviction/fifo/SFIFOv0.c b/libCacheSim/cache/eviction/fifo/SFIFOv0.c deleted file mode 100644 index 2e55d86d..00000000 --- a/libCacheSim/cache/eviction/fifo/SFIFOv0.c +++ /dev/null @@ -1,474 +0,0 @@ -// -// segment FIFO -// -// cache hit promotes an object to the next FIFO -// no promotion if it is in the last FIFO -// cache miss inserts an object into the first FIFO -// if not use Belady, -// evict from the first FIFO -// else -// evict from one of the FIFOs based on distance to the next request -// -// -// we notice that adding belady is not helpful -// -// -// libCacheSim -// -// - -#include "../../dataStructure/hashtable/hashtable.h" -#include "../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct SFIFOv0_params { - cache_t **FIFOs; - int n_queues; - // a temporary request used to move object between FIFOs - request_t *req_local; -} SFIFOv0_params_t; - -// #define USE_BELADY -static const char *DEFAULT_CACHE_PARAMS = "n-queue=4"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void SFIFOv0_parse_params(cache_t *cache, - const char *cache_specific_params); -static void SFIFOv0_free(cache_t *cache); -static bool SFIFOv0_get(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFOv0_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *SFIFOv0_insert(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFOv0_to_evict(cache_t *cache, const request_t *req); -static void SFIFOv0_evict(cache_t *cache, const request_t *req); -static bool SFIFOv0_remove(cache_t *cache, const obj_id_t obj_id); -static void SFIFOv0_cool(cache_t *cache, const request_t *req, int i); - -/* SFIFOv0 cannot an object larger than segment size */ -static inline bool SFIFOv0_can_insert(cache_t *cache, const request_t *req); -static inline int64_t SFIFOv0_get_occupied_byte(const cache_t *cache); -static inline int64_t SFIFOv0_get_n_obj(const cache_t *cache); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *SFIFOv0_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("SFIFOv0", ccache_params); - cache->cache_init = SFIFOv0_init; - cache->cache_free = SFIFOv0_free; - cache->get = SFIFOv0_get; - cache->find = SFIFOv0_find; - cache->insert = SFIFOv0_insert; - cache->evict = SFIFOv0_evict; - cache->remove = SFIFOv0_remove; - cache->to_evict = SFIFOv0_to_evict; - cache->init_params = cache_specific_params; - cache->can_insert = SFIFOv0_can_insert; - cache->get_occupied_byte = SFIFOv0_get_occupied_byte; - cache->get_n_obj = SFIFOv0_get_n_obj; - - cache->obj_md_size = 0; - - cache->eviction_params = (SFIFOv0_params_t *)malloc(sizeof(SFIFOv0_params_t)); - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - - if (cache_specific_params != NULL) { - SFIFOv0_parse_params(cache, cache_specific_params); - } else { - SFIFOv0_parse_params(cache, DEFAULT_CACHE_PARAMS); - } - - params->FIFOs = (cache_t **)malloc(sizeof(cache_t *) * params->n_queues); - - common_cache_params_t ccache_params_local = ccache_params; - ccache_params_local.cache_size /= params->n_queues; - ccache_params_local.hashpower /= MIN(16, ccache_params_local.hashpower - 4); - for (int i = 0; i < params->n_queues; i++) { - params->FIFOs[i] = FIFO_init(ccache_params_local, NULL); - } - params->req_local = new_request(); - -#ifdef USE_BELADY - snprintf(cache->cache_name, 20, "SFIFOv0-%d-belady", params->n_queues); -#else - snprintf(cache->cache_name, 20, "SFIFOv0-%d", params->n_queues); -#endif - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void SFIFOv0_free(cache_t *cache) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - free_request(params->req_local); - for (int i = 0; i < params->n_queues; i++) - params->FIFOs[i]->cache_free(params->FIFOs[i]); - free(params->FIFOs); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool SFIFOv0_get(cache_t *cache, const request_t *req) { - bool found = cache_get_base(cache, req); - - return found; -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *SFIFOv0_find(cache_t *cache, const request_t *req, - const bool update_cache) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - - cache_obj_t *obj = NULL; - for (int i = 0; i < params->n_queues; i++) { - obj = params->FIFOs[i]->find(params->FIFOs[i], req, false); - bool cache_hit = obj != NULL; - - if (cache_hit) { - // bump object from lower segment to upper segment; - if (i != params->n_queues - 1) { - params->FIFOs[i]->remove(params->FIFOs[i], req->obj_id); - - // If the upper FIFO is full - cache_t *next_fifo = params->FIFOs[i + 1]; - while (next_fifo->get_occupied_byte(next_fifo) + req->obj_size + - cache->obj_md_size > - next_fifo->cache_size) - SFIFOv0_cool(cache, req, i + 1); - - cache_obj_t *new_obj = next_fifo->insert(next_fifo, req); - new_obj->misc.next_access_vtime = req->next_access_vtime; - } else { - obj->misc.next_access_vtime = req->next_access_vtime; - } - - return obj; - } - } - return NULL; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *SFIFOv0_insert(cache_t *cache, const request_t *req) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - - // Find the lowest FIFO with space for insertion - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - if (fifo->get_occupied_byte(fifo) + req->obj_size + cache->obj_md_size <= - fifo->cache_size) { - cache_obj_t *obj = fifo->insert(fifo, req); - obj->misc.next_access_vtime = req->next_access_vtime; - return obj; - } - } - - // If all FIFOs are filled, insert into the lowest FIFO. - cache_t *fifo = params->FIFOs[0]; - cache_obj_t *obj = fifo->insert(fifo, req); - obj->misc.next_access_vtime = req->next_access_vtime; - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *SFIFOv0_to_evict(cache_t *cache, const request_t *req) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); -#ifdef USE_BELADY - cache_obj_t *best_obj = NULL; - double best_obj_score = 0; - int best_obj_fifo_idx = 0; - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - cache_obj_t *obj = fifo->to_evict(fifo, req); - if (obj == NULL) continue; - if (best_obj == NULL || obj->next_access_vtime > best_obj_score) { - best_obj = obj; - best_obj_score = obj->next_access_vtime; - best_obj_fifo_idx = i; - } - - return best_obj; - } -#else - - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - if (fifo->get_occupied_byte(fifo) > 0) { - return fifo->to_evict(fifo, req); - } - } -#endif -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void SFIFOv0_evict(cache_t *cache, const request_t *req) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); -#ifdef USE_BELADY - cache_obj_t *best_obj = NULL; - double best_obj_score = 0; - int best_obj_fifo_idx = 0; - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - cache_obj_t *obj = fifo->to_evict(fifo, req); - if (obj == NULL) continue; - if (best_obj == NULL || obj->next_access_vtime > best_obj_score) { - best_obj = obj; - best_obj_score = obj->next_access_vtime; - best_obj_fifo_idx = i; - } - } - cache_t *fifo = params->FIFOs[best_obj_fifo_idx]; - fifo->evict(fifo, req); -#else - - int nth_seg_to_evict = 0; - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - if (fifo->get_occupied_byte(fifo) > 0) { - fifo->evict(fifo, req); - return; - } - } -#endif -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool SFIFOv0_remove(cache_t *cache, const obj_id_t obj_id) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - for (int i = 0; i < params->n_queues; i++) { - cache_t *fifo = params->FIFOs[i]; - if (fifo->remove(fifo, obj_id)) { - return true; - } - } - return false; -} - -/* SFIFOv0 cannot an object larger than segment size */ -static inline bool SFIFOv0_can_insert(cache_t *cache, const request_t *req) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)cache->eviction_params; - bool can_insert = cache_can_insert_default(cache, req); - return can_insert && - (req->obj_size + cache->obj_md_size <= params->FIFOs[0]->cache_size); -} - -static inline int64_t SFIFOv0_get_occupied_byte(const cache_t *cache) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)cache->eviction_params; - int64_t occupied_byte = 0; - for (int i = 0; i < params->n_queues; i++) { - occupied_byte += params->FIFOs[i]->occupied_byte; - } - return occupied_byte; -} - -static inline int64_t SFIFOv0_get_n_obj(const cache_t *cache) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)cache->eviction_params; - int64_t n_obj = 0; - for (int i = 0; i < params->n_queues; i++) { - n_obj += params->FIFOs[i]->n_obj; - } - return n_obj; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *SFIFOv0_current_params(SFIFOv0_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "n-queue=%d\n", params->n_queues); - return params_str; -} - -static void SFIFOv0_parse_params(cache_t *cache, - const char *cache_specific_params) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "n-queue") == 0) { - params->n_queues = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", SFIFOv0_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** cache internal functions **** -// **** **** -// *********************************************************************** -/** - * @brief move an object from ith FIFO into (i-1)th FIFO, cool - * (i-1)th FIFO if it is full - * - * @param cache - * @param i - */ -static void SFIFOv0_cool(cache_t *cache, const request_t *req, int i) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)(cache->eviction_params); - - cache_t *fifo = params->FIFOs[i]; - // the last FIFO is evict-only, do not move to a lower fifo - if (i == 0) { - fifo->evict(fifo, NULL); - return; - }; - - // the evicted object move to lower fifo - cache_obj_t *obj_evicted = fifo->to_evict(fifo, req); - copy_cache_obj_to_request(params->req_local, obj_evicted); - fifo->evict(fifo, NULL); - - // If lower FIFOs are full - cache_t *next_fifo = params->FIFOs[i - 1]; - int64_t required_size = - next_fifo->cache_size - params->req_local->obj_size - cache->obj_md_size; - while (next_fifo->get_occupied_byte(next_fifo) > required_size) { - SFIFOv0_cool(cache, req, i - 1); - } - - next_fifo->insert(next_fifo, params->req_local); -} - -// *********************************************************************** -// **** **** -// **** debug functions **** -// **** **** -// *********************************************************************** -static void SFIFOv0_print_cache(cache_t *cache) { - SFIFOv0_params_t *params = (SFIFOv0_params_t *)cache->eviction_params; - for (int i = params->n_queues - 1; i >= 0; i--) { - cache_obj_t *obj = - ((FIFO_params_t *)params->FIFOs[i]->eviction_params)->q_head; - while (obj) { - printf("%ld(%u)->", obj->obj_id, obj->obj_size); - obj = obj->queue.next; - } - printf(" | "); - } - printf("\n"); -} - -#ifdef __cplusplus -extern "C" -} -#endif diff --git a/libCacheSim/cache/eviction/priv/LRU_Prob.c b/libCacheSim/cache/eviction/priv/LRU_Prob.c deleted file mode 100644 index 1ee3bdb8..00000000 --- a/libCacheSim/cache/eviction/priv/LRU_Prob.c +++ /dev/null @@ -1,290 +0,0 @@ -// -// LRU with probabilistic promotion -// -// -// LRU_Prob.c -// libCacheSim -// -// Created by Juncheng on 12/4/18. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/cache.h" -#include "../../../utils/include/mymath.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct LRU_Prob_params { - cache_obj_t *q_head; - cache_obj_t *q_tail; - - double prob; - int threshold; -} LRU_Prob_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void LRU_Prob_parse_params(cache_t *cache, const char *cache_specific_params); -static void LRU_Prob_free(cache_t *cache); -static bool LRU_Prob_get(cache_t *cache, const request_t *req); -static cache_obj_t *LRU_Prob_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *LRU_Prob_insert(cache_t *cache, const request_t *req); -static cache_obj_t *LRU_Prob_to_evict(cache_t *cache, const request_t *req); -static void LRU_Prob_evict(cache_t *cache, const request_t *req); -static bool LRU_Prob_remove(cache_t *cache, const obj_id_t obj_id); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *LRU_Prob_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("LRU_Prob", ccache_params); - cache->cache_init = LRU_Prob_init; - cache->cache_free = LRU_Prob_free; - cache->get = LRU_Prob_get; - cache->find = LRU_Prob_find; - cache->insert = LRU_Prob_insert; - cache->evict = LRU_Prob_evict; - cache->remove = LRU_Prob_remove; - cache->to_evict = LRU_Prob_to_evict; - cache->init_params = cache_specific_params; - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 8 * 2; - } else { - cache->obj_md_size = 0; - } - - cache->eviction_params = - (LRU_Prob_params_t *)malloc(sizeof(LRU_Prob_params_t)); - LRU_Prob_params_t *params = (LRU_Prob_params_t *)(cache->eviction_params); - params->prob = 0.5; - - if (cache_specific_params != NULL) { - LRU_Prob_parse_params(cache, cache_specific_params); - } - - params->threshold = (int)1.0 / params->prob; - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "LRU_Prob_%lf", - params->prob); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void LRU_Prob_free(cache_t *cache) { - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool LRU_Prob_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t* LRU_Prob_find(cache_t *cache, const request_t *req, - const bool update_cache) { - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - - cache_obj_t *cached_obj = cache_find_base(cache, req, update_cache); - if (cached_obj != NULL && likely(update_cache)) { - cached_obj->misc.freq += 1; - cached_obj->misc.next_access_vtime = req->next_access_vtime; - - if (next_rand() % params->threshold == 0) { - move_obj_to_head(¶ms->q_head, ¶ms->q_tail, cached_obj); - } - } - - return cached_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *LRU_Prob_insert(cache_t *cache, const request_t *req) { - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - cache_obj_t *obj = cache_insert_base(cache, req); - prepend_obj_to_head(¶ms->q_head, ¶ms->q_tail, obj); - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *LRU_Prob_to_evict(cache_t *cache, const request_t *req) { - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - cache_obj_t *obj_to_evict = params->q_tail; - return obj_to_evict; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void LRU_Prob_evict(cache_t *cache, const request_t *req) { - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - cache_obj_t *obj_to_evict = params->q_tail; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj_to_evict); - cache_remove_obj_base(cache, obj_to_evict, true); -} - -static void LRU_Prob_remove_obj(cache_t *cache, cache_obj_t *obj_to_remove) { - DEBUG_ASSERT(obj_to_remove != NULL); - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj_to_remove); - cache_remove_obj_base(cache, obj_to_remove, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool LRU_Prob_remove(cache_t *cache, const obj_id_t obj_id) { - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - - LRU_Prob_remove_obj(cache, obj); - - return true; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *LRU_Prob_current_params(LRU_Prob_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "prob=%.4lf\n", params->prob); - return params_str; -} - -static void LRU_Prob_parse_params(cache_t *cache, - const char *cache_specific_params) { - LRU_Prob_params_t *params = (LRU_Prob_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "prob") == 0) { - params->prob = (double)strtof(value, &end); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", LRU_Prob_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/MClock.c b/libCacheSim/cache/eviction/priv/MClock.c deleted file mode 100644 index 6894d959..00000000 --- a/libCacheSim/cache/eviction/priv/MClock.c +++ /dev/null @@ -1,483 +0,0 @@ -// -// multi handed clock -// there are m hands, each points to i/m position of the clock -// there is no action on hit, -// on miss, one of the hands is selected to evict based on next access distance -// (Belady) then the hands are reset to correponding positions -// -// -// mClock.c -// libCacheSim -// -// Created by Juncheng on 12/4/18. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_obj_t *q_head; - cache_obj_t *q_tail; - cache_obj_t **hands; - int n_hands; - double *hand_pos; - int n_consider_obj; - - int last_eviction_hand; - - request_t *req_local; - -} MClock_params_t; - -static const char *DEFAULT_PARAMS = - "hand-pos=0:0.25:0.50:0.75:1.0,n-consider-obj=1"; -// static const char *DEFAULT_PARAMS = -// "hand-pos=0:0.10:0.20:0.30:0.40:0.50:0.60:0.70:0.80:0.90:1.0"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void MClock_parse_params(cache_t *cache, - const char *cache_specific_params); -static void MClock_free(cache_t *cache); -static bool MClock_get(cache_t *cache, const request_t *req); -static cache_obj_t *MClock_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *MClock_insert(cache_t *cache, const request_t *req); -static cache_obj_t *MClock_to_evict(cache_t *cache, const request_t *req); -static void MClock_evict(cache_t *cache, const request_t *req); -static bool MClock_remove(cache_t *cache, const obj_id_t obj_id); -static int64_t MClock_get_occupied_byte(const cache_t *cache); -static int64_t MClock_get_n_obj(const cache_t *cache); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *MClock_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("MClock", ccache_params); - cache->cache_init = MClock_init; - cache->cache_free = MClock_free; - cache->get = MClock_get; - cache->find = MClock_find; - cache->insert = MClock_insert; - cache->evict = MClock_evict; - cache->remove = MClock_remove; - cache->to_evict = MClock_to_evict; - cache->get_occupied_byte = MClock_get_occupied_byte; - cache->get_n_obj = MClock_get_n_obj; - cache->can_insert = cache_can_insert_default; - - cache->init_params = cache_specific_params; - cache->obj_md_size = 0; - - cache->eviction_params = malloc(sizeof(MClock_params_t)); - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - params->q_head = NULL; - params->q_tail = NULL; - - params->req_local = new_request(); - - // we must parse the default params because the user specified params - // may not have hand-pos and the hand_pos array will not be initialized - MClock_parse_params(cache, DEFAULT_PARAMS); - if (cache_specific_params != NULL) { - MClock_parse_params(cache, cache_specific_params); - } - - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "MClock-%d-%d", - params->n_hands, params->n_consider_obj); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void MClock_free(cache_t *cache) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - free(params->hands); - free(params->hand_pos); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -bool MClock_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *MClock_find(cache_t *cache, const request_t *req, - const bool update_cache) { - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - - return cache_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *MClock_insert(cache_t *cache, const request_t *req) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - cache_obj_t *obj = cache_insert_base(cache, req); - prepend_obj_to_head(¶ms->q_head, ¶ms->q_tail, obj); - - if (params->hands[0] != NULL) { - for (int i = 0; i < params->last_eviction_hand; i++) { - params->hands[i] = params->hands[i]->queue.prev; - } - if (params->last_eviction_hand == params->n_hands - 1) { - params->hands[params->last_eviction_hand] = params->q_tail; - } else { - params->hands[params->last_eviction_hand] = - params->hands[params->last_eviction_hand]->queue.prev; - } - assert(params->hands[0] != NULL); - assert(params->hands[0] == params->q_head); - } - - return obj; -} - -static void reset_hands(cache_t *cache) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - cache_obj_t *obj = params->q_head; - int hand_idx = 0; - int64_t obj_idx = 0; - while (obj != NULL) { - if (obj_idx >= params->hand_pos[hand_idx] * cache->n_obj) { - params->hands[hand_idx++] = obj; - } - obj = obj->queue.next; - obj_idx++; - } - if (params->hand_pos[params->n_hands - 1] == 1) { - params->hands[hand_idx++] = params->q_tail; - } - assert(hand_idx == params->n_hands); -} - -static void print_curr_hand_pos(cache_t *cache) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - cache_obj_t *obj = params->q_head; - int hand_idx = 0; - int64_t obj_idx = 0; - while (obj != NULL) { - if (obj == params->hands[hand_idx]) { - printf("hand %d: %ld %p %p %p\n", hand_idx, obj_idx, obj, obj->queue.prev, - obj->queue.next); - hand_idx++; - } - obj = obj->queue.next; - obj_idx++; - } -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *MClock_to_evict(cache_t *cache, const request_t *req) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - int best_obj_pos = 0; - cache_obj_t *best_obj = params->hands[0]; - double best_obj_benefit = best_obj->misc.next_access_vtime; - for (int i = 0; i < params->n_hands; i++) { - if (params->hands[i]->misc.next_access_vtime > best_obj_benefit) { - best_obj_pos = i; - best_obj = params->hands[i]; - best_obj_benefit = best_obj->misc.next_access_vtime; - } - } - - cache->to_evict_candidate_gen_vtime = cache->n_req; - cache->to_evict_candidate = best_obj; - assert(false); - return best_obj; -} - -static double calc_candidate_score1(cache_t *cache, cache_obj_t *obj) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - double score = 0; - int n_score = 0; - cache_obj_t *curr_obj = obj; - - for (int i = 0; i < params->n_consider_obj; i++) { - if (curr_obj == NULL) { - break; - } - score += 1.0 / (curr_obj->misc.next_access_vtime - cache->n_req); - n_score++; - curr_obj = curr_obj->queue.prev; - } - - if (n_score > 0) score = n_score / score; - return score; -} - -static double calc_candidate_score(cache_t *cache, cache_obj_t *obj) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - double score = 0; - int n_score = 0; - cache_obj_t *curr_obj = obj; - - for (int i = 0; i < params->n_consider_obj; i++) { - if (curr_obj == NULL) { - break; - } - score += 1.0 / (curr_obj->misc.next_access_vtime - cache->n_req); - n_score++; - curr_obj = curr_obj->queue.prev; - } - - if (n_score > 0) score = n_score / score; - return score; -} -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void MClock_evict(cache_t *cache, const request_t *req) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - static __thread int n_reset_hand = 0; - if (params->hands[0] == NULL) { - n_reset_hand++; - assert(n_reset_hand < 2); - reset_hands(cache); - } - - int best_obj_pos = params->n_hands - 1; - cache_obj_t *best_obj = params->hands[params->n_hands - 1]; - double score = calc_candidate_score(cache, best_obj); - double best_score = score; - - /* 0.0 is the head (most recently inserted), - * 1.0 is the tail (least recently inserted) */ - for (int i = params->n_hands - 1; i >= 0; i--) { - score = calc_candidate_score(cache, params->hands[i]); - if (score > best_score) { - best_obj_pos = i; - best_obj = params->hands[i]; - best_score = score; - } - } - - - // static __thread int *n_choice_per_hand; - // static __thread int n_evictions = 0; - // if (n_choice_per_hand == NULL) { - // n_choice_per_hand = (int *)malloc(sizeof(int) * params->n_hands); - // memset(n_choice_per_hand, 0, sizeof(int) * params->n_hands); - // } - // n_choice_per_hand[best_obj_pos]++; - // if (++n_evictions % 1000 == 0) { - // for (int i = 0; i < params->n_hands; i++) { - // printf("%d ", n_choice_per_hand[i]); - // n_choice_per_hand[i] = 0; - // } - // printf("\n"); - // } - - params->last_eviction_hand = best_obj_pos; - params->hands[best_obj_pos] = best_obj->queue.next; - DEBUG_ASSERT(best_obj_pos == params->n_hands - 1 || - best_obj->queue.next != NULL); - - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, best_obj); - cache_evict_base(cache, best_obj, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool MClock_remove(cache_t *cache, const obj_id_t obj_id) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - - // need to update hands - assert(false); - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj); - cache_remove_obj_base(cache, obj, true); - - return true; -} - -static int64_t MClock_get_occupied_byte(const cache_t *cache) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - int64_t occupied_byte = cache->occupied_byte; - return occupied_byte; -} - -static int64_t MClock_get_n_obj(const cache_t *cache) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - int64_t n_obj = cache->n_obj; - return n_obj; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *MClock_current_params(cache_t *cache, - MClock_params_t *params) { - static __thread char params_str[128]; - int n = snprintf(params_str, 128, "hand-pos=%.2lf", (params->hand_pos[0])); - - for (int i = 1; i < params->n_hands; i++) { - n += snprintf(params_str + n, 128 - n, ":%.2lf", (params->hand_pos[i])); - } - - snprintf(cache->cache_name + n, 128 - n, "\n"); - - return params_str; -} - -static void MClock_parse_params(cache_t *cache, - const char *cache_specific_params) { - MClock_params_t *params = (MClock_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "hand-pos") == 0) { - int n_hands = 0; -#define MClock_MAX_N_HAND 16 - double hand_pos[MClock_MAX_N_HAND]; - char *v = strsep((char **)&value, ":"); - while (v != NULL) { - hand_pos[n_hands++] = strtod(v, &end); - v = strsep((char **)&value, ":"); - } - params->n_hands = n_hands; - if (params->hands != NULL) { - free(params->hands); - } - if (params->hand_pos != NULL) { - free(params->hand_pos); - } - params->hands = calloc(params->n_hands, sizeof(cache_obj_t *)); - params->hand_pos = calloc(params->n_hands, sizeof(double)); - for (int i = 0; i < n_hands; i++) { - params->hand_pos[i] = hand_pos[i]; - } - assert(hand_pos[0] == 0); - assert(hand_pos[n_hands - 1] == 1); - } else if (strcasecmp(key, "n-consider-obj") == 0) { - params->n_consider_obj = (int)strtol(value, &end, 10); - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", MClock_current_params(cache, params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/MyClock.c b/libCacheSim/cache/eviction/priv/MyClock.c deleted file mode 100644 index 51da33e2..00000000 --- a/libCacheSim/cache/eviction/priv/MyClock.c +++ /dev/null @@ -1,293 +0,0 @@ - - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/cache.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_obj_t *q_head; - cache_obj_t *q_tail; - - cache_obj_t *pointer; - int64_t n_scanned_obj; - int64_t n_written_obj; - double wrap_around_ratio; -} MyClock_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void MyClock_parse_params(cache_t *cache, - const char *cache_specific_params); -static void MyClock_free(cache_t *cache); -static bool MyClock_get(cache_t *cache, const request_t *req); -static cache_obj_t *MyClock_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *MyClock_insert(cache_t *cache, const request_t *req); -static cache_obj_t *MyClock_to_evict(cache_t *cache, const request_t *req); -static void MyClock_evict(cache_t *cache, const request_t *req); -static bool MyClock_remove(cache_t *cache, const obj_id_t obj_id); - -static void MyClock_verify(cache_t *cache); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** - -/** - * @brief initialize cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *MyClock_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("MyClock", ccache_params); - cache->cache_init = MyClock_init; - cache->cache_free = MyClock_free; - cache->get = MyClock_get; - cache->find = MyClock_find; - cache->insert = MyClock_insert; - cache->evict = MyClock_evict; - cache->remove = MyClock_remove; - cache->to_evict = MyClock_to_evict; - cache->init_params = cache_specific_params; - - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 1; - } else { - cache->obj_md_size = 0; - } - - if (cache_specific_params != NULL) { - ERROR("Clock does not support any parameters, but got %s\n", - cache_specific_params); - abort(); - } - - cache->eviction_params = my_malloc(MyClock_params_t); - MyClock_params_t *params = (MyClock_params_t *)cache->eviction_params; - params->pointer = NULL; - params->q_head = NULL; - params->q_tail = NULL; - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void MyClock_free(cache_t *cache) { - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ - -static bool MyClock_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *MyClock_find(cache_t *cache, const request_t *req, - const bool update_cache) { - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - if (cache_obj != NULL && update_cache) { - cache_obj->clock.visited = true; - } - - return cache_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *MyClock_insert(cache_t *cache, const request_t *req) { - MyClock_params_t *params = cache->eviction_params; - cache_obj_t *obj = cache_insert_base(cache, req); - prepend_obj_to_head(¶ms->q_head, ¶ms->q_tail, obj); - obj->clock.visited = false; - params->n_written_obj++; - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *MyClock_to_evict(cache_t *cache, const request_t *req) { - MyClock_params_t *params = cache->eviction_params; - cache_obj_t *pointer = params->pointer; - - /* if we have run one full around or first eviction */ - if (pointer == NULL) pointer = params->q_tail; - - /* find the first untouched */ - while (pointer != NULL && pointer->clock.visited) { - pointer = pointer->queue.prev; - } - - /* if we have finished one around, start from the tail */ - if (pointer == NULL) { - pointer = params->q_tail; - while (pointer != NULL && pointer->clock.visited) { - pointer = pointer->queue.prev; - } - } - - return pointer; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void MyClock_evict(cache_t *cache, const request_t *req) { - MyClock_params_t *params = cache->eviction_params; - cache_obj_t *obj = params->pointer; - - /* if we have run one full around or first eviction */ - if (obj == NULL) obj = params->q_tail; - - /* find the first untouched */ - while (obj != NULL && obj->clock.visited) { - params->n_scanned_obj++; - obj->clock.visited = false; - obj = obj->queue.prev; - } - - /* if we have finished one around, start from the tail */ - if (obj == NULL) { - obj = params->q_tail; - while (obj != NULL && obj->clock.visited) { - params->n_scanned_obj++; - obj->clock.visited = false; - obj = obj->queue.prev; - } - } - - params->n_scanned_obj++; - params->pointer = obj->queue.prev; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj); - cache_evict_base(cache, obj, true); -} - -static void MyClock_remove_obj(cache_t *cache, cache_obj_t *obj_to_remove) { - DEBUG_ASSERT(obj_to_remove != NULL); - MyClock_params_t *params = cache->eviction_params; - if (obj_to_remove == params->pointer) { - params->pointer = obj_to_remove->queue.prev; - } - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj_to_remove); - cache_remove_obj_base(cache, obj_to_remove, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool MyClock_remove(cache_t *cache, const obj_id_t obj_id) { - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - - MyClock_remove_obj(cache, obj); - - return true; -} - - -static void MyClock_verify(cache_t *cache) { - MyClock_params_t *params = cache->eviction_params; - int64_t n_obj = 0, n_byte = 0; - cache_obj_t *obj = params->q_head; - - while (obj != NULL) { - assert(hashtable_find_obj_id(cache->hashtable, obj->obj_id) != NULL); - n_obj++; - n_byte += obj->obj_size; - obj = obj->queue.next; - } - - assert(n_obj == cache->get_n_obj(cache)); - assert(n_byte == cache->get_occupied_byte(cache)); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/QDLP.c b/libCacheSim/cache/eviction/priv/QDLP.c deleted file mode 100644 index cbc69581..00000000 --- a/libCacheSim/cache/eviction/priv/QDLP.c +++ /dev/null @@ -1,514 +0,0 @@ -/** - * @file QDLP.c - * @brief Implementation of QDLP eviction algorithm - * QDLP: lazy promotion and quick demotion - * it uses a probationary FIFO queue with a myclock cache - * objects are first inserted into the FIFO queue, and moved to the clock cache - * when evicting from the FIFO queue if it has been accessed - * if the cache is full, evict from the FIFO cache - * if the clock cache is full, then promoting to clock will trigger an eviction - * from the clock cache (not insert into the FIFO queue) - */ - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/cache.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// #define DEBUG_MODE - -// *********************************************************************** // -// **** debug macro **** // -#ifdef DEBUG_MODE -#define PRINT_CACHE_STATE(cache, params) \ - printf("cache size %ld + %ld + %ld, %ld %ld \t", params->n_fifo_byte, \ - params->n_fifo_ghost_byte, params->n_clock_byte, \ - cache->occupied_size, cache->cache_size); \ - // j -#define DEBUG_PRINT(FMT, ...) \ - do { \ - PRINT_CACHE_STATE(cache, params); \ - printf(FMT, ##__VA_ARGS__); \ - printf("%s", NORMAL); \ - fflush(stdout); \ - } while (0) - -#else -#define DEBUG_PRINT(FMT, ...) -#endif -// *********************************************************************** // - -typedef struct { - cache_obj_t *fifo_head; - cache_obj_t *fifo_tail; - - cache_obj_t *fifo_ghost_head; - cache_obj_t *fifo_ghost_tail; - - cache_obj_t *clock_head; - cache_obj_t *clock_tail; - int64_t n_fifo_obj; - int64_t n_fifo_byte; - int64_t n_fifo_ghost_obj; - int64_t n_fifo_ghost_byte; - int64_t n_clock_obj; - int64_t n_clock_byte; - // the user specified size - double fifo_ratio; - int64_t fifo_size; - int64_t clock_size; - int64_t fifo_ghost_size; - cache_obj_t *clock_pointer; - int64_t vtime_last_check_is_ghost; - - bool lazy_promotion; -} QDLP_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void QDLP_parse_params(cache_t *cache, - const char *cache_specific_params); -static void QDLP_free(cache_t *cache); -static bool QDLP_get(cache_t *cache, const request_t *req); -static cache_obj_t *QDLP_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *QDLP_insert(cache_t *cache, const request_t *req); -static cache_obj_t *QDLP_to_evict(cache_t *cache, const request_t *req); -static void QDLP_evict(cache_t *cache, const request_t *req); -static bool QDLP_remove(cache_t *cache, const obj_id_t obj_id); - -/* internal functions */ -static void QDLP_remove_obj(cache_t *cache, cache_obj_t *obj_to_remove); - -static void QDLP_clock_evict(cache_t *cache, const request_t *req); -static void QDLP_parse_params(cache_t *cache, - const char *cache_specific_params); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** -/** - * @brief initialize a QDLP cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params QDLP specific parameters, should be NULL - */ -cache_t *QDLP_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("QDLP", ccache_params); - cache->cache_init = QDLP_init; - cache->cache_free = QDLP_free; - cache->get = QDLP_get; - cache->find = QDLP_find; - cache->insert = QDLP_insert; - cache->evict = QDLP_evict; - cache->remove = QDLP_remove; - cache->to_evict = QDLP_to_evict; - cache->init_params = cache_specific_params; - - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 1; - } else { - cache->obj_md_size = 0; - } - - cache->eviction_params = my_malloc(QDLP_params_t); - QDLP_params_t *params = (QDLP_params_t *)cache->eviction_params; - memset(cache->eviction_params, 0, sizeof(QDLP_params_t)); - params->clock_pointer = NULL; - params->fifo_ratio = 0.2; - params->lazy_promotion = true; - - params->n_fifo_obj = 0; - params->n_fifo_byte = 0; - params->n_fifo_ghost_obj = 0; - params->n_fifo_ghost_byte = 0; - params->n_clock_obj = 0; - params->n_clock_byte = 0; - params->fifo_head = NULL; - params->fifo_tail = NULL; - params->clock_head = NULL; - params->clock_tail = NULL; - params->fifo_ghost_head = NULL; - params->fifo_ghost_tail = NULL; - params->vtime_last_check_is_ghost = -1; - - if (cache_specific_params != NULL) { - QDLP_parse_params(cache, cache_specific_params); - } - - params->fifo_size = cache->cache_size * params->fifo_ratio; - params->clock_size = cache->cache_size - params->fifo_size; - params->fifo_ghost_size = params->clock_size; - if (params->lazy_promotion) { - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "QDLP-%.4lf-lazy", - params->fifo_ratio); - } else { - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "QDLP-%.4lf", - params->fifo_ratio); - } - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void QDLP_free(cache_t *cache) { - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool QDLP_get(cache_t *cache, const request_t *req) { - QDLP_params_t *params = cache->eviction_params; - bool cache_hit = cache_get_base(cache, req); - DEBUG_PRINT("%ld QDLP_get2\n", cache->n_req); - DEBUG_ASSERT(params->n_fifo_obj + params->n_clock_obj == cache->n_obj); - DEBUG_ASSERT(params->n_fifo_byte + params->n_clock_byte == - cache->occupied_byte); - - return cache_hit; -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief check whether an object is in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return true on hit, false on miss - */ -static cache_obj_t *QDLP_find(cache_t *cache, const request_t *req, - const bool update_cache) { - QDLP_params_t *params = cache->eviction_params; - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - cache_obj_t *ret = cache_obj; - bool cache_hit = (cache_obj != NULL && cache_obj->QDLP.cache_id != 3); - DEBUG_PRINT("%ld QDLP_find %s\n", cache->n_req, cache_hit ? "hit" : "miss"); - - if (cache_obj != NULL && update_cache) { - if (cache_obj->QDLP.cache_id == 1) { - cache_obj->QDLP.freq += 1; - if (!params->lazy_promotion) { - /* FIFO cache, promote to clock cache */ - remove_obj_from_list(¶ms->fifo_head, ¶ms->fifo_tail, cache_obj); - params->n_fifo_obj--; - params->n_fifo_byte -= cache_obj->obj_size + cache->obj_md_size; - prepend_obj_to_head(¶ms->clock_head, ¶ms->clock_tail, - cache_obj); - params->n_clock_obj++; - params->n_clock_byte += cache_obj->obj_size + cache->obj_md_size; - cache_obj->QDLP.cache_id = 2; - cache_obj->QDLP.freq = 0; - while (params->n_clock_byte > params->clock_size) { - // clock cache is full, evict from clock cache - QDLP_clock_evict(cache, req); - } - } - } else if (cache_obj->QDLP.cache_id == 2) { - // clock cache - DEBUG_PRINT("%ld QDLP_find hit on clock\n", cache->n_req); - if (cache_obj->QDLP.freq < 1) { - // using one-bit, using multi-bit reduce miss ratio most of the time - cache_obj->QDLP.freq += 1; - } - } else if (cache_obj->QDLP.cache_id == 3) { - // FIFO ghost - DEBUG_PRINT("%ld QDLP_check ghost\n", cache->n_req); - DEBUG_ASSERT(cache_hit == false); - params->vtime_last_check_is_ghost = cache->n_req; - QDLP_remove_obj(cache, cache_obj); - } else { - ERROR("cache_obj->QDLP.cache_id = %d", cache_obj->QDLP.cache_id); - } - } - - if (cache_hit) - return ret; - else - return NULL; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * and eviction is not part of this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *QDLP_insert(cache_t *cache, const request_t *req) { - QDLP_params_t *params = cache->eviction_params; - - cache_obj_t *obj = cache_insert_base(cache, req); - obj->QDLP.visited = false; - - if (cache->n_req == params->vtime_last_check_is_ghost) { - // insert to Clock - DEBUG_PRINT("%ld QDLP_insert to clock\n", cache->n_req); - prepend_obj_to_head(¶ms->clock_head, ¶ms->clock_tail, obj); - params->n_clock_obj++; - params->n_clock_byte += obj->obj_size + cache->obj_md_size; - obj->QDLP.cache_id = 2; - obj->QDLP.freq = 0; - - } else { - // insert to FIFO - DEBUG_PRINT("%ld QDLP_insert to fifo\n", cache->n_req); - prepend_obj_to_head(¶ms->fifo_head, ¶ms->fifo_tail, obj); - params->n_fifo_obj++; - params->n_fifo_byte += obj->obj_size + cache->obj_md_size; - obj->QDLP.cache_id = 1; - obj->QDLP.freq = 0; - } - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *QDLP_to_evict(cache_t *cache, const request_t *req) { - QDLP_params_t *params = cache->eviction_params; - if (params->fifo_tail != NULL) { - return params->fifo_tail; - } else { - // not implemented, we need to evict from the clock cache - assert(0); - } -} - -/** - * @brief evict an object from the clock - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void QDLP_clock_evict(cache_t *cache, const request_t *reqj) { - QDLP_params_t *params = cache->eviction_params; - cache_obj_t *pointer = params->clock_pointer; - - /* if we have run one full around or first eviction */ - if (pointer == NULL) { - pointer = params->clock_tail; - } - - /* find the first untouched */ - int n_loop = 0; - while (pointer->QDLP.freq > 0) { - pointer->QDLP.freq -= 1; - pointer = pointer->queue.prev; - if (pointer == NULL) { - n_loop += 1; - pointer = params->clock_tail; - assert(n_loop < 1000); - } - } - - params->clock_pointer = pointer->queue.prev; - remove_obj_from_list(¶ms->clock_head, ¶ms->clock_tail, pointer); - params->n_clock_obj--; - params->n_clock_byte -= pointer->obj_size + cache->obj_md_size; - cache_evict_base(cache, pointer, true); -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void QDLP_evict(cache_t *cache, const request_t *req) { - QDLP_params_t *params = cache->eviction_params; - - if (params->n_fifo_byte > params->fifo_size || params->n_clock_obj == 0) { - DEBUG_PRINT("%ld QDLP_evict_fifo\n", cache->n_req); - cache_obj_t *obj_to_evict = params->fifo_tail; - DEBUG_ASSERT(obj_to_evict != NULL); - - // remove from FIFO - remove_obj_from_list(¶ms->fifo_head, ¶ms->fifo_tail, obj_to_evict); - params->n_fifo_obj--; - params->n_fifo_byte -= obj_to_evict->obj_size + cache->obj_md_size; - - if (params->lazy_promotion && obj_to_evict->QDLP.freq > 0) { - prepend_obj_to_head(¶ms->clock_head, ¶ms->clock_tail, - obj_to_evict); - params->n_clock_obj++; - params->n_clock_byte += obj_to_evict->obj_size + cache->obj_md_size; - obj_to_evict->QDLP.cache_id = 2; - obj_to_evict->QDLP.freq = 0; - while (params->n_clock_byte > params->clock_size) { - // clock cache is full, evict from clock cache - QDLP_clock_evict(cache, req); - } - } else { - cache_evict_base(cache, obj_to_evict, false); - prepend_obj_to_head(¶ms->fifo_ghost_head, ¶ms->fifo_ghost_tail, - obj_to_evict); - params->n_fifo_ghost_obj++; - params->n_fifo_ghost_byte += obj_to_evict->obj_size + cache->obj_md_size; - obj_to_evict->QDLP.cache_id = 3; - while (params->n_fifo_ghost_byte > params->fifo_ghost_size) { - // clock cache is full, evict from clock cache - QDLP_remove_obj(cache, params->fifo_ghost_tail); - } - } - } else { - DEBUG_PRINT("%ld QDLP_evict_clock\n", cache->n_req); - // evict from clock cache, this can happen because we insert to the clock - // when the object hit on the ghost - QDLP_clock_evict(cache, req); - } -} - -static void QDLP_remove_obj(cache_t *cache, cache_obj_t *obj_to_remove) { - DEBUG_ASSERT(obj_to_remove != NULL); - QDLP_params_t *params = cache->eviction_params; - - if (obj_to_remove->QDLP.cache_id == 1) { - // fifo cache - remove_obj_from_list(¶ms->fifo_head, ¶ms->fifo_tail, obj_to_remove); - params->n_fifo_obj--; - params->n_fifo_byte -= obj_to_remove->obj_size + cache->obj_md_size; - cache_remove_obj_base(cache, obj_to_remove, true); - } else if (obj_to_remove->QDLP.cache_id == 2) { - // clock cache - remove_obj_from_list(¶ms->clock_head, ¶ms->clock_tail, - obj_to_remove); - params->n_clock_obj--; - params->n_clock_byte -= obj_to_remove->obj_size + cache->obj_md_size; - cache_remove_obj_base(cache, obj_to_remove, true); - } else if (obj_to_remove->QDLP.cache_id == 3) { - // fifo ghost - remove_obj_from_list(¶ms->fifo_ghost_head, ¶ms->fifo_ghost_tail, - obj_to_remove); - params->n_fifo_ghost_obj--; - params->n_fifo_ghost_byte -= obj_to_remove->obj_size + cache->obj_md_size; - hashtable_delete(cache->hashtable, obj_to_remove); - } -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool QDLP_remove(cache_t *cache, const obj_id_t obj_id) { - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - QDLP_remove_obj(cache, obj); - - return true; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *QDLP_current_params(QDLP_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "fifo-ratio=%.4lf\n", params->fifo_ratio); - return params_str; -} - -static void QDLP_parse_params(cache_t *cache, - const char *cache_specific_params) { - QDLP_params_t *params = (QDLP_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "fifo-ratio") == 0) { - params->fifo_ratio = (double)strtof(value, &end); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", QDLP_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/QDLPv1.c b/libCacheSim/cache/eviction/priv/QDLPv1.c deleted file mode 100644 index e7905de8..00000000 --- a/libCacheSim/cache/eviction/priv/QDLPv1.c +++ /dev/null @@ -1,413 +0,0 @@ -// -// Quick demotion + lazy promoition v1 -// -// 20% FIFO + ARC -// insert to ARC when evicting from FIFO -// -// -// QDLPv1.c -// libCacheSim -// -// Created by Juncheng on 12/4/18. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_t *fifo; - cache_t *fifo_ghost; - cache_t *main_cache; - bool hit_on_ghost; - - double fifo_size_ratio; - char main_cache_type[32]; - - request_t *req_local; -} QDLPv1_params_t; - -static const char *DEFAULT_CACHE_PARAMS = "fifo-size-ratio=0.2,main-cache=ARC"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** -cache_t *QDLPv1_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); -static void QDLPv1_free(cache_t *cache); -static bool QDLPv1_get(cache_t *cache, const request_t *req); - -static cache_obj_t *QDLPv1_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *QDLPv1_insert(cache_t *cache, const request_t *req); -static cache_obj_t *QDLPv1_to_evict(cache_t *cache, const request_t *req); -static void QDLPv1_evict(cache_t *cache, const request_t *req); -static bool QDLPv1_remove(cache_t *cache, const obj_id_t obj_id); -static inline int64_t QDLPv1_get_occupied_byte(const cache_t *cache); -static inline int64_t QDLPv1_get_n_obj(const cache_t *cache); -static inline bool QDLPv1_can_insert(cache_t *cache, const request_t *req); -static void QDLPv1_parse_params(cache_t *cache, - const char *cache_specific_params); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** - -cache_t *QDLPv1_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("QDLPv1", ccache_params); - cache->cache_init = QDLPv1_init; - cache->cache_free = QDLPv1_free; - cache->get = QDLPv1_get; - cache->find = QDLPv1_find; - cache->insert = QDLPv1_insert; - cache->evict = QDLPv1_evict; - cache->remove = QDLPv1_remove; - cache->to_evict = QDLPv1_to_evict; - cache->init_params = cache_specific_params; - cache->get_n_obj = QDLPv1_get_n_obj; - cache->get_occupied_byte = QDLPv1_get_occupied_byte; - cache->can_insert = QDLPv1_can_insert; - - cache->obj_md_size = 0; - - cache->eviction_params = malloc(sizeof(QDLPv1_params_t)); - memset(cache->eviction_params, 0, sizeof(QDLPv1_params_t)); - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - params->req_local = new_request(); - params->hit_on_ghost = false; - - QDLPv1_parse_params(cache, DEFAULT_CACHE_PARAMS); - if (cache_specific_params != NULL) { - QDLPv1_parse_params(cache, cache_specific_params); - } - - int64_t fifo_cache_size = - (int64_t)ccache_params.cache_size * params->fifo_size_ratio; - int64_t main_cache_size = ccache_params.cache_size - fifo_cache_size; - int64_t fifo_ghost_cache_size = main_cache_size; - - common_cache_params_t ccache_params_local = ccache_params; - ccache_params_local.cache_size = fifo_cache_size; - params->fifo = FIFO_init(ccache_params_local, NULL); - - ccache_params_local.cache_size = fifo_ghost_cache_size; - params->fifo_ghost = FIFO_init(ccache_params_local, NULL); - snprintf(params->fifo_ghost->cache_name, CACHE_NAME_ARRAY_LEN, "FIFO-ghost"); -#if defined(TRACK_EVICTION_R_AGE) || defined(TRACK_EVICTION_V_AGE) - params->fifo_ghost->track_eviction_age = false; -#endif - - ccache_params_local.cache_size = main_cache_size; - if (strcasecmp(params->main_cache_type, "ARC") == 0) { - params->main_cache = ARC_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LHD") == 0) { - params->main_cache = LHD_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "clock") == 0) { - params->main_cache = Clock_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "clock-2") == 0) { - params->main_cache = Clock_init(ccache_params_local, "n-bit-counter=2"); - } else if (strcasecmp(params->main_cache_type, "clock-3") == 0) { - params->main_cache = Clock_init(ccache_params_local, "n-bit-counter=3"); - } else if (strcasecmp(params->main_cache_type, "myclock") == 0) { - params->main_cache = MyClock_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LRU") == 0) { - params->main_cache = LRU_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LeCaR") == 0) { - params->main_cache = LeCaR_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "Cacheus") == 0) { - params->main_cache = Cacheus_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "twoQ") == 0) { - params->main_cache = TwoQ_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "FIFO") == 0) { - params->main_cache = FIFO_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LIRS") == 0) { - params->main_cache = LIRS_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "Hyperbolic") == 0) { - params->main_cache = Hyperbolic_init(ccache_params_local, NULL); - } else { - ERROR("QDLPv1 does not support %s \n", params->main_cache_type); - } - - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "QDLPv1-%.2lf-ghost-%s", - params->fifo_size_ratio, params->main_cache_type); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void QDLPv1_free(cache_t *cache) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - free_request(params->req_local); - params->fifo->cache_free(params->fifo); - params->fifo_ghost->cache_free(params->fifo_ghost); - params->main_cache->cache_free(params->main_cache); - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool QDLPv1_get(cache_t *cache, const request_t *req) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - DEBUG_ASSERT(params->fifo->get_occupied_byte(params->fifo) + - params->main_cache->get_occupied_byte(params->main_cache) <= - cache->cache_size); - bool cache_hit = cache_get_base(cache, req); - return cache_hit; -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *QDLPv1_find(cache_t *cache, const request_t *req, - const bool update_cache) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - - // if update cache is false, we only check the fifo and main caches - if (!update_cache) { - cache_obj_t *obj = params->fifo->find(params->fifo, req, false); - if (obj != NULL) { - return obj; - } - obj = params->main_cache->find(params->main_cache, req, false); - if (obj != NULL) { - return obj; - } - return NULL; - } - - /* update cache is true from now */ - params->hit_on_ghost = false; - cache_obj_t *obj = params->fifo->find(params->fifo, req, false); - if (obj != NULL) { - obj->misc.freq = 1; - - return obj; - } - - if (params->fifo_ghost->remove(params->fifo_ghost, req->obj_id)) { - // if object in fifo_ghost, remove will return true - params->hit_on_ghost = true; - } - - obj = params->main_cache->find(params->main_cache, req, update_cache); - - return obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *QDLPv1_insert(cache_t *cache, const request_t *req) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - cache_obj_t *obj = NULL; - - if (params->hit_on_ghost) { - /* insert into the ARC */ - params->hit_on_ghost = false; - params->main_cache->get(params->main_cache, req); - } else { - /* insert into the fifo */ - obj = params->fifo->insert(params->fifo, req); - } - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *QDLPv1_to_evict(cache_t *cache, const request_t *req) { - assert(false); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void QDLPv1_evict(cache_t *cache, const request_t *req) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - - cache_t *fifo = params->fifo; - cache_t *ghost = params->fifo_ghost; - cache_t *main = params->main_cache; - - if (fifo->get_occupied_byte(fifo) == 0) { - assert(main->get_occupied_byte(main) > main->cache_size); - assert(main->get_occupied_byte(main) <= cache->cache_size); - // evict from main cache - main->evict(main, req); - return; - } - - // evict from FIFO - cache_obj_t *obj = fifo->to_evict(fifo, req); - assert(obj != NULL); - // need to copy the object before it is evicted - copy_cache_obj_to_request(params->req_local, obj); - // remove from fifo1, but do not update stat - fifo->evict(fifo, req); - - if (obj->misc.freq > 0) { - // promote to main cache - // get will insert to and evict from main cache - params->main_cache->get(params->main_cache, params->req_local); - } else { - // insert to ghost - ghost->get(ghost, params->req_local); - } -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool QDLPv1_remove(cache_t *cache, const obj_id_t obj_id) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - bool removed = false; - removed = removed || params->fifo->remove(params->fifo, obj_id); - removed = removed || params->fifo_ghost->remove(params->fifo_ghost, obj_id); - removed = removed || params->main_cache->remove(params->main_cache, obj_id); - - return removed; -} - -static inline int64_t QDLPv1_get_occupied_byte(const cache_t *cache) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - return params->fifo->get_occupied_byte(params->fifo) + - params->main_cache->get_occupied_byte(params->main_cache); -} - -static inline int64_t QDLPv1_get_n_obj(const cache_t *cache) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - return params->fifo->get_n_obj(params->fifo) + - params->main_cache->get_n_obj(params->main_cache); -} - -static inline bool QDLPv1_can_insert(cache_t *cache, const request_t *req) { - QDLPv1_params_t *params = (QDLPv1_params_t *)cache->eviction_params; - - return req->obj_size <= params->fifo->cache_size; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *QDLPv1_current_params(QDLPv1_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "fifo-size-ratio=%.4lf,main-cache=%s\n", - params->fifo_size_ratio, params->main_cache->cache_name); - return params_str; -} - -static void QDLPv1_parse_params(cache_t *cache, - const char *cache_specific_params) { - QDLPv1_params_t *params = (QDLPv1_params_t *)(cache->eviction_params); - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "fifo-size-ratio") == 0) { - params->fifo_size_ratio = strtod(value, NULL); - } else if (strcasecmp(key, "main-cache") == 0) { - strncpy(params->main_cache_type, value, 30); - } else if (strcasecmp(key, "print") == 0) { - printf("parameters: %s\n", QDLPv1_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/QDLPv2.c b/libCacheSim/cache/eviction/priv/QDLPv2.c deleted file mode 100644 index 27e61d3c..00000000 --- a/libCacheSim/cache/eviction/priv/QDLPv2.c +++ /dev/null @@ -1,485 +0,0 @@ -// -// Quick demotion + lazy promoition v2 -// -// FIFO + Clock -// the ratio of FIFO is decided dynamically -// based on the marginal hits on FIFO-ghost and main cache -// we track the hit distribution of FIFO-ghost and main cache -// if the hit distribution of FIFO-ghost at pos 0 is larger than -// the hit distribution of main cache at pos -1, -// we increase FIFO size by 1 -// -// -// QDLPv2.c -// libCacheSim -// -// Created by Juncheng on 1/24/23 -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_t *fifo; - cache_t *fifo_ghost; - cache_t *main_cache; - bool hit_on_ghost; - - double fifo_size_ratio; - char main_cache_type[32]; - - cache_t *fifo_eviction; - cache_t *main_cache_eviction; - int32_t fifo_eviction_hit; - int32_t main_eviction_hit; - - request_t *req_local; -} QDLPv2_params_t; - -static const char *DEFAULT_CACHE_PARAMS = - "fifo-size-ratio=0.2,main-cache=Clock-2"; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** -cache_t *QDLPv2_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); -static void QDLPv2_free(cache_t *cache); -static bool QDLPv2_get(cache_t *cache, const request_t *req); - -static cache_obj_t *QDLPv2_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *QDLPv2_insert(cache_t *cache, const request_t *req); -static cache_obj_t *QDLPv2_to_evict(cache_t *cache, const request_t *req); -static void QDLPv2_evict(cache_t *cache, const request_t *req); -static bool QDLPv2_remove(cache_t *cache, const obj_id_t obj_id); -static inline int64_t QDLPv2_get_occupied_byte(const cache_t *cache); -static inline int64_t QDLPv2_get_n_obj(const cache_t *cache); -static inline bool QDLPv2_can_insert(cache_t *cache, const request_t *req); -static void QDLPv2_parse_params(cache_t *cache, - const char *cache_specific_params); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** - -cache_t *QDLPv2_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("QDLPv2", ccache_params); - cache->cache_init = QDLPv2_init; - cache->cache_free = QDLPv2_free; - cache->get = QDLPv2_get; - cache->find = QDLPv2_find; - cache->insert = QDLPv2_insert; - cache->evict = QDLPv2_evict; - cache->remove = QDLPv2_remove; - cache->to_evict = QDLPv2_to_evict; - cache->init_params = cache_specific_params; - cache->get_n_obj = QDLPv2_get_n_obj; - cache->get_occupied_byte = QDLPv2_get_occupied_byte; - cache->can_insert = QDLPv2_can_insert; - - cache->obj_md_size = 0; - - cache->eviction_params = malloc(sizeof(QDLPv2_params_t)); - memset(cache->eviction_params, 0, sizeof(QDLPv2_params_t)); - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - params->req_local = new_request(); - params->hit_on_ghost = false; - - QDLPv2_parse_params(cache, DEFAULT_CACHE_PARAMS); - if (cache_specific_params != NULL) { - QDLPv2_parse_params(cache, cache_specific_params); - } - - int64_t fifo_cache_size = - (int64_t)ccache_params.cache_size * params->fifo_size_ratio; - int64_t main_cache_size = ccache_params.cache_size - fifo_cache_size; - int64_t fifo_ghost_cache_size = main_cache_size; - - common_cache_params_t ccache_params_local = ccache_params; - ccache_params_local.cache_size = fifo_cache_size; - params->fifo = FIFO_init(ccache_params_local, NULL); - - ccache_params_local.cache_size = fifo_ghost_cache_size; - params->fifo_ghost = FIFO_init(ccache_params_local, NULL); - snprintf(params->fifo_ghost->cache_name, CACHE_NAME_ARRAY_LEN, "FIFO-ghost"); -#if defined(TRACK_EVICTION_R_AGE) || defined(TRACK_EVICTION_V_AGE) - params->fifo_ghost->track_eviction_age = false; -#endif - - ccache_params_local.cache_size = main_cache_size; - if (strcasecmp(params->main_cache_type, "FIFO") == 0) { - params->main_cache = FIFO_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "clock") == 0) { - params->main_cache = Clock_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "clock-2") == 0) { - params->main_cache = Clock_init(ccache_params_local, "n-bit-counter=2"); - } else if (strcasecmp(params->main_cache_type, "clock-3") == 0) { - params->main_cache = Clock_init(ccache_params_local, "n-bit-counter=3"); - } else if (strcasecmp(params->main_cache_type, "myclock") == 0) { - params->main_cache = MyClock_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LRU") == 0) { - params->main_cache = LRU_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "ARC") == 0) { - params->main_cache = ARC_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LHD") == 0) { - params->main_cache = LHD_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LeCaR") == 0) { - params->main_cache = LeCaR_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "Cacheus") == 0) { - params->main_cache = Cacheus_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "twoQ") == 0) { - params->main_cache = TwoQ_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "LIRS") == 0) { - params->main_cache = LIRS_init(ccache_params_local, NULL); - } else if (strcasecmp(params->main_cache_type, "Hyperbolic") == 0) { - params->main_cache = Hyperbolic_init(ccache_params_local, NULL); - } else { - ERROR("QDLPv2 does not support %s \n", params->main_cache_type); - } - - ccache_params_local.cache_size = ccache_params.cache_size / 10; - ccache_params_local.hashpower -= 4; - // ccache_params_local.cache_size = 100; - params->fifo_eviction = FIFO_init(ccache_params_local, NULL); - params->main_cache_eviction = FIFO_init(ccache_params_local, NULL); - - snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "QDLPv2-%.2lf-ghost-%s", - params->fifo_size_ratio, params->main_cache_type); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void QDLPv2_free(cache_t *cache) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - free_request(params->req_local); - params->fifo->cache_free(params->fifo); - params->fifo_ghost->cache_free(params->fifo_ghost); - params->main_cache->cache_free(params->main_cache); - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool QDLPv2_get(cache_t *cache, const request_t *req) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - DEBUG_ASSERT(params->fifo->get_occupied_byte(params->fifo) + - params->main_cache->get_occupied_byte(params->main_cache) <= - cache->cache_size); - - static __thread int64_t last_print_rtime = 0; - static __thread int last_change_direction = 0; - if (cache->n_req % 1000 == 0) { - // if (cache->n_req % 1000 == 0) { - // if (req->clock_time - last_print_rtime >= 60) { - // printf("%ld: %d %d %ld %ld\n", cache->n_req, params->fifo_eviction_hit, - // params->main_eviction_hit, params->fifo->cache_size, - // params->main_cache->cache_size); - // last_print_rtime = req->clock_time; - // } - - if (params->fifo_eviction_hit > params->main_eviction_hit * 1.2) { - if (params->main_cache->cache_size > 20) { - params->fifo->cache_size += 20; - params->main_cache->cache_size -= 20; - } - last_change_direction = 1; - } else if (params->main_eviction_hit > params->fifo_eviction_hit * 1.2) { - if (params->fifo->cache_size > 20) { - params->fifo->cache_size -= 20; - params->main_cache->cache_size += 20; - } - last_change_direction = 2; - } - params->fifo_eviction_hit = params->fifo_eviction_hit * 0.8; - params->main_eviction_hit = params->main_eviction_hit * 0.8; - } - - bool cache_hit = cache_get_base(cache, req); - return cache_hit; -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *QDLPv2_find(cache_t *cache, const request_t *req, - const bool update_cache) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - - // if update cache is false, we only check the fifo and main caches - if (!update_cache) { - cache_obj_t *obj = params->fifo->find(params->fifo, req, false); - if (obj != NULL) { - return obj; - } - obj = params->main_cache->find(params->main_cache, req, false); - if (obj != NULL) { - return obj; - } - return NULL; - } - - /* update cache is true from now */ - params->hit_on_ghost = false; - cache_obj_t *obj = params->fifo->find(params->fifo, req, false); - if (obj != NULL) { - // we can use misc field because FIFO does not use any metadata - obj->misc.freq = 1; - - return obj; - } - - if (params->fifo_ghost->remove(params->fifo_ghost, req->obj_id)) { - params->hit_on_ghost = true; - } - - obj = params->main_cache->find(params->main_cache, req, update_cache); - - if (params->fifo_eviction->find(params->fifo_eviction, req, false) != NULL) { - params->fifo_eviction->remove(params->fifo_eviction, req->obj_id); - params->fifo_eviction_hit++; - } - - if (params->main_cache_eviction->find(params->main_cache_eviction, req, - false) != NULL) { - params->main_cache_eviction->remove(params->main_cache_eviction, - req->obj_id); - params->main_eviction_hit++; - } - - return obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *QDLPv2_insert(cache_t *cache, const request_t *req) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - cache_obj_t *obj = NULL; - - if (params->hit_on_ghost) { - /* insert into the ARC */ - params->hit_on_ghost = false; - obj = params->main_cache->insert(params->main_cache, req); - } else { - /* insert into the fifo */ - obj = params->fifo->insert(params->fifo, req); - obj->misc.freq = 0; - } - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *QDLPv2_to_evict(cache_t *cache, const request_t *req) { - assert(false); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void QDLPv2_evict(cache_t *cache, const request_t *req) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - - cache_t *fifo = params->fifo; - cache_t *ghost = params->fifo_ghost; - cache_t *main = params->main_cache; - - if (fifo->get_occupied_byte(fifo) == 0) { - assert(main->get_occupied_byte(main) > main->cache_size); - assert(main->get_occupied_byte(main) <= cache->cache_size); - // evict from main cache - cache_obj_t *obj = main->to_evict(main, req); - copy_cache_obj_to_request(params->req_local, obj); - params->main_cache_eviction->get(params->main_cache_eviction, - params->req_local); - main->evict(main, req); - return; - } - - // evict from FIFO - cache_obj_t *obj = fifo->to_evict(fifo, req); - assert(obj != NULL); - // need to copy the object before it is evicted - copy_cache_obj_to_request(params->req_local, obj); - // remove from fifo1, but do not update stat - fifo->evict(fifo, req); - - if (obj->misc.freq > 0) { - // promote to main cache - // get will insert to and evict from main cache - main->insert(main, params->req_local); - while (main->get_occupied_byte(main) > main->cache_size) { - // evict from main cache - cache_obj_t *obj = main->to_evict(main, req); - copy_cache_obj_to_request(params->req_local, obj); - params->main_cache_eviction->get(params->main_cache_eviction, - params->req_local); - main->evict(main, req); - } - } else { - // insert to ghost - ghost->get(ghost, params->req_local); - params->fifo_eviction->get(params->fifo_eviction, params->req_local); - } -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool QDLPv2_remove(cache_t *cache, const obj_id_t obj_id) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - bool removed = false; - removed = removed || params->fifo->remove(params->fifo, obj_id); - removed = removed || params->fifo_ghost->remove(params->fifo_ghost, obj_id); - removed = removed || params->main_cache->remove(params->main_cache, obj_id); - - return removed; -} - -static inline int64_t QDLPv2_get_occupied_byte(const cache_t *cache) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - return params->fifo->get_occupied_byte(params->fifo) + - params->main_cache->get_occupied_byte(params->main_cache); -} - -static inline int64_t QDLPv2_get_n_obj(const cache_t *cache) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - return params->fifo->get_n_obj(params->fifo) + - params->main_cache->get_n_obj(params->main_cache); -} - -static inline bool QDLPv2_can_insert(cache_t *cache, const request_t *req) { - QDLPv2_params_t *params = (QDLPv2_params_t *)cache->eviction_params; - - return req->obj_size <= params->fifo->cache_size; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *QDLPv2_current_params(QDLPv2_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "fifo-size-ratio=%.4lf,main-cache=%s\n", - params->fifo_size_ratio, params->main_cache->cache_name); - return params_str; -} - -static void QDLPv2_parse_params(cache_t *cache, - const char *cache_specific_params) { - QDLPv2_params_t *params = (QDLPv2_params_t *)(cache->eviction_params); - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "fifo-size-ratio") == 0) { - params->fifo_size_ratio = strtod(value, NULL); - } else if (strcasecmp(key, "main-cache") == 0) { - strncpy(params->main_cache_type, value, 30); - } else if (strcasecmp(key, "print") == 0) { - printf("parameters: %s\n", QDLPv2_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/SFIFO_Merge.c b/libCacheSim/cache/eviction/priv/SFIFO_Merge.c deleted file mode 100644 index bf263add..00000000 --- a/libCacheSim/cache/eviction/priv/SFIFO_Merge.c +++ /dev/null @@ -1,469 +0,0 @@ -// -// SFIFO_Merge scans N objects and retains M objects, evict the rest -// -// -// SFIFO_Merge.c -// libCacheSim -// -// Created by Juncheng on 12/20/21. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct sort_list_node { - double metric; - cache_obj_t *cache_obj; -}; - -typedef enum { - RETAIN_POLICY_RECENCY = 0, - RETAIN_POLICY_FREQUENCY, - RETAIN_POLICY_BELADY, - RETAIN_NONE -} retain_policy_t; - -static char *retain_policy_names[] = {"RECENCY", "FREQUENCY", "BELADY", "None"}; - -typedef struct SFIFO_Merge_params { - cache_obj_t *q_head; - cache_obj_t *q_tail; - - // points to the eviction position - cache_obj_t *next_to_exam; - // the number of object to examine at each eviction - int n_exam_obj; - // of the n_exam_obj, we evict n_evict_obj and evict the rest - int n_evict_obj; - // used to sort the n_exam_obj objects - struct sort_list_node *metric_list; - // the policy to determine the n_keep_obj objects - retain_policy_t retain_policy; - int pos_in_metric_list; -} SFIFO_Merge_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void SFIFO_Merge_parse_params(cache_t *cache, const char *cache_specific_params); -static void SFIFO_Merge_free(cache_t *cache); -static bool SFIFO_Merge_get(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFO_Merge_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *SFIFO_Merge_insert(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFO_Merge_to_evict(cache_t *cache, const request_t *req); -static void SFIFO_Merge_evict(cache_t *cache, const request_t *req); -static bool SFIFO_Merge_remove(cache_t *cache, const obj_id_t obj_id); - -/* internal functions */ -static inline int cmp_list_node(const void *a0, const void *b0); -static inline double belady_metric(cache_t *cache, cache_obj_t *cache_obj); -static inline double freq_metric(cache_t *cache, cache_obj_t *cache_obj); -static inline double recency_metric(cache_t *cache, cache_obj_t *cache_obj); -static double retain_metric(cache_t *cache, cache_obj_t *cache_obj); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *SFIFO_Merge_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("SFIFO_Merge", ccache_params); - cache->cache_init = SFIFO_Merge_init; - cache->cache_free = SFIFO_Merge_free; - cache->get = SFIFO_Merge_get; - cache->find = SFIFO_Merge_find; - cache->insert = SFIFO_Merge_insert; - cache->evict = SFIFO_Merge_evict; - cache->remove = SFIFO_Merge_remove; - cache->to_evict = SFIFO_Merge_to_evict; - cache->init_params = cache_specific_params; - - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 4; - } else { - cache->obj_md_size = 0; - } - - SFIFO_Merge_params_t *params = my_malloc(SFIFO_Merge_params_t); - memset(params, 0, sizeof(SFIFO_Merge_params_t)); - cache->eviction_params = params; - - /* TODO: can we make this parameter adaptive to trace? */ - params->n_exam_obj = 100; - params->n_evict_obj = params->n_exam_obj / 4; - params->retain_policy = RETAIN_POLICY_FREQUENCY; - params->next_to_exam = NULL; - params->pos_in_metric_list = INT32_MAX; - - if (cache_specific_params != NULL) { - SFIFO_Merge_parse_params(cache, cache_specific_params); - } - - assert(params->n_exam_obj > 0 && params->n_evict_obj >= 0); - assert(params->n_evict_obj <= params->n_exam_obj); - - snprintf(cache->cache_name, 32, "SFIFO_Merge_%s", - retain_policy_names[params->retain_policy]); - params->metric_list = my_malloc_n(struct sort_list_node, params->n_exam_obj); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void SFIFO_Merge_free(cache_t *cache) { - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - my_free(sizeof(struct sort_list_node) * params->n_exam_obj, - params->metric_list); - my_free(sizeof(SFIFO_Merge_params_t), params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool SFIFO_Merge_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *SFIFO_Merge_find(cache_t *cache, const request_t *req, - const bool update_cache) { - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - - if (cache_obj && update_cache) { - if (cache_obj->SFIFO_Merge.freq < 4) - cache_obj->SFIFO_Merge.freq++; - - cache_obj->SFIFO_Merge.last_access_vtime = cache->n_req; - cache_obj->misc.next_access_vtime = req->next_access_vtime; - } - - return cache_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *SFIFO_Merge_insert(cache_t *cache, const request_t *req) { - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - - cache_obj_t *cache_obj = cache_insert_base(cache, req); - prepend_obj_to_head(¶ms->q_head, ¶ms->q_tail, cache_obj); - cache_obj->SFIFO_Merge.freq = 0; - cache_obj->SFIFO_Merge.last_access_vtime = cache->n_req; - cache_obj->misc.next_access_vtime = req->next_access_vtime; - - return cache_obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *SFIFO_Merge_to_evict(cache_t *cache, const request_t *req) { - ERROR("Undefined! Multiple objs will be evicted\n"); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void SFIFO_Merge_evict(cache_t *cache, const request_t *req) { - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - cache_obj_t *cache_obj = NULL; - // the logic is that - we search for n_exam objects and identify n_exam - - // n_keep objects to evict, each time we evict one object - if (params->pos_in_metric_list < params->n_evict_obj) { - // there are objects identified to evict - cache_obj = params->metric_list[params->pos_in_metric_list++].cache_obj; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, cache_obj); - cache_evict_base(cache, cache_obj, true); - return; - } - - if (cache->n_obj <= params->n_exam_obj) { - // just evict one object - this is fifo - cache_obj_t *cache_obj = params->q_tail; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, cache_obj); - cache_evict_base(cache, cache_obj, true); - - return; - } - - // we need to exam n_exam objects - // collect metric for n_exam obj, we will keep objects with larger metric - int n_loop = 0; - cache_obj = params->next_to_exam; - for (int i = 0; i < params->n_exam_obj; i++) { - if (cache_obj == NULL) { - cache_obj = params->q_tail; - n_loop += 1; - assert(n_loop++ <= 2); - } - - // params->metric_list[i].metric = retain_metric(cache, cache_obj); - params->metric_list[i].metric = cache_obj->SFIFO_Merge.freq; - params->metric_list[i].cache_obj = cache_obj; - cache_obj = cache_obj->queue.prev; - } - params->next_to_exam = cache_obj; - - // sort metrics - qsort(params->metric_list, params->n_exam_obj, sizeof(struct sort_list_node), - cmp_list_node); - - params->n_evict_obj = 0; - for (int i = 0; i < params->n_exam_obj; i++) { - cache_obj = params->metric_list[i].cache_obj; - if (cache_obj->SFIFO_Merge.freq == 0) { - params->n_evict_obj += 1; - } - // cache_obj->SFIFO_Merge.freq = cache_obj->SFIFO_Merge.freq / 2; - cache_obj->SFIFO_Merge.freq = cache_obj->SFIFO_Merge.freq - 1; - // cache_obj->SFIFO_Merge.freq = 0; - } - - // printf("cache size %ld: evict %d/%d object\n", cache->cache_size, - // params->n_evict_obj, params->n_exam_obj); - - // remove objects - params->pos_in_metric_list = 1; - cache_obj = params->metric_list[0].cache_obj; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, cache_obj); - cache_evict_base(cache, cache_obj, true); -} - -static void SFIFO_Merge_remove_obj(cache_t *cache, cache_obj_t *obj_to_remove) { - assert(obj_to_remove != NULL); - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj_to_remove); - cache_remove_obj_base(cache, obj_to_remove, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -bool SFIFO_Merge_remove(cache_t *cache, const obj_id_t obj_id) { - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - - SFIFO_Merge_remove_obj(cache, obj); - - return true; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *SFIFO_Merge_current_params(SFIFO_Merge_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "n-exam=%d, n-evict=%d, retain-policy=%s", - params->n_exam_obj, params->n_evict_obj, - retain_policy_names[params->retain_policy]); - return params_str; -} - -static void SFIFO_Merge_parse_params(cache_t *cache, - const char *cache_specific_params) { - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - if (strcasecmp(key, "retain-policy") == 0) { - if (strcasecmp(value, "freq") == 0 || strcasecmp(value, "frequency") == 0) - params->retain_policy = RETAIN_POLICY_FREQUENCY; - else if (strcasecmp(value, "recency") == 0) - params->retain_policy = RETAIN_POLICY_RECENCY; - else if (strcasecmp(value, "belady") == 0 || - strcasecmp(value, "optimal") == 0) - params->retain_policy = RETAIN_POLICY_BELADY; - else if (strcasecmp(value, "none") == 0) { - params->retain_policy = RETAIN_NONE; - params->n_evict_obj = params->n_exam_obj; - } else { - ERROR("unknown retain-policy %s\n", value); - exit(1); - } - } else if (strcasecmp(key, "n-exam") == 0) { - params->n_exam_obj = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "n-evict") == 0) { - params->n_evict_obj = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "print") == 0) { - printf("%s parameters: %s\n", cache->cache_name, - SFIFO_Merge_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** cache internal functions **** -// **** **** -// *********************************************************************** -static inline int cmp_list_node(const void *a0, const void *b0) { - struct sort_list_node *a = (struct sort_list_node *)a0; - struct sort_list_node *b = (struct sort_list_node *)b0; - - if (a->metric > b->metric) { - return 1; - } else if (a->metric < b->metric) { - return -1; - } else { - return 0; - } -} - -static inline double belady_metric(cache_t *cache, cache_obj_t *cache_obj) { - if (cache_obj->misc.next_access_vtime == -1 || - cache_obj->misc.next_access_vtime == INT64_MAX) - return -1; - return 1.0e12 / (cache_obj->misc.next_access_vtime - cache->n_req) / - (double)cache_obj->obj_size; -} - -static inline double freq_metric(cache_t *cache, cache_obj_t *cache_obj) { - /* we add a small rand number to distinguish objects with frequency 0 or same - * frequency */ - double r = (double)(next_rand() % 1000) / 10000.0; - return 1.0e6 * ((double)cache_obj->SFIFO_Merge.freq + r) / - (double)cache_obj->obj_size; -} - -static inline double recency_metric(cache_t *cache, cache_obj_t *cache_obj) { - return 1.0e12 / - (double)(cache->n_req - cache_obj->SFIFO_Merge.last_access_vtime) / - (double)cache_obj->obj_size; -} - -static double retain_metric(cache_t *cache, cache_obj_t *cache_obj) { - SFIFO_Merge_params_t *params = (SFIFO_Merge_params_t *)cache->eviction_params; - - switch (params->retain_policy) { - case RETAIN_POLICY_FREQUENCY: - return freq_metric(cache, cache_obj); - case RETAIN_POLICY_RECENCY: - return recency_metric(cache, cache_obj); - case RETAIN_POLICY_BELADY: - return belady_metric(cache, cache_obj); - default: - break; - } -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/SFIFO_Reinsertion.c b/libCacheSim/cache/eviction/priv/SFIFO_Reinsertion.c deleted file mode 100644 index e9216ac5..00000000 --- a/libCacheSim/cache/eviction/priv/SFIFO_Reinsertion.c +++ /dev/null @@ -1,473 +0,0 @@ -// -// SFIFO_Reinsertion scans N objects and retains M objects, evict the rest -// -// -// SFIFO_Reinsertion.c -// libCacheSim -// -// Created by Juncheng on 12/20/21. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct sort_list_node { - double metric; - cache_obj_t *cache_obj; -}; - -typedef enum { - RETAIN_POLICY_RECENCY = 0, - RETAIN_POLICY_FREQUENCY, - RETAIN_POLICY_BELADY, - RETAIN_NONE -} retain_policy_t; - -static char *retain_policy_names[] = {"RECENCY", "FREQUENCY", "BELADY", "None"}; - -typedef struct SFIFO_Reinsertion_params { - cache_obj_t *q_head; - cache_obj_t *q_tail; - - // points to the eviction position - cache_obj_t *next_to_merge; - // the number of object to examine at each eviction - int n_exam_obj; - // of the n_exam_obj, we keep n_keep_obj and evict the rest - int n_keep_obj; - // used to sort the n_exam_obj objects - struct sort_list_node *metric_list; - // the policy to determine the n_keep_obj objects - retain_policy_t retain_policy; -} SFIFO_Reinsertion_params_t; - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void SFIFO_Reinsertion_parse_params(cache_t *cache, - const char *cache_specific_params); -static void SFIFO_Reinsertion_free(cache_t *cache); -static bool SFIFO_Reinsertion_get(cache_t *cache, const request_t *req); -static cache_obj_t *SFIFO_Reinsertion_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *SFIFO_Reinsertion_insert(cache_t *cache, - const request_t *req); -static cache_obj_t *SFIFO_Reinsertion_to_evict(cache_t *cache, - const request_t *req); -static void SFIFO_Reinsertion_evict(cache_t *cache, const request_t *req); -static void SFIFO_Reinsertion_remove_obj(cache_t *cache, cache_obj_t *obj); -static bool SFIFO_Reinsertion_remove(cache_t *cache, const obj_id_t obj_id); - -/* internal functions */ -static inline int cmp_list_node(const void *a0, const void *b0); -static inline double belady_metric(cache_t *cache, cache_obj_t *cache_obj); -static inline double freq_metric(cache_t *cache, cache_obj_t *cache_obj); -static inline double recency_metric(cache_t *cache, cache_obj_t *cache_obj); -static double retain_metric(cache_t *cache, cache_obj_t *cache_obj); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// **** init, free, get **** -// *********************************************************************** - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *SFIFO_Reinsertion_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("SFIFO_Reinsertion", ccache_params); - cache->cache_init = SFIFO_Reinsertion_init; - cache->cache_free = SFIFO_Reinsertion_free; - cache->get = SFIFO_Reinsertion_get; - cache->find = SFIFO_Reinsertion_find; - cache->insert = SFIFO_Reinsertion_insert; - cache->evict = SFIFO_Reinsertion_evict; - cache->remove = SFIFO_Reinsertion_remove; - cache->to_evict = SFIFO_Reinsertion_to_evict; - cache->init_params = cache_specific_params; - - if (ccache_params.consider_obj_metadata) { - cache->obj_md_size = 4; - } else { - cache->obj_md_size = 0; - } - - SFIFO_Reinsertion_params_t *params = my_malloc(SFIFO_Reinsertion_params_t); - memset(params, 0, sizeof(SFIFO_Reinsertion_params_t)); - cache->eviction_params = params; - - params->n_exam_obj = 100; - params->n_keep_obj = params->n_exam_obj / 2; - params->retain_policy = RETAIN_POLICY_FREQUENCY; - params->next_to_merge = NULL; - params->q_head = NULL; - params->q_tail = NULL; - - if (cache_specific_params != NULL) { - SFIFO_Reinsertion_parse_params(cache, cache_specific_params); - } - - assert(params->n_exam_obj > 0 && params->n_keep_obj >= 0); - assert(params->n_keep_obj <= params->n_exam_obj); - - snprintf(cache->cache_name, 32, "SFIFO_Reinsertion_%s", - retain_policy_names[params->retain_policy]); - params->metric_list = my_malloc_n(struct sort_list_node, params->n_exam_obj); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void SFIFO_Reinsertion_free(cache_t *cache) { - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - my_free(sizeof(struct sort_list_node) * params->n_exam_obj, - params->metric_list); - my_free(sizeof(SFIFO_Reinsertion_params_t), params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -static bool SFIFO_Reinsertion_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** - -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *SFIFO_Reinsertion_find(cache_t *cache, const request_t *req, - const bool update_cache) { - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - - if (cache_obj && update_cache) { - cache_obj->SFIFO_Reinsertion.freq++; - cache_obj->SFIFO_Reinsertion.last_access_vtime = cache->n_req; - cache_obj->misc.next_access_vtime = req->next_access_vtime; - } - - return cache_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *SFIFO_Reinsertion_insert(cache_t *cache, - const request_t *req) { - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - - cache_obj_t *obj = cache_insert_base(cache, req); - prepend_obj_to_head(¶ms->q_head, ¶ms->q_tail, obj); - - obj->SFIFO_Reinsertion.freq = 0; - obj->SFIFO_Reinsertion.last_access_vtime = cache->n_req; - obj->misc.next_access_vtime = req->next_access_vtime; - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *SFIFO_Reinsertion_to_evict(cache_t *cache, - const request_t *req) { - ERROR("Undefined! Multiple objs will be evicted\n"); - abort(); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void SFIFO_Reinsertion_evict(cache_t *cache, const request_t *req) { - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - - // collect metric for n_exam obj, we will keep objects with larger metric - int n_loop = 0; - cache_obj_t *cache_obj = params->next_to_merge; - if (cache_obj == NULL) { - params->next_to_merge = params->q_tail; - cache_obj = params->q_tail; - n_loop = 1; - } - - if (cache->n_obj <= params->n_exam_obj) { - // just evict one object - cache_obj_t *cache_obj = params->next_to_merge->queue.prev; - SFIFO_Reinsertion_remove_obj(cache, params->next_to_merge); - params->next_to_merge = cache_obj; - - return; - } - - for (int i = 0; i < params->n_exam_obj; i++) { - assert(cache_obj != NULL); - params->metric_list[i].metric = retain_metric(cache, cache_obj); - params->metric_list[i].cache_obj = cache_obj; - cache_obj = cache_obj->queue.prev; - - // TODO: wrap back to the head of the list early before reaching the end of - // the list - if (cache_obj == NULL) { - cache_obj = params->q_tail; - DEBUG_ASSERT(n_loop++ <= 2); - } - } - params->next_to_merge = cache_obj; - - // sort metrics - qsort(params->metric_list, params->n_exam_obj, sizeof(struct sort_list_node), - cmp_list_node); - - // remove objects - int n_evict = params->n_exam_obj - params->n_keep_obj; - for (int i = 0; i < n_evict; i++) { - cache_obj = params->metric_list[i].cache_obj; - SFIFO_Reinsertion_remove_obj(cache, cache_obj); - } - - for (int i = n_evict; i < params->n_exam_obj; i++) { - cache_obj = params->metric_list[i].cache_obj; - move_obj_to_head(¶ms->q_head, ¶ms->q_tail, cache_obj); - cache_obj->SFIFO_Reinsertion.freq = - (cache_obj->SFIFO_Reinsertion.freq + 1) / 2; - } -} - -static void SFIFO_Reinsertion_remove_obj(cache_t *cache, cache_obj_t *obj) { - DEBUG_ASSERT(obj != NULL); - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - - remove_obj_from_list(¶ms->q_head, ¶ms->q_tail, obj); - cache_remove_obj_base(cache, obj, true); -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool SFIFO_Reinsertion_remove(cache_t *cache, const obj_id_t obj_id) { - cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id); - if (obj == NULL) { - return false; - } - - SFIFO_Reinsertion_remove_obj(cache, obj); - - return true; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *SFIFO_Reinsertion_current_params( - SFIFO_Reinsertion_params_t *params) { - static __thread char params_str[128]; - snprintf(params_str, 128, "n-exam=%d, n-keep=%d, retain-policy=%s", - params->n_exam_obj, params->n_keep_obj, - retain_policy_names[params->retain_policy]); - return params_str; -} - -static void SFIFO_Reinsertion_parse_params(cache_t *cache, - const char *cache_specific_params) { - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - if (strcasecmp(key, "retain-policy") == 0) { - if (strcasecmp(value, "freq") == 0 || strcasecmp(value, "frequency") == 0) - params->retain_policy = RETAIN_POLICY_FREQUENCY; - else if (strcasecmp(value, "recency") == 0) - params->retain_policy = RETAIN_POLICY_RECENCY; - else if (strcasecmp(value, "belady") == 0 || - strcasecmp(value, "optimal") == 0) - params->retain_policy = RETAIN_POLICY_BELADY; - else if (strcasecmp(value, "none") == 0) { - params->retain_policy = RETAIN_NONE; - params->n_keep_obj = 0; - } else { - ERROR("unknown retain-policy %s\n", value); - exit(1); - } - } else if (strcasecmp(key, "n-exam") == 0) { - params->n_exam_obj = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "n-keep") == 0) { - params->n_keep_obj = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "print") == 0) { - printf("%s parameters: %s\n", cache->cache_name, - SFIFO_Reinsertion_current_params(params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - - free(old_params_str); -} - -// *********************************************************************** -// **** **** -// **** cache internal functions **** -// **** **** -// *********************************************************************** -static inline int cmp_list_node(const void *a0, const void *b0) { - struct sort_list_node *a = (struct sort_list_node *)a0; - struct sort_list_node *b = (struct sort_list_node *)b0; - - if (a->metric > b->metric) { - return 1; - } else if (a->metric < b->metric) { - return -1; - } else { - return 0; - } -} - -static inline double belady_metric(cache_t *cache, cache_obj_t *cache_obj) { - if (cache_obj->misc.next_access_vtime == -1 || - cache_obj->misc.next_access_vtime == INT64_MAX) - return -1; - return 1.0e12 / (cache_obj->misc.next_access_vtime - cache->n_req) / - (double)cache_obj->obj_size; -} - -static inline double freq_metric(cache_t *cache, cache_obj_t *cache_obj) { - /* we add a small rand number to distinguish objects with frequency 0 or same - * frequency */ - double r = (double)(next_rand() % 1000) / 10000.0; - return 1.0e6 * ((double)cache_obj->SFIFO_Reinsertion.freq + r) / - (double)cache_obj->obj_size; -} - -static inline double recency_metric(cache_t *cache, cache_obj_t *cache_obj) { - return 1.0e12 / - (double)(cache->n_req - - cache_obj->SFIFO_Reinsertion.last_access_vtime) / - (double)cache_obj->obj_size; -} - -static double retain_metric(cache_t *cache, cache_obj_t *cache_obj) { - SFIFO_Reinsertion_params_t *params = - (SFIFO_Reinsertion_params_t *)cache->eviction_params; - - switch (params->retain_policy) { - case RETAIN_POLICY_FREQUENCY: - return freq_metric(cache, cache_obj); - case RETAIN_POLICY_RECENCY: - return recency_metric(cache, cache_obj); - case RETAIN_POLICY_BELADY: - return belady_metric(cache, cache_obj); - default: - break; - } -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/cache/eviction/priv/myMQv1.c b/libCacheSim/cache/eviction/priv/myMQv1.c deleted file mode 100644 index 0aa9de4b..00000000 --- a/libCacheSim/cache/eviction/priv/myMQv1.c +++ /dev/null @@ -1,376 +0,0 @@ -// -// multi queue -// each queue has a specified size and a specified ghost size -// promotion upon hit -// -// in progress, this is not finished -// -// -// myMQv1.c -// libCacheSim -// -// Created by Juncheng on 12/4/18. -// Copyright © 2018 Juncheng. All rights reserved. -// - -#include "../../../dataStructure/hashtable/hashtable.h" -#include "../../../include/libCacheSim/evictionAlgo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cache_t **caches; - cache_t **ghost_caches; - int64_t n_caches; - int64_t *cache_sizes; - int64_t *ghost_sizes; - - request_t *req_local; - -} myMQv1_params_t; - -static const char *DEFAULT_PARAMS = - "cache_sizes=0.25,0.25,0.25,0.25;ghost_sizes=0.75,0.75,0.75,0.75"; -#define myMQv1_MAX_N_cache 16 - -// *********************************************************************** -// **** **** -// **** function declarations **** -// **** **** -// *********************************************************************** - -static void myMQv1_parse_params(cache_t *cache, - const char *cache_specific_params); -static void myMQv1_free(cache_t *cache); -static bool myMQv1_get(cache_t *cache, const request_t *req); -static cache_obj_t *myMQv1_find(cache_t *cache, const request_t *req, - const bool update_cache); -static cache_obj_t *myMQv1_insert(cache_t *cache, const request_t *req); -static cache_obj_t *myMQv1_to_evict(cache_t *cache, const request_t *req); -static void myMQv1_evict(cache_t *cache, const request_t *req); -static bool myMQv1_remove(cache_t *cache, const obj_id_t obj_id); -static int64_t myMQv1_get_occupied_byte(const cache_t *cache); -static int64_t myMQv1_get_n_obj(const cache_t *cache); - -// *********************************************************************** -// **** **** -// **** end user facing functions **** -// **** **** -// *********************************************************************** - - -/** - * @brief initialize the cache - * - * @param ccache_params some common cache parameters - * @param cache_specific_params cache specific parameters, see parse_params - * function or use -e "print" with the cachesim binary - */ -cache_t *myMQv1_init(const common_cache_params_t ccache_params, - const char *cache_specific_params) { - cache_t *cache = cache_struct_init("myMQv1", ccache_params); - cache->cache_init = myMQv1_init; - cache->cache_free = myMQv1_free; - cache->get = myMQv1_get; - cache->find = myMQv1_find; - cache->insert = myMQv1_insert; - cache->evict = myMQv1_evict; - cache->remove = myMQv1_remove; - cache->to_evict = myMQv1_to_evict; - cache->get_occupied_byte = myMQv1_get_occupied_byte; - cache->get_n_obj = myMQv1_get_n_obj; - cache->can_insert = cache_can_insert_default; - - cache->init_params = cache_specific_params; - cache->obj_md_size = 0; - - cache->eviction_params = malloc(sizeof(myMQv1_params_t)); - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - params->req_local = new_request(); - - if (cache_specific_params != NULL) { - myMQv1_parse_params(cache, cache_specific_params); - } else { - myMQv1_parse_params(cache, DEFAULT_PARAMS); - } - - params->caches = malloc(sizeof(cache_t *) * params->n_caches); - params->ghost_caches = malloc(sizeof(cache_t *) * params->n_caches); - common_cache_params_t ccache_params_local = ccache_params; - for (int i = 0; i < params->n_caches; i++) { - ccache_params_local.cache_size = params->cache_sizes[i]; - params->caches[i] = FIFO_init(ccache_params, NULL); - params->ghost_caches[i] = FIFO_init(ccache_params_local, NULL); - } - - // snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "myMQv1", 0.25); - - return cache; -} - -/** - * free resources used by this cache - * - * @param cache - */ -static void myMQv1_free(cache_t *cache) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - for (int i = 0; i < params->n_caches; i++) { - params->caches[i]->cache_free(params->caches[i]); - params->ghost_caches[i]->cache_free(params->ghost_caches[i]); - } - free(params->caches); - free(params->ghost_caches); - free(params->cache_sizes); - free(cache->eviction_params); - cache_struct_free(cache); -} - -/** - * @brief this function is the user facing API - * it performs the following logic - * - * ``` - * if obj in cache: - * update_metadata - * return true - * else: - * if cache does not have enough space: - * evict until it has space to insert - * insert the object - * return false - * ``` - * - * @param cache - * @param req - * @return true if cache hit, false if cache miss - */ -bool myMQv1_get(cache_t *cache, const request_t *req) { - return cache_get_base(cache, req); -} - -// *********************************************************************** -// **** **** -// **** developer facing APIs (used by cache developer) **** -// **** **** -// *********************************************************************** -/** - * @brief find an object in the cache - * - * @param cache - * @param req - * @param update_cache whether to update the cache, - * if true, the object is promoted - * and if the object is expired, it is removed from the cache - * @return the object or NULL if not found - */ -static cache_obj_t *myMQv1_find(cache_t *cache, const request_t *req, - const bool update_cache) { - cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache); - ERROR("todo"); - - - return cache_obj; -} - -/** - * @brief insert an object into the cache, - * update the hash table and cache metadata - * this function assumes the cache has enough space - * eviction should be - * performed before calling this function - * - * @param cache - * @param req - * @return the inserted object - */ -static cache_obj_t *myMQv1_insert(cache_t *cache, const request_t *req) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - - cache_obj_t *obj = cache_insert_base(cache, req); - ERROR("todo"); - - - return obj; -} - -/** - * @brief find the object to be evicted - * this function does not actually evict the object or update metadata - * not all eviction algorithms support this function - * because the eviction logic cannot be decoupled from finding eviction - * candidate, so use assert(false) if you cannot support this function - * - * @param cache the cache - * @return the object to be evicted - */ -static cache_obj_t *myMQv1_to_evict(cache_t *cache, const request_t *req) { - assert(false); - return NULL; -} - -/** - * @brief evict an object from the cache - * it needs to call cache_evict_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param req not used - * @param evicted_obj if not NULL, return the evicted object to caller - */ -static void myMQv1_evict(cache_t *cache, const request_t *req) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - - ERROR("todo"); - - -} - -/** - * @brief remove an object from the cache - * this is different from cache_evict because it is used to for user trigger - * remove, and eviction is used by the cache to make space for new objects - * - * it needs to call cache_remove_obj_base before returning - * which updates some metadata such as n_obj, occupied size, and hash table - * - * @param cache - * @param obj_id - * @return true if the object is removed, false if the object is not in the - * cache - */ -static bool myMQv1_remove(cache_t *cache, const obj_id_t obj_id) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - - for (int i = 0; i < params->n_caches; i++) { - if (params->caches[i]->remove(params->caches[i], obj_id)) { - return true; - } - } - - return true; -} - -static int64_t myMQv1_get_occupied_byte(const cache_t *cache) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - int64_t occupied_byte = 0; - for (int i = 0; i < params->n_caches; i++) { - occupied_byte += params->caches[i]->get_occupied_byte(params->caches[i]); - } - return occupied_byte; -} - -static int64_t myMQv1_get_n_obj(const cache_t *cache) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - int64_t n_obj = 0; - for (int i = 0; i < params->n_caches; i++) { - n_obj += params->caches[i]->get_n_obj(params->caches[i]); - } - return n_obj; -} - -// *********************************************************************** -// **** **** -// **** parameter set up functions **** -// **** **** -// *********************************************************************** -static const char *myMQv1_current_params(cache_t *cache, - myMQv1_params_t *params) { - static __thread char params_str[128]; - int n = snprintf(params_str, 128, "n-caches=%ld;cache-size-ratio=%d", - params->n_caches, - (int)(params->cache_sizes[0] * 100 / cache->cache_size)); - - for (int i = 1; i < params->n_caches; i++) { - n += snprintf(params_str + n, 128 - n, ":%d", - (int)(params->cache_sizes[i] * 100 / cache->cache_size)); - } - n += snprintf(params_str + n, 128 - n, ";ghost-size-ratio=%d", - (int)(params->ghost_sizes[0] * 100 / cache->cache_size)); - for (int i = 1; i < params->n_caches; i++) { - n += snprintf(params_str + n, 128 - n, ":%d", - (int)(params->ghost_sizes[i] * 100 / cache->cache_size)); - } - - snprintf(cache->cache_name + n, 128 - n, "\n"); - - return params_str; -} - -static void myMQv1_parse_params(cache_t *cache, - const char *cache_specific_params) { - myMQv1_params_t *params = (myMQv1_params_t *)cache->eviction_params; - char *params_str = strdup(cache_specific_params); - char *old_params_str = params_str; - char *end; - - while (params_str != NULL && params_str[0] != '\0') { - /* different parameters are separated by comma, - * key and value are separated by = */ - char *key = strsep((char **)¶ms_str, "="); - char *value = strsep((char **)¶ms_str, ","); - - // skip the white space - while (params_str != NULL && *params_str == ' ') { - params_str++; - } - - if (strcasecmp(key, "n-cache") == 0) { - params->n_caches = (int)strtol(value, &end, 0); - if (strlen(end) > 2) { - ERROR("param parsing error, find string \"%s\" after number\n", end); - } - } else if (strcasecmp(key, "cache-size-ratio") == 0) { - int n_caches = 0; - int64_t cache_size_sum = 0; - int64_t cache_size_array[myMQv1_MAX_N_cache]; - char *v = strsep((char **)&value, ":"); - while (v != NULL) { - cache_size_array[n_caches++] = (int64_t)strtol(v, &end, 0); - cache_size_sum += cache_size_array[n_caches - 1]; - v = strsep((char **)&value, ":"); - } - if (params->n_caches != 0 && params->n_caches != n_caches) { - ERROR("n-cache and n-ghost-cache must be the same\n"); - exit(1); - } - params->n_caches = n_caches; - params->cache_sizes = calloc(params->n_caches, sizeof(int64_t)); - for (int i = 0; i < n_caches; i++) { - params->cache_sizes[i] = (int64_t)((double)cache_size_array[i] / - cache_size_sum * cache->cache_size); - } - } else if (strcasecmp(key, "ghost-size-ratio") == 0) { - int n_ghost_caches = 0; - int64_t cache_size_sum = 0; - int64_t ghost_size_array[myMQv1_MAX_N_cache]; - char *v = strsep((char **)&value, ":"); - while (v != NULL) { - ghost_size_array[n_ghost_caches++] = (int64_t)strtol(v, &end, 0); - v = strsep((char **)&value, ":"); - } - if (params->n_caches != 0 && params->n_caches != n_ghost_caches) { - ERROR("n-cache and n-ghost-cache must be the same\n"); - exit(1); - } - params->ghost_sizes = calloc(params->n_caches, sizeof(int64_t)); - for (int i = 0; i < n_ghost_caches; i++) { - params->ghost_sizes[i] = - (int64_t)((double)ghost_size_array[i] / cache->cache_size); - } - } else if (strcasecmp(key, "print") == 0) { - printf("current parameters: %s\n", myMQv1_current_params(cache, params)); - exit(0); - } else { - ERROR("%s does not have parameter %s\n", cache->cache_name, key); - exit(1); - } - } - free(old_params_str); -} - -#ifdef __cplusplus -} -#endif diff --git a/libCacheSim/include/libCacheSim/evictionAlgo.h b/libCacheSim/include/libCacheSim/evictionAlgo.h index 70434191..eb710927 100644 --- a/libCacheSim/include/libCacheSim/evictionAlgo.h +++ b/libCacheSim/include/libCacheSim/evictionAlgo.h @@ -91,9 +91,6 @@ cache_t *SLRU_init(const common_cache_params_t ccache_params, cache_t *SLRUv0_init(const common_cache_params_t ccache_params, const char *cache_specific_params); -cache_t *SFIFOv0_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - cache_t *SR_LRU_init(const common_cache_params_t ccache_params, const char *cache_specific_params); @@ -106,59 +103,12 @@ cache_t *LIRS_init(const common_cache_params_t ccache_params, cache_t *Size_init(const common_cache_params_t ccache_params, const char *cache_specific_params); -#ifdef ENABLE_LRB -cache_t *LRB_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); -#endif - -#ifdef INCLUDE_PRIV -cache_t *LRU_Prob_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *MyClock_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *QDLP_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *QDLPv1_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *ClockSize_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *QDLPv1_Size_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *QDLPv2_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *myMQv1_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *MClock_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *SFIFO_Merge_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *SFIFO_Reinsertion_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *SFIFO_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - cache_t *WTinyLFU_init(const common_cache_params_t ccache_params, const char *cache_specific_params); -cache_t *LP_SFIFO_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *LP_ARC_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); - -cache_t *LP_TwoQ_init(const common_cache_params_t ccache_params, - const char *cache_specific_params); +#ifdef ENABLE_LRB +cache_t *LRB_init(const common_cache_params_t ccache_params, + const char *cache_specific_params); #endif #if defined(ENABLE_GLCACHE) && ENABLE_GLCACHE == 1 From ca0968abd7b5249650495f994ff5693f9d39231a Mon Sep 17 00:00:00 2001 From: Juncheng Yang <1a1a11a@users.noreply.github.com> Date: Sat, 18 Feb 2023 18:32:12 +0000 Subject: [PATCH 2/2] allow LRB to run in parallel --- README.md | 2 - doc/install.md | 6 +-- libCacheSim/cache/eviction/LRB/lrb.cpp | 8 +-- libCacheSim/cache/eviction/LRB/lrb.h | 69 +++++++++++++++----------- 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 522287dd..e9419343 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [![build](https://github.com/1a1a11a/libCacheSimPrv/actions/workflows/build.yml/badge.svg)](https://github.com/1a1a11a/libCacheSimPrv/actions/workflows/build.yml) - ![visitors](https://visitor-badge.glitch.me/badge?page_id=1a1a11a.libCacheSim) diff --git a/doc/install.md b/doc/install.md index 69e55099..042d384d 100644 --- a/doc/install.md +++ b/doc/install.md @@ -20,7 +20,7 @@ tar xvf zstd-1.5.0.tar.gz; pushd zstd-1.5.0/build/cmake/; mkdir _build && cd _build/; cmake .. && make -j; -[sudo] make install; +sudo make install; popd; ``` @@ -30,7 +30,7 @@ git clone --recursive https://github.com/dmlc/xgboost; pushd xgboost; mkdir _build && cd _build; cmake .. && make -j; -[sudo] make install; +sudo make install; popd; ``` @@ -40,7 +40,7 @@ git clone --recursive https://github.com/microsoft/LightGBM; pushd LightGBM; mkdir _build && cd _build; cmake .. && make -j; -[sudo] make install +sudo make install popd; ``` diff --git a/libCacheSim/cache/eviction/LRB/lrb.cpp b/libCacheSim/cache/eviction/LRB/lrb.cpp index 4bb82354..91829d08 100644 --- a/libCacheSim/cache/eviction/LRB/lrb.cpp +++ b/libCacheSim/cache/eviction/LRB/lrb.cpp @@ -150,7 +150,7 @@ bool LRBCache::lookup(const SimpleRequest &req) { for (auto &sample_time: meta._sample_times) { //don't use label within the first forget window because the data is not static uint32_t future_distance = current_seq - sample_time; - training_data->emplace_back(meta, sample_time, future_distance, meta._key); + training_data->emplace_back(meta, sample_time, future_distance, meta._key, max_hash_edc_idx, edc_windows, hash_edc); ++training_data_distribution[1]; } //batch_size ~>= batch_size @@ -163,7 +163,7 @@ bool LRBCache::lookup(const SimpleRequest &req) { } //make this update after update training, otherwise the last timestamp will change - meta.update(current_seq); + meta.update(current_seq, n_extra_fields, max_hash_edc_idx, edc_windows, hash_edc); if (list_idx) { negative_candidate_queue->erase(forget_timestamp); negative_candidate_queue->insert({current_seq % memory_window, req.id}); @@ -209,7 +209,7 @@ void LRBCache::forget() { uint32_t future_distance = memory_window * 2; for (auto &sample_time: meta._sample_times) { //don't use label within the first forget window because the data is not static - training_data->emplace_back(meta, sample_time, future_distance, meta._key); + training_data->emplace_back(meta, sample_time, future_distance, meta._key, max_hash_edc_idx, edc_windows, hash_edc); ++training_data_distribution[0]; } //batch_size ~>= batch_size @@ -424,7 +424,7 @@ void LRBCache::evict_with_candidate(pair &epair) { uint32_t future_distance = current_seq - meta._past_timestamp + memory_window; for (auto &sample_time: meta._sample_times) { //don't use label within the first forget window because the data is not static - training_data->emplace_back(meta, sample_time, future_distance, meta._key); + training_data->emplace_back(meta, sample_time, future_distance, meta._key, max_hash_edc_idx, edc_windows, hash_edc); ++training_data_distribution[0]; } //batch_size ~>= batch_size diff --git a/libCacheSim/cache/eviction/LRB/lrb.h b/libCacheSim/cache/eviction/LRB/lrb.h index 84e0c5c6..d12d5063 100644 --- a/libCacheSim/cache/eviction/LRB/lrb.h +++ b/libCacheSim/cache/eviction/LRB/lrb.h @@ -24,19 +24,14 @@ using namespace std; using spp::sparse_hash_map; namespace lrb { - static uint32_t current_seq = -1; - static uint8_t max_n_past_timestamps = 32; - static uint8_t max_n_past_distances = 31; - static uint8_t base_edc_window = 10; static const uint8_t n_edc_feature = 10; - static vector edc_windows; - static vector hash_edc; - static uint32_t max_hash_edc_idx; - static uint32_t memory_window = 67108864; - static uint32_t n_extra_fields = 0; - static uint32_t batch_size = 131072; static const uint max_n_extra_feature = 4; - static uint32_t n_feature; + static const uint32_t n_extra_fields = 0; + static const uint8_t max_n_past_timestamps = 32; + static const uint8_t max_n_past_distances = 31; + static const uint8_t base_edc_window = 10; + static const uint32_t batch_size = 131072; + struct MetaExtra { //vector overhead = 24 (8 pointer, 8 size, 8 allocation) @@ -49,7 +44,11 @@ struct MetaExtra { //the next index to put the distance uint8_t _past_distance_idx = 1; - MetaExtra(const uint32_t &distance) { + MetaExtra(const uint32_t &distance, + uint32_t max_hash_edc_idx, + vector &edc_windows, + const vector &hash_edc + ) { _past_distances = vector(1, distance); for (uint8_t i = 0; i < n_edc_feature; ++i) { uint32_t _distance_idx = min(uint32_t(distance / edc_windows[i]), max_hash_edc_idx); @@ -57,7 +56,11 @@ struct MetaExtra { } } - void update(const uint32_t &distance) { + void update(const uint32_t &distance, + uint32_t max_hash_edc_idx, + vector &edc_windows, + const vector &hash_edc + ) { uint8_t distance_idx = _past_distance_idx % max_n_past_distances; if (_past_distances.size() < max_n_past_distances) _past_distances.emplace_back(distance); @@ -84,7 +87,6 @@ class Meta { MetaExtra *_extra = nullptr; vector _sample_times; - Meta(const uint64_t &key, const uint64_t &size, const uint64_t &past_timestamp, const vector &extra_features) { _key = key; @@ -104,14 +106,18 @@ class Meta { delete _extra; } - void update(const uint32_t &past_timestamp) { + void update(const uint32_t &past_timestamp, uint32_t n_extra_fields, + uint32_t max_hash_edc_idx, + vector &edc_windows, + const vector &hash_edc + ) { //distance uint32_t _distance = past_timestamp - _past_timestamp; assert(_distance); if (!_extra) { - _extra = new MetaExtra(_distance); + _extra = new MetaExtra(_distance, max_hash_edc_idx, edc_windows, hash_edc); } else - _extra->update(_distance); + _extra->update(_distance, max_hash_edc_idx, edc_windows, hash_edc); //timestamp _past_timestamp = past_timestamp; } @@ -174,16 +180,19 @@ class TrainingData { vector indptr; vector indices; vector data; + uint32_t memory_window; - TrainingData() { + TrainingData(uint32_t n_feature, uint32_t memory_window_) { labels.reserve(batch_size); indptr.reserve(batch_size + 1); indptr.emplace_back(0); indices.reserve(batch_size * n_feature); data.reserve(batch_size * n_feature); + memory_window = memory_window_; } - void emplace_back(Meta &meta, uint32_t &sample_timestamp, uint32_t &future_interval, const uint64_t &key) { + void emplace_back(Meta &meta, uint32_t &sample_timestamp, uint32_t &future_interval, const uint64_t &key, + uint32_t max_hash_edc_idx, vector &edc_windows, vector &hash_edc) { int32_t counter = indptr.back(); indices.emplace_back(0); @@ -262,6 +271,13 @@ struct KeyMapEntryT { class LRBCache : public Cache { public: + uint32_t current_seq = -1; + vector edc_windows; + vector hash_edc; + uint32_t max_hash_edc_idx; + uint32_t memory_window = 67108864; + uint32_t n_feature; + //key -> (0/1 list, idx) sparse_hash_map key_map; vector in_cache_metas; @@ -326,12 +342,6 @@ class LRBCache : public Cache { sample_rate = stoul(it.second); } else if (it.first == "memory_window") { memory_window = stoull(it.second); - } else if (it.first == "max_n_past_timestamps") { - max_n_past_timestamps = (uint8_t) stoi(it.second); - } else if (it.first == "batch_size") { - batch_size = stoull(it.second); - } else if (it.first == "n_extra_fields") { - n_extra_fields = stoull(it.second); } else if (it.first == "num_iterations") { training_params["num_iterations"] = it.second; } else if (it.first == "learning_rate") { @@ -363,7 +373,8 @@ class LRBCache : public Cache { } negative_candidate_queue = make_shared>(memory_window); - max_n_past_distances = max_n_past_timestamps - 1; + // max_n_past_distances = max_n_past_timestamps - 1; + //init edc_windows = vector(n_edc_feature); for (uint8_t i = 0; i < n_edc_feature; ++i) { @@ -386,7 +397,7 @@ class LRBCache : public Cache { training_params["categorical_feature"] = categorical_feature; } inference_params = training_params; - training_data = new TrainingData(); + training_data = new TrainingData(n_feature, memory_window); } string map_to_string(unordered_map &map) { @@ -417,7 +428,7 @@ class LRBCache : public Cache { void update_stat_periodic() override; - static void set_hash_edc() { + void set_hash_edc() { max_hash_edc_idx = (uint64_t) (memory_window / pow(2, base_edc_window)) - 1; hash_edc = vector(max_hash_edc_idx + 1); for (int i = 0; i < hash_edc.size(); ++i) @@ -454,7 +465,7 @@ class LRBCache : public Cache { }; -static Factory factoryLRB("LRB"); +// static Factory factoryLRB("LRB"); } #endif //WEBCACHESIM_LRB_H \ No newline at end of file