From 2c257b9808ed3360281400202319a4e6d979f25e Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Tue, 1 Sep 2015 23:05:53 -0700 Subject: [PATCH] Do not promote HIR if already at the top of the stack Comparing multi1 trace between this version and the reference C output, it seems that a HIR to LIR promotion does not occur if the block is already at the top of the stack. This occurs when a HIR is accessed multiple times in a row and added to the stack on a non-resident miss. I don't see where this is stated in the paper, though. Most traces now have matching miss counts. A few, like sprite, are off by one. So this needs to be looked at next. --- .../cache/simulator/policy/irr/LirsPolicy.java | 13 ++++++++++++- .../simulator/policy/two_queue/EdenQueuePolicy.java | 10 ++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/irr/LirsPolicy.java b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/irr/LirsPolicy.java index faa53c9708..eb3fa39e13 100644 --- a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/irr/LirsPolicy.java +++ b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/irr/LirsPolicy.java @@ -119,9 +119,10 @@ private void onResidentHir(Node node) { policyStats.recordHit(); boolean isInStack = node.isInStack(StackType.S); + boolean isTop = node.isStackTop(StackType.S); node.moveToTop(StackType.S); - if (isInStack) { + if (isInStack && !isTop) { sizeHot++; node.status = Status.LIR; node.removeFrom(StackType.Q); @@ -354,6 +355,16 @@ public boolean isInStack(StackType stackType) { } } + public boolean isStackTop(StackType stackType) { + if (stackType == StackType.S) { + return (headS.nextS == this); + } else if (stackType == StackType.Q) { + return (headQ.nextQ == this); + } else { + throw new IllegalArgumentException(); + } + } + public void moveToTop(StackType stackType) { if (isInStack(stackType)) { removeFrom(stackType); diff --git a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/EdenQueuePolicy.java b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/EdenQueuePolicy.java index 9e3f771fad..3f51311333 100644 --- a/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/EdenQueuePolicy.java +++ b/simulator/src/main/java/com/github/benmanes/caffeine/cache/simulator/policy/two_queue/EdenQueuePolicy.java @@ -35,7 +35,9 @@ * A new entry starts in the eden queue and remain there as long as it has high temporal locality. * Eventually an entry will slip from the end of the eden queue onto the front of the main queue. If * the main queue is already full, then TinyLfu determines whether to evict the newly admitted entry - * or the victim entry chosen by main queue's policy. Both the eden and main spaces use LRU queues. + * or the victim entry chosen by main queue's policy. The eden queue allows an entry that has a high + * temporal locality and a low frequency of use to reside the cache until it has poor recency, at + * which point it is discarded by TinyLfu. Both the eden and main spaces use LRU queues. *

* Scan resistance is achieved by means of the eden queue. Transient data will pass through from the * eden queue and not be accepted into the main queue. Responsiveness is maintained by the main @@ -94,7 +96,7 @@ public void record(Comparable key) { } } - /** Evicts while the map exceeds the maximum capacity. */ + /** Evicts if the map exceeds the maximum capacity. */ private void evict() { if (sizeEden <= maxEden) { return; @@ -109,13 +111,13 @@ private void evict() { sizeMain++; if (sizeMain > maxMain) { - policyStats.recordEviction(); - Node victim = headMain.next; Node evict = admittor.admit(candidate.key, victim.key) ? victim : candidate; data.remove(evict.key); evict.remove(); sizeMain--; + + policyStats.recordEviction(); } }