class Indicator(object): def __init__(self): self.cms = CMS(5000) self.hinter_sum = 0 self.hinter_count = 0 self.freqs = Counter() # Alternatively use SpaceSaving def record(self, key): hint = self.cms.frequancy(key) self.hinter_sum += hint self.hinter_count += 1 self.cms.increment(key) self.freqs[key] += 1 def get_hint(self): return self.hinter_sum / self.hinter_count def est_skew(self): top_k = [(i, log(k[1])) for i, k in zip(range(1, 71), self.freqs.most_common(70))] return -stats.linregress(top_k)[0] def get_indicator(self): skew = self.est_skew() return (self.get_hint() * ((1 - skew**3) if skew < 1 else 0)) / 15.0 def reset(self): self.hinter_sum = 0 self.hinter_count = 0 self.freqs.clear()
class WTinyLFU(Policy): def __init__(self, maximum_size, window_percentage=1): super().__init__(maximum_size) self.data = {} self.cms = CMS(maximum_size) self.sentinel_window = Node() # LRU self.sentinel_probation = Node() # SLRU self.sentinel_protected = Node() # SLRU self.max_window_size = (self.maximum_size * window_percentage) // 100 max_main = self.maximum_size - self.max_window_size self.max_protected = max_main * 4 // 5 self.size_window = 0 self.size_protected = 0 def record(self, key, size=1): self.cms.increment(key) node = self.data.get(key) if not node: self.misses += 1 new_node = Node(key, Node.Status.Window) new_node.append_to_tail(self.sentinel_window) self.data[key] = new_node self.size_window += 1 if self.size_window > self.max_window_size: self.evict() return False else: self.hits += 1 node.remove() if node.status == Node.Status.Window: node.append_to_tail(self.sentinel_window) elif node.status == Node.Status.Probation: node.status = Node.Status.Protected node.append_to_tail(self.sentinel_protected) self.size_protected += 1 self.demote_protected() elif node.status == Node.Status.Protected: node.append_to_tail(self.sentinel_protected) return True def demote_protected(self): if self.size_protected > self.max_protected: demote = self.sentinel_protected.next_node demote.remove() demote.status = Node.Status.Probation demote.append_to_tail(self.sentinel_probation) self.size_protected -= 1 def evict(self): candidate = self.sentinel_window.next_node candidate.remove() self.size_window -= 1 candidate.status = Node.Status.Probation candidate.append_to_tail(self.sentinel_probation) if len(self.data) > self.maximum_size: victim = self.sentinel_probation.next_node evicted = victim if self.cms.frequancy( candidate.data) > self.cms.frequancy( victim.data) else candidate del self.data[evicted.data] evicted.remove()