13–18% fewer misses than LRU
Miss ratio on a Zipf workload
α = 1, one panel per cache size as a share of the working set. Lower is better.
An eviction algorithm simpler than LRU, for web caches
One queue, one pointer and one bit per object. A hit only sets a bit, so it takes no lock, and replacing LRU with SIEVE in a cache library takes about 20 lines of code.
SIEVE runs in
How it works
New objects join the head of a single queue. When the cache is full, a hand walks from the tail toward the head: objects that were used since it last passed keep their place, and the first one that was not is evicted.
Objects stay in the order they arrived. Nothing is ever moved back to the head, so the queue never needs reordering.
A hit marks the object as visited. If the bit is already set there is nothing to do at all: no lock and no pointer updates on the hot path.
To make room, the hand walks from the tail toward the head, clearing the bits of visited objects, and evicts the first one that was not visited. Past the head, it wraps back to the tail.
CLOCK moves a surviving object back to the head with the new ones. SIEVE leaves it where it is, so popular objects settle near the tail and new ones that are not reused leave quickly.
Results
On 1,559 traces with 247 billion requests, SIEVE beats every state-of-the-art eviction algorithm on more than 45% of them, and it does so with less code and more throughput than LRU.
13–18% fewer misses than LRU
α = 1, one panel per cache size as a share of the working set. Lower is better.
A better building block
Mean miss ratio reduction from FIFO across traces, before and after SIEVE replaces each algorithm’s LRU or FIFO queue. Higher is better.
About an hour of work
In four popular cache libraries, tests not included.
| Library | Language | Lines | Hours |
|---|---|---|---|
| groupcache | Go | 21 | <1 |
| mnemonist | JavaScript | 12 | 1 |
| lru-rs | Rust | 16 | 1 |
| lru-dict | Python + C | 21 | <1 |
Charts redrawn from the figures in the paper and the blog post.
Use it
Pick a library in your language, or replay your own traces against SIEVE in libCacheSim.
# request x, queue T, size C, hand p
if x in T: # hit
x.visited = true
else: # miss
if |T| == C: # cache full
obj = p or tail(T)
while obj.visited:
obj.visited = false
obj = obj.prev or tail(T)
p = obj.prev
discard obj # eviction
insert x at head(T)
x.visited = false # insertion Adoption
Databases, DNS servers, storage engines and web frameworks run SIEVE. Each entry links to the code, pull request or docs that show it.
Open pull requests.
Carnegie Mellon University, Parallel Data Laboratory, Emory University, SimBioSys Lab, Meta, Google, AWS, Microsoft, CloudLab, NSF, the Sloan Foundation and VMware.
Meta, Tencent, Wikimedia and Twitter.
We would love to list you, and to hear how it went.
More from cacheMon: S3-FIFO · libCacheSim · cachemon.org