Skip to content

Commit 0da6555

Browse files
committed
Add write amplification statistics and update eviction algorithms for enhanced reporting
1 parent 5251a56 commit 0da6555

6 files changed

Lines changed: 481 additions & 74 deletions

File tree

libCacheSim/bin/cachesim/sim.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "libCacheSim/cache.h"
2+
#include "libCacheSim/evictionAlgo.h"
23
#include "libCacheSim/reader.h"
34
#include "utils/include/mymath.h"
45
#include "utils/include/mystr.h"
@@ -103,6 +104,32 @@ void simulate(reader_t *reader, cache_t *cache, int report_interval,
103104
if (show_cost)
104105
n += snprintf(output_str + n, sizeof(output_str) - n,
105106
", cost saving ratio %.4lf", cost_saving_ratio);
107+
108+
/* compute extra write bytes for flash write ratio reporting */
109+
int64_t extra_write_byte = 0;
110+
if (cache->cache_init == Clock_init) {
111+
extra_write_byte = ((Clock_params_t *)cache->eviction_params)->n_byte_rewritten;
112+
} else if (cache->cache_init == ClockRI_init) {
113+
extra_write_byte = ((ClockRI_params_t *)cache->eviction_params)->n_byte_rewritten;
114+
} else if (cache->cache_init == ClockOracle_init) {
115+
extra_write_byte = ((ClockOracle_params_t *)cache->eviction_params)->n_byte_rewritten;
116+
} else if (cache->cache_init == LRU_init) {
117+
extra_write_byte = ((LRU_params_t *)cache->eviction_params)->n_byte_promoted;
118+
} else if (cache->cache_init == S3FIFO_init) {
119+
S3FIFO_params_t *p = (S3FIFO_params_t *)cache->eviction_params;
120+
extra_write_byte = p->n_byte_promoted + p->n_byte_rewritten;
121+
}
122+
123+
if (cache->cache_init == FIFO_init || cache->cache_init == Sieve_init ||
124+
cache->cache_init == Clock_init || cache->cache_init == ClockRI_init ||
125+
cache->cache_init == ClockOracle_init || cache->cache_init == LRU_init ||
126+
cache->cache_init == S3FIFO_init) {
127+
double write_ratio = req_byte > 0
128+
? (double)(miss_byte + extra_write_byte) / (double)req_byte : 0.0;
129+
n += snprintf(output_str + n, sizeof(output_str) - n,
130+
", write ratio %.4lf", write_ratio);
131+
}
132+
106133
snprintf(output_str + n, sizeof(output_str) - n, ", throughput %.2lf MQPS\n",
107134
(double)req_cnt / 1000000.0 / runtime);
108135
printf("%s", output_str);

libCacheSim/cache/eviction/ClockOracle.c

Lines changed: 43 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
//
22
// ClockOracle
33
//
4-
// An oracle-assisted CLOCK that uses next_access_vtime to decide reinsertion.
5-
// During eviction scan, an object is reinserted only if:
6-
// next_access_vtime - current_vtime <= cache_size / miss_ratio
7-
// Objects whose next access is beyond this threshold are evicted.
4+
// An oracle-assisted CLOCK that combines the visited bit with oracle
5+
// reuse distance to decide reinsertion.
6+
//
7+
// An object is reinserted only if BOTH conditions hold:
8+
// 1. The visited bit is set (object was accessed since last eviction scan)
9+
// 2. next_access_vtime - current_vtime <= cache_size / miss_ratio
10+
//
11+
// The visited bit is cleared on reinsertion (like standard CLOCK).
12+
// Objects failing either condition are evicted.
813
//
914
// Requires oracle traces (oracleGeneral / lcs) that provide next_access_vtime.
1015
//
@@ -19,16 +24,6 @@
1924
extern "C" {
2025
#endif
2126

22-
typedef struct {
23-
cache_obj_t *q_head;
24-
cache_obj_t *q_tail;
25-
26-
int64_t n_miss;
27-
28-
int64_t n_obj_rewritten;
29-
int64_t n_byte_rewritten;
30-
} ClockOracle_params_t;
31-
3227
// ***********************************************************************
3328
// **** ****
3429
// **** function declarations ****
@@ -83,32 +78,8 @@ static void ClockOracle_free(cache_t *cache) {
8378
cache_struct_free(cache);
8479
}
8580

86-
/**
87-
* @brief custom get that tracks misses for miss ratio computation
88-
*/
8981
static bool ClockOracle_get(cache_t *cache, const request_t *req) {
90-
ClockOracle_params_t *params =
91-
(ClockOracle_params_t *)cache->eviction_params;
92-
93-
cache->n_req += 1;
94-
95-
cache_obj_t *obj = cache->find(cache, req, true);
96-
bool hit = (obj != NULL);
97-
98-
if (!hit) {
99-
params->n_miss += 1;
100-
101-
if (cache->can_insert(cache, req)) {
102-
while (cache->get_occupied_byte(cache) + req->obj_size +
103-
cache->obj_md_size >
104-
cache->cache_size) {
105-
cache->evict(cache, req);
106-
}
107-
cache->insert(cache, req);
108-
}
109-
}
110-
111-
return hit;
82+
return cache_get_base(cache, req);
11283
}
11384

11485
// ***********************************************************************
@@ -121,6 +92,8 @@ static cache_obj_t *ClockOracle_find(cache_t *cache, const request_t *req,
12192
bool update_cache) {
12293
cache_obj_t *obj = cache_find_base(cache, req, update_cache);
12394
if (obj != NULL && update_cache) {
95+
/* set visited bit */
96+
obj->clock.freq = 1;
12497
obj->next_access_vtime = req->next_access_vtime;
12598
}
12699
return obj;
@@ -130,9 +103,13 @@ static cache_obj_t *ClockOracle_insert(cache_t *cache, const request_t *req) {
130103
ClockOracle_params_t *params =
131104
(ClockOracle_params_t *)cache->eviction_params;
132105

106+
params->n_miss += 1;
107+
133108
cache_obj_t *obj = cache_insert_base(cache, req);
134109
prepend_obj_to_head(&params->q_head, &params->q_tail, obj);
135110

111+
/* new objects start with visited bit clear */
112+
obj->clock.freq = 0;
136113
obj->next_access_vtime = req->next_access_vtime;
137114

138115
return obj;
@@ -145,23 +122,21 @@ static cache_obj_t *ClockOracle_to_evict(cache_t *cache, const request_t *req) {
145122
}
146123

147124
/**
148-
* @brief evict using oracle information
125+
* @brief evict using oracle + visited bit
149126
*
150-
* Scan from the tail. For each object, compute the reinsertion threshold:
151-
* threshold = cache_size / miss_ratio
152-
* If next_access_vtime - current_vtime > threshold, evict the object.
153-
* Otherwise, reinsert it to the head.
127+
* Scan from the tail. An object is reinserted only if BOTH:
128+
* 1. visited bit is set (freq >= 1)
129+
* 2. next_access_vtime - current_vtime <= cache_size / miss_ratio
154130
*
155-
* Objects with next_access_vtime == INT64_MAX (no future access) are always
156-
* evicted.
131+
* On reinsertion, the visited bit is cleared.
132+
* Objects failing either condition are evicted.
157133
*/
158134
static void ClockOracle_evict(cache_t *cache, const request_t *req) {
159135
ClockOracle_params_t *params =
160136
(ClockOracle_params_t *)cache->eviction_params;
161137

162-
/* compute the reinsertion threshold: cache_size / miss_ratio
163-
* miss_ratio = n_miss / n_req, so threshold = cache_size * n_req / n_miss
164-
* when n_miss == 0, use cache_size as the threshold (conservative) */
138+
/* threshold = cache_size / miss_ratio = cache_size * n_req / n_miss
139+
* when n_miss == 0, use cache_size as the threshold */
165140
int64_t threshold;
166141
if (params->n_miss > 0) {
167142
threshold = (int64_t)((double)cache->cache_size * (double)cache->n_req /
@@ -170,23 +145,31 @@ static void ClockOracle_evict(cache_t *cache, const request_t *req) {
170145
threshold = cache->cache_size;
171146
}
172147

173-
/* scan at most n_obj objects to avoid infinite loop */
174-
int64_t n_scanned = 0;
148+
175149
cache_obj_t *obj_to_evict = params->q_tail;
150+
int64_t n_scanned = 0;
176151
while (obj_to_evict != NULL && n_scanned < cache->n_obj) {
177-
int64_t reuse_dist = obj_to_evict->next_access_vtime - cache->n_req;
178152
n_scanned++;
179153

180-
/* evict if no future access or reuse distance exceeds threshold */
181-
if (obj_to_evict->next_access_vtime == INT64_MAX || reuse_dist > threshold) {
182-
break;
154+
bool no_future_access = (obj_to_evict->next_access_vtime == -1 ||
155+
obj_to_evict->next_access_vtime == INT64_MAX);
156+
bool visited = (obj_to_evict->clock.freq >= 1);
157+
int64_t reuse_dist = obj_to_evict->next_access_vtime - cache->n_req;
158+
bool within_threshold = (!no_future_access && reuse_dist <= threshold);
159+
160+
/* reinsert only if visited AND within threshold */
161+
if (visited && within_threshold) {
162+
/* clear visited bit, reinsert to head */
163+
obj_to_evict->clock.freq = 0;
164+
params->n_obj_rewritten += 1;
165+
params->n_byte_rewritten += obj_to_evict->obj_size;
166+
move_obj_to_head(&params->q_head, &params->q_tail, obj_to_evict);
167+
obj_to_evict = params->q_tail;
168+
continue;
183169
}
184170

185-
/* reinsert: move to head */
186-
params->n_obj_rewritten += 1;
187-
params->n_byte_rewritten += obj_to_evict->obj_size;
188-
move_obj_to_head(&params->q_head, &params->q_tail, obj_to_evict);
189-
obj_to_evict = params->q_tail;
171+
/* evict: either not visited, no future access, or too far away */
172+
break;
190173
}
191174

192175
/* safety: if everything was reinserted, evict the tail */

libCacheSim/cache/eviction/S3FIFO.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,6 @@
3636
extern "C" {
3737
#endif
3838

39-
typedef struct {
40-
cache_t *small_fifo;
41-
cache_t *ghost_fifo;
42-
cache_t *main_fifo;
43-
bool hit_on_ghost;
44-
45-
int move_to_main_threshold;
46-
double small_size_ratio;
47-
double ghost_size_ratio;
48-
49-
bool has_evicted;
50-
request_t *req_local;
51-
} S3FIFO_params_t;
52-
5339
static const char *DEFAULT_CACHE_PARAMS =
5440
"small-size-ratio=0.10,ghost-size-ratio=0.90,move-to-main-threshold=2";
5541

@@ -323,6 +309,8 @@ static void S3FIFO_evict_small(cache_t *cache, const request_t *req) {
323309
copy_cache_obj_to_request(params->req_local, obj_to_evict);
324310

325311
if (obj_to_evict->S3FIFO.freq >= params->move_to_main_threshold) {
312+
params->n_obj_promoted += 1;
313+
params->n_byte_promoted += obj_to_evict->obj_size;
326314
main_fifo->insert(main_fifo, params->req_local);
327315
} else {
328316
// insert to ghost
@@ -349,6 +337,8 @@ static void S3FIFO_evict_main(cache_t *cache, const request_t *req) {
349337
int freq = obj_to_evict->S3FIFO.freq;
350338
copy_cache_obj_to_request(params->req_local, obj_to_evict);
351339
if (freq >= 1) {
340+
params->n_obj_rewritten += 1;
341+
params->n_byte_rewritten += obj_to_evict->obj_size;
352342
// we need to evict first because the object to insert has the same obj_id
353343
main_fifo->remove(main_fifo, obj_to_evict->obj_id);
354344
obj_to_evict = NULL;

libCacheSim/include/libCacheSim/evictionAlgo.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ typedef struct {
5656
int64_t n_byte_rewritten;
5757
} ClockRI_params_t;
5858

59+
typedef struct {
60+
cache_obj_t *q_head;
61+
cache_obj_t *q_tail;
62+
63+
int64_t n_miss;
64+
65+
int64_t n_obj_rewritten;
66+
int64_t n_byte_rewritten;
67+
} ClockOracle_params_t;
68+
5969
cache_t *ARC_init(const common_cache_params_t ccache_params,
6070
const char *cache_specific_params);
6171

@@ -159,6 +169,25 @@ cache_t *RandomTwo_init(const common_cache_params_t ccache_params,
159169
cache_t *Random_init(const common_cache_params_t ccache_params,
160170
const char *cache_specific_params);
161171

172+
typedef struct {
173+
cache_t *small_fifo;
174+
cache_t *ghost_fifo;
175+
cache_t *main_fifo;
176+
bool hit_on_ghost;
177+
178+
int move_to_main_threshold;
179+
double small_size_ratio;
180+
double ghost_size_ratio;
181+
182+
bool has_evicted;
183+
request_t *req_local;
184+
185+
int64_t n_obj_promoted;
186+
int64_t n_byte_promoted;
187+
int64_t n_obj_rewritten;
188+
int64_t n_byte_rewritten;
189+
} S3FIFO_params_t;
190+
162191
cache_t *S3FIFO_init(const common_cache_params_t ccache_params,
163192
const char *cache_specific_params);
164193

0 commit comments

Comments
 (0)