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 ****
@@ -121,6 +116,8 @@ static cache_obj_t *ClockOracle_find(cache_t *cache, const request_t *req,
121116 bool update_cache ) {
122117 cache_obj_t * obj = cache_find_base (cache , req , update_cache );
123118 if (obj != NULL && update_cache ) {
119+ /* set visited bit */
120+ obj -> clock .freq = 1 ;
124121 obj -> next_access_vtime = req -> next_access_vtime ;
125122 }
126123 return obj ;
@@ -133,6 +130,8 @@ static cache_obj_t *ClockOracle_insert(cache_t *cache, const request_t *req) {
133130 cache_obj_t * obj = cache_insert_base (cache , req );
134131 prepend_obj_to_head (& params -> q_head , & params -> q_tail , obj );
135132
133+ /* new objects start with visited bit clear */
134+ obj -> clock .freq = 0 ;
136135 obj -> next_access_vtime = req -> next_access_vtime ;
137136
138137 return obj ;
@@ -145,23 +144,21 @@ static cache_obj_t *ClockOracle_to_evict(cache_t *cache, const request_t *req) {
145144}
146145
147146/**
148- * @brief evict using oracle information
147+ * @brief evict using oracle + visited bit
149148 *
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.
149+ * Scan from the tail. An object is reinserted only if BOTH:
150+ * 1. visited bit is set (freq >= 1)
151+ * 2. next_access_vtime - current_vtime <= cache_size / miss_ratio
154152 *
155- * Objects with next_access_vtime == INT64_MAX (no future access) are always
156- * evicted.
153+ * On reinsertion, the visited bit is cleared.
154+ * Objects failing either condition are evicted.
157155 */
158156static void ClockOracle_evict (cache_t * cache , const request_t * req ) {
159157 ClockOracle_params_t * params =
160158 (ClockOracle_params_t * )cache -> eviction_params ;
161159
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) */
160+ /* threshold = cache_size / miss_ratio = cache_size * n_req / n_miss
161+ * when n_miss == 0, use cache_size as the threshold */
165162 int64_t threshold ;
166163 if (params -> n_miss > 0 ) {
167164 threshold = (int64_t )((double )cache -> cache_size * (double )cache -> n_req /
@@ -170,23 +167,31 @@ static void ClockOracle_evict(cache_t *cache, const request_t *req) {
170167 threshold = cache -> cache_size ;
171168 }
172169
173- /* scan at most n_obj objects to avoid infinite loop */
174- int64_t n_scanned = 0 ;
170+
175171 cache_obj_t * obj_to_evict = params -> q_tail ;
172+ int64_t n_scanned = 0 ;
176173 while (obj_to_evict != NULL && n_scanned < cache -> n_obj ) {
177- int64_t reuse_dist = obj_to_evict -> next_access_vtime - cache -> n_req ;
178174 n_scanned ++ ;
179175
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 ;
176+ bool no_future_access = (obj_to_evict -> next_access_vtime == -1 ||
177+ obj_to_evict -> next_access_vtime == INT64_MAX );
178+ bool visited = (obj_to_evict -> clock .freq >= 1 );
179+ int64_t reuse_dist = obj_to_evict -> next_access_vtime - cache -> n_req ;
180+ bool within_threshold = (!no_future_access && reuse_dist <= threshold );
181+
182+ /* reinsert only if visited AND within threshold */
183+ if (visited && within_threshold ) {
184+ /* clear visited bit, reinsert to head */
185+ obj_to_evict -> clock .freq = 0 ;
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 ;
190+ continue ;
183191 }
184192
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 ;
193+ /* evict: either not visited, no future access, or too far away */
194+ break ;
190195 }
191196
192197 /* safety: if everything was reinserted, evict the tail */
0 commit comments