Skip to content

Commit 07128a4

Browse files
committed
Add ClockRI eviction algorithm implementation and update related files
1 parent d3c4364 commit 07128a4

5 files changed

Lines changed: 325 additions & 0 deletions

File tree

libCacheSim/bin/cachesim/cache_init.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static inline cache_t *create_cache(const char *trace_path,
4141
{"CAR", CAR_init},
4242
{"cacheus", Cacheus_init},
4343
{"clock", Clock_init},
44+
{"clockri", ClockRI_init},
4445
{"clockpro", ClockPro_init},
4546
{"fifo", FIFO_init},
4647
{"fifo-merge", FIFO_Merge_init},

libCacheSim/cache/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ set(eviction_sources_c
3232
eviction/CAR.c
3333
eviction/Cacheus.c
3434
eviction/Clock.c
35+
eviction/ClockRI.c
3536
eviction/ClockPro.c
3637
eviction/FIFO.c
3738
eviction/Hyperbolic.c
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
//
2+
// ClockRI (Clock with fixed Reinsertion ratio)
3+
//
4+
// A CLOCK/FIFO variant that examines a batch of objects at eviction time
5+
// and reinserts the most recently accessed x% (default 28%) to the head,
6+
// evicting the rest.
7+
//
8+
// ClockRI.c
9+
// libCacheSim
10+
//
11+
12+
#include <assert.h>
13+
14+
#include "dataStructure/hashtable/hashtable.h"
15+
#include "libCacheSim/evictionAlgo.h"
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
struct sort_list_node {
22+
int32_t last_access_vtime;
23+
cache_obj_t *cache_obj;
24+
};
25+
26+
static const char *DEFAULT_PARAMS =
27+
"n-exam=100,reinsertion-ratio=0.28";
28+
29+
// ***********************************************************************
30+
// **** ****
31+
// **** function declarations ****
32+
// **** ****
33+
// ***********************************************************************
34+
35+
static void ClockRI_parse_params(cache_t *cache,
36+
const char *cache_specific_params);
37+
static void ClockRI_free(cache_t *cache);
38+
static bool ClockRI_get(cache_t *cache, const request_t *req);
39+
static cache_obj_t *ClockRI_find(cache_t *cache, const request_t *req,
40+
bool update_cache);
41+
static cache_obj_t *ClockRI_insert(cache_t *cache, const request_t *req);
42+
static cache_obj_t *ClockRI_to_evict(cache_t *cache, const request_t *req);
43+
static void ClockRI_evict(cache_t *cache, const request_t *req);
44+
static void ClockRI_remove_obj(cache_t *cache, cache_obj_t *obj);
45+
static bool ClockRI_remove(cache_t *cache, obj_id_t obj_id);
46+
47+
static inline int cmp_list_node(const void *a0, const void *b0);
48+
49+
// ***********************************************************************
50+
// **** ****
51+
// **** end user facing functions ****
52+
// **** ****
53+
// ***********************************************************************
54+
55+
cache_t *ClockRI_init(const common_cache_params_t ccache_params,
56+
const char *cache_specific_params) {
57+
cache_t *cache =
58+
cache_struct_init("ClockRI", ccache_params, cache_specific_params);
59+
cache->cache_init = ClockRI_init;
60+
cache->cache_free = ClockRI_free;
61+
cache->get = ClockRI_get;
62+
cache->find = ClockRI_find;
63+
cache->insert = ClockRI_insert;
64+
cache->evict = ClockRI_evict;
65+
cache->remove = ClockRI_remove;
66+
cache->to_evict = ClockRI_to_evict;
67+
68+
if (ccache_params.consider_obj_metadata) {
69+
cache->obj_md_size = sizeof(ClockRI_obj_metadata_t);
70+
} else {
71+
cache->obj_md_size = 0;
72+
}
73+
74+
ClockRI_params_t *params = my_malloc(ClockRI_params_t);
75+
memset(params, 0, sizeof(ClockRI_params_t));
76+
cache->eviction_params = params;
77+
78+
params->q_head = NULL;
79+
params->q_tail = NULL;
80+
params->next_to_merge = NULL;
81+
params->n_exam_obj = 100;
82+
params->reinsertion_ratio = 0.28;
83+
84+
if (cache_specific_params != NULL) {
85+
ClockRI_parse_params(cache, cache_specific_params);
86+
}
87+
88+
assert(params->n_exam_obj > 0);
89+
assert(params->reinsertion_ratio >= 0.0 && params->reinsertion_ratio < 1.0);
90+
91+
snprintf(cache->cache_name, CACHE_NAME_ARRAY_LEN, "ClockRI-%.2lf-%d",
92+
params->reinsertion_ratio, params->n_exam_obj);
93+
94+
return cache;
95+
}
96+
97+
static void ClockRI_free(cache_t *cache) {
98+
my_free(sizeof(ClockRI_params_t), cache->eviction_params);
99+
cache_struct_free(cache);
100+
}
101+
102+
static bool ClockRI_get(cache_t *cache, const request_t *req) {
103+
return cache_get_base(cache, req);
104+
}
105+
106+
// ***********************************************************************
107+
// **** ****
108+
// **** developer facing APIs (used by cache developer) ****
109+
// **** ****
110+
// ***********************************************************************
111+
112+
static cache_obj_t *ClockRI_find(cache_t *cache, const request_t *req,
113+
bool update_cache) {
114+
cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache);
115+
116+
if (cache_obj && update_cache) {
117+
cache_obj->ClockRI.last_access_vtime = (int32_t)cache->n_req;
118+
}
119+
120+
return cache_obj;
121+
}
122+
123+
static cache_obj_t *ClockRI_insert(cache_t *cache, const request_t *req) {
124+
ClockRI_params_t *params = (ClockRI_params_t *)cache->eviction_params;
125+
126+
cache_obj_t *obj = cache_insert_base(cache, req);
127+
prepend_obj_to_head(&params->q_head, &params->q_tail, obj);
128+
129+
obj->ClockRI.last_access_vtime = (int32_t)cache->n_req;
130+
131+
return obj;
132+
}
133+
134+
static cache_obj_t *ClockRI_to_evict(cache_t *cache, const request_t *req) {
135+
/* multiple objects may be evicted per call, cannot return a single one */
136+
ERROR("Undefined! Multiple objs will be evicted\n");
137+
abort();
138+
return NULL;
139+
}
140+
141+
/**
142+
* @brief evict objects from the cache
143+
* examine n_exam_obj objects from the eviction end, reinsert the most recently
144+
* accessed reinsertion_ratio fraction to the head, evict the rest
145+
*/
146+
static void ClockRI_evict(cache_t *cache, const request_t *req) {
147+
ClockRI_params_t *params = (ClockRI_params_t *)cache->eviction_params;
148+
149+
cache_obj_t *cache_obj = params->next_to_merge;
150+
int n_loop = 0;
151+
if (cache_obj == NULL) {
152+
params->next_to_merge = params->q_tail;
153+
cache_obj = params->q_tail;
154+
n_loop = 1;
155+
}
156+
157+
/* if cache is too small, just evict one object */
158+
if (cache->n_obj <= params->n_exam_obj) {
159+
cache_obj_t *prev = params->next_to_merge->queue.prev;
160+
ClockRI_remove_obj(cache, params->next_to_merge);
161+
params->next_to_merge = prev;
162+
return;
163+
}
164+
165+
int n_exam = params->n_exam_obj;
166+
int n_keep = (int)(n_exam * params->reinsertion_ratio);
167+
168+
/* collect objects to examine */
169+
struct sort_list_node *metric_list =
170+
(struct sort_list_node *)alloca(sizeof(struct sort_list_node) * n_exam);
171+
172+
for (int i = 0; i < n_exam; i++) {
173+
assert(cache_obj != NULL);
174+
metric_list[i].last_access_vtime = cache_obj->ClockRI.last_access_vtime;
175+
metric_list[i].cache_obj = cache_obj;
176+
cache_obj = cache_obj->queue.prev;
177+
178+
if (cache_obj == NULL) {
179+
cache_obj = params->q_tail;
180+
DEBUG_ASSERT(n_loop++ <= 2);
181+
}
182+
}
183+
params->next_to_merge = cache_obj;
184+
185+
/* sort by last_access_vtime ascending: smallest (oldest) first */
186+
qsort(metric_list, n_exam, sizeof(struct sort_list_node), cmp_list_node);
187+
188+
/* evict the oldest (1 - reinsertion_ratio) fraction */
189+
int n_evict = n_exam - n_keep;
190+
for (int i = 0; i < n_evict; i++) {
191+
ClockRI_remove_obj(cache, metric_list[i].cache_obj);
192+
}
193+
194+
/* reinsert the most recent n_keep objects to the head */
195+
for (int i = n_evict; i < n_exam; i++) {
196+
cache_obj_t *obj = metric_list[i].cache_obj;
197+
move_obj_to_head(&params->q_head, &params->q_tail, obj);
198+
199+
params->n_obj_rewritten += 1;
200+
params->n_byte_rewritten += obj->obj_size;
201+
}
202+
}
203+
204+
static void ClockRI_remove_obj(cache_t *cache, cache_obj_t *obj) {
205+
DEBUG_ASSERT(obj != NULL);
206+
ClockRI_params_t *params = (ClockRI_params_t *)cache->eviction_params;
207+
208+
if (obj == params->next_to_merge) {
209+
params->next_to_merge = obj->queue.prev;
210+
}
211+
212+
remove_obj_from_list(&params->q_head, &params->q_tail, obj);
213+
cache_remove_obj_base(cache, obj, true);
214+
}
215+
216+
static bool ClockRI_remove(cache_t *cache, obj_id_t obj_id) {
217+
cache_obj_t *obj = hashtable_find_obj_id(cache->hashtable, obj_id);
218+
if (obj == NULL) {
219+
return false;
220+
}
221+
222+
ClockRI_remove_obj(cache, obj);
223+
224+
return true;
225+
}
226+
227+
// ***********************************************************************
228+
// **** ****
229+
// **** parameter set up functions ****
230+
// **** ****
231+
// ***********************************************************************
232+
static const char *ClockRI_current_params(ClockRI_params_t *params) {
233+
static __thread char params_str[128];
234+
snprintf(params_str, 128, "n-exam=%d, reinsertion-ratio=%.4lf",
235+
params->n_exam_obj, params->reinsertion_ratio);
236+
return params_str;
237+
}
238+
239+
static void ClockRI_parse_params(cache_t *cache,
240+
const char *cache_specific_params) {
241+
ClockRI_params_t *params = (ClockRI_params_t *)cache->eviction_params;
242+
243+
char *params_str = strdup(cache_specific_params);
244+
char *old_params_str = params_str;
245+
char *end;
246+
247+
while (params_str != NULL && params_str[0] != '\0') {
248+
char *key = strsep((char **)&params_str, "=");
249+
char *value = strsep((char **)&params_str, ",");
250+
251+
// skip white space
252+
while (params_str != NULL && *params_str == ' ') {
253+
params_str++;
254+
}
255+
256+
if (strcasecmp(key, "n-exam") == 0) {
257+
params->n_exam_obj = (int)strtol(value, &end, 0);
258+
if (strlen(end) > 2) {
259+
ERROR("param parsing error, find string \"%s\" after number\n", end);
260+
}
261+
} else if (strcasecmp(key, "reinsertion-ratio") == 0) {
262+
params->reinsertion_ratio = strtod(value, &end);
263+
if (strlen(end) > 2) {
264+
ERROR("param parsing error, find string \"%s\" after number\n", end);
265+
}
266+
} else if (strcasecmp(key, "print") == 0) {
267+
printf("%s parameters: %s\n", cache->cache_name,
268+
ClockRI_current_params(params));
269+
exit(0);
270+
} else {
271+
ERROR("%s does not have parameter %s, example parameters %s\n",
272+
cache->cache_name, key, ClockRI_current_params(params));
273+
exit(1);
274+
}
275+
}
276+
277+
free(old_params_str);
278+
}
279+
280+
// ***********************************************************************
281+
// **** ****
282+
// **** cache internal functions ****
283+
// **** ****
284+
// ***********************************************************************
285+
static inline int cmp_list_node(const void *a0, const void *b0) {
286+
const struct sort_list_node *a = (const struct sort_list_node *)a0;
287+
const struct sort_list_node *b = (const struct sort_list_node *)b0;
288+
289+
if (a->last_access_vtime < b->last_access_vtime) {
290+
return -1;
291+
} else if (a->last_access_vtime > b->last_access_vtime) {
292+
return 1;
293+
} else {
294+
return 0;
295+
}
296+
}
297+
298+
#ifdef __cplusplus
299+
}
300+
#endif

libCacheSim/include/libCacheSim/cacheObj.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ typedef struct {
143143
int32_t freq;
144144
} __attribute__((packed)) Sieve_obj_params_t;
145145

146+
typedef struct {
147+
int32_t last_access_vtime;
148+
} ClockRI_obj_metadata_t;
149+
146150
// ############################## cache obj ###################################
147151
struct cache_obj;
148152
typedef struct cache_obj {
@@ -188,6 +192,7 @@ typedef struct cache_obj {
188192
S3FIFO_obj_metadata_t S3FIFO;
189193
Sieve_obj_params_t sieve;
190194
CAR_obj_metadata_t CAR;
195+
ClockRI_obj_metadata_t ClockRI;
191196

192197
#if defined(ENABLE_GLCACHE) && ENABLE_GLCACHE == 1
193198
GLCache_obj_metadata_t GLCache;

libCacheSim/include/libCacheSim/evictionAlgo.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ typedef struct {
4141
int64_t n_byte_rewritten;
4242
} Clock_params_t;
4343

44+
typedef struct {
45+
cache_obj_t *q_head;
46+
cache_obj_t *q_tail;
47+
48+
// points to the eviction position
49+
cache_obj_t *next_to_merge;
50+
// the number of objects to examine at each eviction
51+
int n_exam_obj;
52+
// reinsertion ratio: fraction of examined objects to reinsert
53+
double reinsertion_ratio;
54+
55+
int64_t n_obj_rewritten;
56+
int64_t n_byte_rewritten;
57+
} ClockRI_params_t;
58+
4459
cache_t *ARC_init(const common_cache_params_t ccache_params,
4560
const char *cache_specific_params);
4661

@@ -62,6 +77,9 @@ cache_t *Cacheus_init(const common_cache_params_t ccache_params,
6277
cache_t *Clock_init(const common_cache_params_t ccache_params,
6378
const char *cache_specific_params);
6479

80+
cache_t *ClockRI_init(const common_cache_params_t ccache_params,
81+
const char *cache_specific_params);
82+
6583
cache_t *ClockPro_init(const common_cache_params_t ccache_params,
6684
const char *cache_specific_params);
6785

0 commit comments

Comments
 (0)