Skip to content

Commit 399e41a

Browse files
committed
Add MultiQueue eviction algorithm
1 parent b155f6c commit 399e41a

File tree

5 files changed

+232
-1
lines changed

5 files changed

+232
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ cachesim supports the following algorithms:
4646
### Eviction algorithms
4747
* [FIFO](/libCacheSim/cache/eviction/FIFO.c), [LRU](/libCacheSim/cache/eviction/LRU.c), [Clock](/libCacheSim/cache/eviction/Clock.c), [SLRU](/libCacheSim/cache/eviction/SLRU.c)
4848
* [LFU](/libCacheSim/cache/eviction/LFU.c), [LFU with dynamic aging](/libCacheSim/cache/eviction/LFUDA.c)
49-
* [ARC](/libCacheSim/cache/eviction/ARC.c), [TwoQ](/libCacheSim/cache/eviction/TwoQ.c), [CLOCK-PRO](/libCacheSim/cache/eviction/ClockPro.c)
49+
* [ARC](/libCacheSim/cache/eviction/ARC.c), [TwoQ](/libCacheSim/cache/eviction/TwoQ.c), [MultiQueue](/libCacheSim/cache/eviction/MultiQueue.c), [CLOCK-PRO](/libCacheSim/cache/eviction/ClockPro.c)
5050
* [Belady](/libCacheSim/cache/eviction/Belady.c), [BeladySize](/libCacheSim/cache/eviction/BeladySize.c)
5151
* [GDSF](/libCacheSim/cache/eviction/cpp/GDSF.cpp)
5252
* [Hyperbolic](/libCacheSim/cache/eviction/Hyperbolic.c)

libCacheSim/bin/cachesim/cache_init.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ static inline cache_t *create_cache(const char *trace_path,
5858
{"lru", LRU_init},
5959
{"lru-prob", LRU_Prob_init},
6060
{"nop", nop_init},
61+
{"mq", MultiQueue_init},
62+
{"multi-queue", MultiQueue_init},
63+
{"multiqueue", MultiQueue_init},
6164
// plugin cache that allows user to implement custom cache
6265
{"pluginCache", pluginCache_init},
6366
{"qdlp", QDLP_init},

libCacheSim/cache/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ set(eviction_sources_c
4444
eviction/LRUProb.c # a probabilistic version of LRU
4545
eviction/LRUv0.c # an inefficient version but easier to understand
4646
eviction/MRU.c
47+
eviction/MultiQueue.c
4748
eviction/nop.c
4849
eviction/plugin_cache.c # plugin cache that allows user to implement custom cache
4950
eviction/QDLP.c
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
//
2+
// Multi-Queue (MQ) cache eviction policy.
3+
// Objects are tracked in multiple LRU queues based on logarithmic frequency.
4+
//
5+
6+
#include "dataStructure/hashtable/hashtable.h"
7+
#include "libCacheSim/evictionAlgo.h"
8+
9+
#ifdef __cplusplus
10+
extern "C" {
11+
#endif
12+
13+
#define MQ_MAX_N_QUEUE 32
14+
15+
typedef struct {
16+
cache_obj_t **q_heads;
17+
cache_obj_t **q_tails;
18+
int64_t *q_n_bytes;
19+
int64_t *q_n_objs;
20+
int n_queue;
21+
} MQ_params_t;
22+
23+
static const char *DEFAULT_CACHE_PARAMS = "n-queue=8";
24+
25+
static void MQ_free(cache_t *cache);
26+
static bool MQ_get(cache_t *cache, const request_t *req);
27+
static cache_obj_t *MQ_find(cache_t *cache, const request_t *req,
28+
bool update_cache);
29+
static cache_obj_t *MQ_insert(cache_t *cache, const request_t *req);
30+
static cache_obj_t *MQ_to_evict(cache_t *cache, const request_t *req);
31+
static void MQ_evict(cache_t *cache, const request_t *req);
32+
static bool MQ_remove(cache_t *cache, obj_id_t obj_id);
33+
34+
static void MQ_remove_obj(cache_t *cache, cache_obj_t *obj);
35+
static void MQ_parse_params(cache_t *cache, const char *cache_specific_params);
36+
37+
static inline int MQ_level(int64_t freq, int n_queue) {
38+
int level = 0;
39+
while (freq > 1 && level < n_queue - 1) {
40+
freq >>= 1;
41+
level++;
42+
}
43+
return level;
44+
}
45+
46+
cache_t *MultiQueue_init(const common_cache_params_t ccache_params,
47+
const char *cache_specific_params) {
48+
cache_t *cache =
49+
cache_struct_init("MultiQueue", ccache_params, cache_specific_params);
50+
cache->cache_init = MultiQueue_init;
51+
cache->cache_free = MQ_free;
52+
cache->get = MQ_get;
53+
cache->find = MQ_find;
54+
cache->insert = MQ_insert;
55+
cache->evict = MQ_evict;
56+
cache->remove = MQ_remove;
57+
cache->to_evict = MQ_to_evict;
58+
cache->get_occupied_byte = cache_get_occupied_byte_default;
59+
cache->can_insert = cache_can_insert_default;
60+
cache->get_n_obj = cache_get_n_obj_default;
61+
62+
if (ccache_params.consider_obj_metadata) {
63+
cache->obj_md_size = 8 * 2;
64+
} else {
65+
cache->obj_md_size = 0;
66+
}
67+
68+
cache->eviction_params = malloc(sizeof(MQ_params_t));
69+
memset(cache->eviction_params, 0, sizeof(MQ_params_t));
70+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
71+
72+
params->n_queue = 8;
73+
MQ_parse_params(cache, DEFAULT_CACHE_PARAMS);
74+
if (cache_specific_params != NULL) {
75+
MQ_parse_params(cache, cache_specific_params);
76+
}
77+
78+
params->q_heads = calloc(params->n_queue, sizeof(cache_obj_t *));
79+
params->q_tails = calloc(params->n_queue, sizeof(cache_obj_t *));
80+
params->q_n_bytes = calloc(params->n_queue, sizeof(int64_t));
81+
params->q_n_objs = calloc(params->n_queue, sizeof(int64_t));
82+
83+
snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "MQ(%d)", params->n_queue);
84+
85+
return cache;
86+
}
87+
88+
static void MQ_free(cache_t *cache) {
89+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
90+
free(params->q_heads);
91+
free(params->q_tails);
92+
free(params->q_n_bytes);
93+
free(params->q_n_objs);
94+
free(params);
95+
cache_struct_free(cache);
96+
}
97+
98+
static bool MQ_get(cache_t *cache, const request_t *req) {
99+
return cache_get_base(cache, req);
100+
}
101+
102+
static cache_obj_t *MQ_find(cache_t *cache, const request_t *req,
103+
bool update_cache) {
104+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
105+
cache_obj_t *obj = cache_find_base(cache, req, update_cache);
106+
if (!obj || !update_cache) {
107+
return obj;
108+
}
109+
110+
obj->misc.freq += 1;
111+
int curr_level = obj->SLRU.lru_id;
112+
int next_level = MQ_level(obj->misc.freq, params->n_queue);
113+
114+
if (next_level != curr_level) {
115+
remove_obj_from_list(&params->q_heads[curr_level], &params->q_tails[curr_level],
116+
obj);
117+
params->q_n_objs[curr_level] -= 1;
118+
params->q_n_bytes[curr_level] -= obj->obj_size;
119+
120+
prepend_obj_to_head(&params->q_heads[next_level], &params->q_tails[next_level],
121+
obj);
122+
params->q_n_objs[next_level] += 1;
123+
params->q_n_bytes[next_level] += obj->obj_size;
124+
obj->SLRU.lru_id = next_level;
125+
} else {
126+
move_obj_to_head(&params->q_heads[curr_level], &params->q_tails[curr_level],
127+
obj);
128+
}
129+
130+
return obj;
131+
}
132+
133+
static cache_obj_t *MQ_insert(cache_t *cache, const request_t *req) {
134+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
135+
cache_obj_t *obj = cache_insert_base(cache, req);
136+
137+
obj->misc.freq = 1;
138+
obj->SLRU.lru_id = 0;
139+
prepend_obj_to_head(&params->q_heads[0], &params->q_tails[0], obj);
140+
params->q_n_objs[0] += 1;
141+
params->q_n_bytes[0] += obj->obj_size;
142+
143+
return obj;
144+
}
145+
146+
static cache_obj_t *MQ_to_evict(cache_t *cache, const request_t *req) {
147+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
148+
(void)req;
149+
150+
for (int i = 0; i < params->n_queue; i++) {
151+
if (params->q_tails[i] != NULL) {
152+
cache->to_evict_candidate_gen_vtime = cache->n_req;
153+
return params->q_tails[i];
154+
}
155+
}
156+
157+
DEBUG_ASSERT(cache->occupied_byte == 0);
158+
return NULL;
159+
}
160+
161+
static void MQ_evict(cache_t *cache, const request_t *req) {
162+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
163+
cache_obj_t *obj_to_evict = MQ_to_evict(cache, req);
164+
DEBUG_ASSERT(obj_to_evict != NULL);
165+
166+
int level = obj_to_evict->SLRU.lru_id;
167+
remove_obj_from_list(&params->q_heads[level], &params->q_tails[level],
168+
obj_to_evict);
169+
params->q_n_objs[level] -= 1;
170+
params->q_n_bytes[level] -= obj_to_evict->obj_size;
171+
172+
cache_evict_base(cache, obj_to_evict, true);
173+
}
174+
175+
static void MQ_remove_obj(cache_t *cache, cache_obj_t *obj) {
176+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
177+
int level = obj->SLRU.lru_id;
178+
179+
remove_obj_from_list(&params->q_heads[level], &params->q_tails[level], obj);
180+
params->q_n_objs[level] -= 1;
181+
params->q_n_bytes[level] -= obj->obj_size;
182+
183+
cache_remove_obj_base(cache, obj, true);
184+
}
185+
186+
static bool MQ_remove(cache_t *cache, obj_id_t obj_id) {
187+
cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id);
188+
if (obj == NULL) {
189+
return false;
190+
}
191+
192+
MQ_remove_obj(cache, obj);
193+
return true;
194+
}
195+
196+
static void MQ_parse_params(cache_t *cache, const char *cache_specific_params) {
197+
MQ_params_t *params = (MQ_params_t *)cache->eviction_params;
198+
199+
char *params_str = strdup(cache_specific_params);
200+
char *params_str_to_free = params_str;
201+
202+
while (params_str != NULL && params_str[0] != '\0') {
203+
char *key = strsep((char **)&params_str, "=");
204+
char *value = strsep((char **)&params_str, ",");
205+
206+
if (strcasecmp(key, "n-queue") == 0 || strcasecmp(key, "n-queues") == 0 ||
207+
strcasecmp(key, "nq") == 0) {
208+
params->n_queue = (int)strtol(value, NULL, 0);
209+
if (params->n_queue <= 0 || params->n_queue > MQ_MAX_N_QUEUE) {
210+
ERROR("MultiQueue n-queue should be in [1, %d], given %d\n",
211+
MQ_MAX_N_QUEUE, params->n_queue);
212+
abort();
213+
}
214+
} else {
215+
WARN("MQ does not support parameter %s\n", key);
216+
}
217+
}
218+
219+
free(params_str_to_free);
220+
}
221+
222+
#ifdef __cplusplus
223+
}
224+
#endif

libCacheSim/include/libCacheSim/evictionAlgo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ cache_t *LRUv0_init(const common_cache_params_t ccache_params,
116116
cache_t *MRU_init(const common_cache_params_t ccache_params,
117117
const char *cache_specific_params);
118118

119+
cache_t *MultiQueue_init(const common_cache_params_t ccache_params,
120+
const char *cache_specific_params);
121+
119122
cache_t *nop_init(const common_cache_params_t ccache_params,
120123
const char *cache_specific_params);
121124

0 commit comments

Comments
 (0)