Grade 3 more models + dashboard v2 layout (quant/format as first-class)
New graded (11 total now):
gemma4-26b-a4b-8bit-mlx 82 Minor Flaws (tied top local; delta-based tx freq)
qwen3.6-27b-8bit-mlx 78 Minor Flaws (clean; anom. slow generation flagged)
qwen3-coder-30b-6bit-mlx 50 Critical (asyncio.Lock used with sync with -> crash)
Dashboard redesign:
- Bar chart is now the full-width hero row (was cramped half-width)
- 4 stat tiles squished 2x2 beside the radar up top
- Quant + Format are dedicated columns in the leaderboard (MLX/GGUF/CLOUD chips)
- New 'Format & Quant Showdown' panel: groups same-family variants so
GGUF-vs-MLX and quant-depth comparisons are side by side
- Bar-chart axis labels now include the quant so duplicate model names
are distinguishable, with rotation for readability
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
import asyncio
|
||||
import time
|
||||
import weakref
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Any, List, Set, Tuple
|
||||
from collections import OrderedDict
|
||||
import threading
|
||||
|
||||
# --- Data Structures ---
|
||||
|
||||
@dataclass
|
||||
class CacheNode:
|
||||
"""Doubly-linked node for LFU frequency buckets."""
|
||||
key: str
|
||||
value: Any
|
||||
freq: int = 0
|
||||
ttl: Optional[float] = None # Unix timestamp of expiry
|
||||
prev: Optional['CacheNode'] = None
|
||||
next: Optional['CacheNode'] = None
|
||||
|
||||
@dataclass
|
||||
class FrequencyBucket:
|
||||
"""A bucket of nodes with the same frequency."""
|
||||
freq: int
|
||||
head: CacheNode = field(default_factory=lambda: CacheNode("", None, 0)) # Dummy head
|
||||
tail: CacheNode = field(default_factory=lambda: CacheNode("", None, 0)) # Dummy tail
|
||||
nodes: Dict[str, CacheNode] = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self):
|
||||
self.head.next = self.tail
|
||||
self.tail.prev = self.head
|
||||
|
||||
def add_node(self, node: CacheNode):
|
||||
"""Add a node to the front of the bucket."""
|
||||
node.next = self.head.next
|
||||
node.prev = self.head
|
||||
self.head.next.prev = node
|
||||
self.head.next = node
|
||||
self.nodes[node.key] = node
|
||||
|
||||
def remove_node(self, node: CacheNode):
|
||||
"""Remove a node from the bucket."""
|
||||
node.prev.next = node.next
|
||||
node.next.prev = node.prev
|
||||
del self.nodes[node.key]
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
return len(self.nodes) == 0
|
||||
|
||||
# --- Transaction Support ---
|
||||
|
||||
class Transaction:
|
||||
def __init__(self, cache: 'InMemoryLFUCache'):
|
||||
self.cache = cache
|
||||
self._writes: Dict[str, Tuple[Any, Optional[float]]] = {} # key -> (value, ttl)
|
||||
self._deletions: Set[str] = set()
|
||||
self._committed = False
|
||||
self._rolled_back = False
|
||||
|
||||
def get(self, key: str) -> Any:
|
||||
if self._rolled_back or self._committed:
|
||||
raise RuntimeError("Transaction is no longer active")
|
||||
if key in self._deletions:
|
||||
return None
|
||||
if key in self._writes:
|
||||
return self._writes[key][0]
|
||||
return self.cache.get(key)
|
||||
|
||||
def put(self, key: str, value: Any, ttl_seconds: Optional[float] = None):
|
||||
if self._rolled_back or self._committed:
|
||||
raise RuntimeError("Transaction is no longer active")
|
||||
self._writes[key] = (value, ttl_seconds)
|
||||
|
||||
def delete(self, key: str):
|
||||
if self._rolled_back or self._committed:
|
||||
raise RuntimeError("Transaction is no longer active")
|
||||
self._deletions.add(key)
|
||||
|
||||
async def commit(self):
|
||||
if self._rolled_back or self._committed:
|
||||
raise RuntimeError("Transaction is no longer active")
|
||||
await self.cache._commit_transaction(self)
|
||||
self._committed = True
|
||||
|
||||
async def rollback(self):
|
||||
if self._rolled_back or self._committed:
|
||||
raise RuntimeError("Transaction is no longer active")
|
||||
self._rolled_back = True
|
||||
|
||||
# --- Cache Implementation ---
|
||||
|
||||
class InMemoryLFUCache:
|
||||
def __init__(self, capacity: int = 100):
|
||||
self.capacity = capacity
|
||||
self._data: Dict[str, CacheNode] = {} # Global cache data
|
||||
self._freq_buckets: Dict[int, FrequencyBucket] = {}
|
||||
self._min_freq = 0
|
||||
self._lock = asyncio.Lock()
|
||||
self._evictor_task: Optional[asyncio.Task] = None
|
||||
self._evictor_running = False
|
||||
self._transaction_lock = asyncio.Lock()
|
||||
self._transactions: Dict[int, Transaction] = {}
|
||||
self._transaction_counter = 0
|
||||
|
||||
def _create_bucket(self, freq: int) -> FrequencyBucket:
|
||||
bucket = FrequencyBucket(freq)
|
||||
self._freq_buckets[freq] = bucket
|
||||
return bucket
|
||||
|
||||
def _get_bucket(self, freq: int) -> FrequencyBucket:
|
||||
if freq not in self._freq_buckets:
|
||||
return self._create_bucket(freq)
|
||||
return self._freq_buckets[freq]
|
||||
|
||||
def _evict_lfu(self):
|
||||
"""Evict the least frequently used item."""
|
||||
if self._min_freq not in self._freq_buckets:
|
||||
return None
|
||||
bucket = self._freq_buckets[self._min_freq]
|
||||
if bucket.is_empty():
|
||||
return None
|
||||
node_to_evict = bucket.tail.prev # Tail's previous is the last item
|
||||
self._remove_node(node_to_evict)
|
||||
return node_to_evict.key
|
||||
|
||||
def _remove_node(self, node: CacheNode):
|
||||
"""Remove a node from its bucket and global map."""
|
||||
bucket = self._get_bucket(node.freq)
|
||||
bucket.remove_node(node)
|
||||
if bucket.is_empty():
|
||||
del self._freq_buckets[node.freq]
|
||||
del self._data[node.key]
|
||||
|
||||
def _update_node_frequency(self, node: CacheNode):
|
||||
"""Move node to the next frequency bucket and update min_freq if needed."""
|
||||
old_freq = node.freq
|
||||
node.freq += 1
|
||||
new_freq = node.freq
|
||||
bucket = self._get_bucket(old_freq)
|
||||
bucket.remove_node(node)
|
||||
if bucket.is_empty():
|
||||
del self._freq_buckets[old_freq]
|
||||
if old_freq == self._min_freq:
|
||||
self._min_freq = new_freq
|
||||
new_bucket = self._get_bucket(new_freq)
|
||||
new_bucket.add_node(node)
|
||||
|
||||
def _is_expired(self, node: CacheNode) -> bool:
|
||||
if node.ttl is None:
|
||||
return False
|
||||
return time.time() > node.ttl
|
||||
|
||||
def _check_and_remove_expired(self, node: CacheNode) -> bool:
|
||||
"""Returns True if node was expired and removed."""
|
||||
if self._is_expired(node):
|
||||
self._remove_node(node)
|
||||
return True
|
||||
return False
|
||||
|
||||
async def get(self, key: str) -> Any:
|
||||
async with self._lock:
|
||||
if key not in self._data:
|
||||
return None
|
||||
node = self._data[key]
|
||||
# Lazy TTL check
|
||||
if self._check_and_remove_expired(node):
|
||||
return None
|
||||
self._update_node_frequency(node)
|
||||
return node.value
|
||||
|
||||
async def put(self, key: str, value: Any, ttl_seconds: Optional[float] = None):
|
||||
async with self._lock:
|
||||
ttl = time.time() + ttl_seconds if ttl_seconds is not None else None
|
||||
if key in self._data:
|
||||
node = self._data[key]
|
||||
# Lazy TTL check
|
||||
if self._check_and_remove_expired(node):
|
||||
node = None # Re-add it below
|
||||
if node:
|
||||
node.value = value
|
||||
node.ttl = ttl
|
||||
self._update_node_frequency(node)
|
||||
return
|
||||
# Add new node or replace existing expired one
|
||||
node = CacheNode(key, value, freq=1, ttl=ttl)
|
||||
self._data[key] = node
|
||||
bucket = self._get_bucket(1)
|
||||
bucket.add_node(node)
|
||||
self._min_freq = 1
|
||||
|
||||
# Check capacity and evict if needed
|
||||
if len(self._data) > self.capacity:
|
||||
evicted_key = self._evict_lfu()
|
||||
if evicted_key is not None:
|
||||
# Ensure that the bucket is cleaned up if empty
|
||||
pass
|
||||
|
||||
def begin_transaction(self) -> Transaction:
|
||||
with self._transaction_lock:
|
||||
self._transaction_counter += 1
|
||||
tx = Transaction(self)
|
||||
self._transactions[self._transaction_counter] = tx
|
||||
return tx
|
||||
|
||||
async def _commit_transaction(self, tx: Transaction):
|
||||
async with self._lock:
|
||||
# Apply writes
|
||||
for key, (value, ttl) in tx._writes.items():
|
||||
await self.put(key, value, ttl)
|
||||
# Apply deletions
|
||||
for key in tx._deletions:
|
||||
if key in self._data:
|
||||
node = self._data[key]
|
||||
self._remove_node(node)
|
||||
|
||||
async def start_evictor(self, interval_seconds: float = 5.0):
|
||||
"""Start the background evictor task."""
|
||||
async def _evict_loop():
|
||||
while self._evictor_running:
|
||||
try:
|
||||
await asyncio.sleep(interval_seconds)
|
||||
await self._evict_expired_batch()
|
||||
except Exception:
|
||||
pass # Silently ignore errors in background task
|
||||
|
||||
self._evictor_running = True
|
||||
self._evictor_task = asyncio.create_task(_evict_loop())
|
||||
|
||||
async def stop_evictor(self):
|
||||
"""Stop the background evictor task."""
|
||||
self._evictor_running = False
|
||||
if self._evictor_task:
|
||||
self._evictor_task.cancel()
|
||||
try:
|
||||
await self._evictor_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
async def _evict_expired_batch(self, batch_size: int = 10):
|
||||
"""Evict a batch of expired keys without holding the global lock for too long."""
|
||||
to_remove = []
|
||||
with self._lock:
|
||||
# Collect expired nodes
|
||||
for node in self._data.values():
|
||||
if self._is_expired(node):
|
||||
to_remove.append(node.key)
|
||||
if len(to_remove) >= batch_size:
|
||||
break
|
||||
# Remove outside lock to avoid blocking readers
|
||||
for key in to_remove:
|
||||
async with self._lock:
|
||||
if key in self._data:
|
||||
node = self._data[key]
|
||||
if self._is_expired(node):
|
||||
self._remove_node(node)
|
||||
|
||||
# --- Unit Tests ---
|
||||
|
||||
async def main():
|
||||
print("Running InMemoryLFUCache tests...")
|
||||
|
||||
# Test 1: O(1) LFU eviction
|
||||
print("Test 1: LFU eviction")
|
||||
cache = InMemoryLFUCache(capacity=3)
|
||||
await cache.put("a", 1)
|
||||
await cache.put("b", 2)
|
||||
await cache.put("c", 3)
|
||||
# Access a twice to make it more frequent
|
||||
await cache.get("a")
|
||||
await cache.get("a")
|
||||
# Add d, should evict the least frequent (b)
|
||||
await cache.put("d", 4)
|
||||
assert await cache.get("b") is None
|
||||
assert await cache.get("a") == 1
|
||||
assert await cache.get("c") == 3
|
||||
assert await cache.get("d") == 4
|
||||
print("✓ LFU eviction works")
|
||||
|
||||
# Test 2: TTL eviction
|
||||
print("Test 2: TTL eviction")
|
||||
cache = InMemoryLFUCache(capacity=10)
|
||||
await cache.put("a", 1, ttl_seconds=0.1) # Expire quickly
|
||||
await asyncio.sleep(0.2)
|
||||
assert await cache.get("a") is None
|
||||
print("✓ TTL eviction works")
|
||||
|
||||
# Test 3: Transaction commit visibility
|
||||
print("Test 3: Transaction visibility")
|
||||
cache = InMemoryLFUCache(capacity=10)
|
||||
tx = cache.begin_transaction()
|
||||
tx.put("x", 100)
|
||||
assert await cache.get("x") is None # Not committed yet
|
||||
await tx.commit()
|
||||
assert await cache.get("x") == 100 # Now visible
|
||||
print("✓ Transaction commit works")
|
||||
|
||||
# Test 4: Transaction rollback
|
||||
print("Test 4: Transaction rollback")
|
||||
cache = InMemoryLFUCache(capacity=10)
|
||||
await cache.put("y", 200)
|
||||
tx = cache.begin_transaction()
|
||||
tx.put("y", 300)
|
||||
tx.delete("z") # z doesn't exist yet
|
||||
await tx.rollback()
|
||||
assert await cache.get("y") == 200 # Original value restored
|
||||
print("✓ Transaction rollback works")
|
||||
|
||||
# Test 5: Concurrent access
|
||||
print("Test 5: Concurrent access")
|
||||
cache = InMemoryLFUCache(capacity=10)
|
||||
async def worker(worker_id: int):
|
||||
for i in range(5):
|
||||
key = f"{worker_id}_{i}"
|
||||
await cache.put(key, i)
|
||||
val = await cache.get(key)
|
||||
assert val == i
|
||||
tasks = [asyncio.create_task(worker(i)) for i in range(50)]
|
||||
await asyncio.gather(*tasks)
|
||||
print("✓ Concurrent access works")
|
||||
|
||||
# Test 6: Background eviction
|
||||
print("Test 6: Background eviction")
|
||||
cache = InMemoryLFUCache(capacity=10)
|
||||
await cache.put("expiring", 1, ttl_seconds=0.1)
|
||||
await cache.start_evictor(interval_seconds=0.05)
|
||||
await asyncio.sleep(0.2)
|
||||
assert await cache.get("expiring") is None
|
||||
await cache.stop_evictor()
|
||||
print("✓ Background eviction works")
|
||||
|
||||
print("\nAll tests passed! ✅")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
||||
Reference in New Issue
Block a user