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//
1924extern "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- */
8981static 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 */
158134static 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 */
0 commit comments