examples/performance/cache_comparison.py
#!/usr/bin/env python3
"""
Comparaison et contrôle fin des différents backends de cache.
Montre comment le même code peut avoir plusieurs entrées de cache
selon les options de compilation (optimize, tco_enabled).
"""
import time
from catnip import Catnip
from catnip.cache import CatnipCache, MemoryCache, CacheKey, CacheType
def benchmark_parsing(name, catnip, code, iterations=100):
"""Benchmark le parsing avec ou sans cache."""
start = time.perf_counter()
for _ in range(iterations):
catnip.parse(code)
elapsed = time.perf_counter() - start
avg = elapsed / iterations * 1000 # en ms
print(f" {name}: {avg:.3f} ms/parse (total: {elapsed:.2f}s)")
return avg
def main():
print("⇒ Contrôle fin et Comparaison des Caches")
# Code de test complexe
code = """
quicksort = (arr) => {
if arr.length <= 1 {
arr
} else {
pivot = arr[0]
rest = arr[1:]
left = rest.filter(x => x < pivot)
right = rest.filter(x => x >= pivot)
quicksort(left) + [pivot] + quicksort(right)
}
}
quicksort([5, 2, 8, 1, 9, 3, 7, 4, 6])
"""
# 1. Démonstration du contrôle fin
print("1. Contrôle fin : même code, clés différentes\n")
cache = CatnipCache(backend=MemoryCache())
# Créer différentes clés pour le même code
keys = [
CacheKey(code, CacheType.AST, optimize=True, tco_enabled=True),
CacheKey(code, CacheType.AST, optimize=True, tco_enabled=False),
CacheKey(code, CacheType.AST, optimize=False, tco_enabled=True),
CacheKey(code, CacheType.AST, optimize=False, tco_enabled=False),
]
print(" Clés générées pour le même code:")
for i, key in enumerate(keys, 1):
print(f" {i}. optimize={key.optimize}, tco={key.tco_enabled}")
print(f" → {key.to_string()}")
print()
# 2. Benchmark avec et sans cache
print("2. Benchmark : impact du cache\n")
# Sans cache
catnip_no_cache = Catnip()
time_no_cache = benchmark_parsing("Sans cache", catnip_no_cache, code, iterations=50)
# Avec cache mémoire
catnip_cached = Catnip(cache=cache)
# Premier passage pour remplir le cache
catnip_cached.parse(code)
time_cached = benchmark_parsing("Avec cache", catnip_cached, code, iterations=50)
speedup = time_no_cache / time_cached
print(f"\n Accélération: {speedup:.1f}x plus rapide avec cache\n")
# 3. Comparaison des backends
print("3. Statistiques des différents backends\n")
backends = {
"Memory": MemoryCache(max_size=100),
}
# Tester DiskCache si disponible
try:
from catnip.cache import DiskCache
import tempfile
tmpdir = tempfile.mkdtemp(prefix="catnip_bench_")
backends["Disk"] = DiskCache(directory=tmpdir)
except ImportError:
print(" (DiskCache non disponible - pip install diskcache)")
# Tester Redis si disponible
try:
from catnip.cache import RedisCache
backends["Redis"] = RedisCache(prefix="catnip_bench")
except (ImportError, Exception):
print(" (Redis non disponible)")
print()
# Benchmark chaque backend
results = {}
for name, backend in backends.items():
cache = CatnipCache(backend=backend, cache_ast=True)
catnip = Catnip(cache=cache)
# Remplir le cache
catnip.parse(code)
# Mesurer
avg = benchmark_parsing(f"{name:8s}", catnip, code, iterations=50)
results[name] = avg
# Stats
stats = cache.stats()
print(f" Stats: {stats.get('hit_rate', 'N/A')}")
# Nettoyer
if hasattr(backend, 'close'):
backend.close()
print("\n4. Résumé des performances\n")
sorted_results = sorted(results.items(), key=lambda x: x[1])
for name, avg in sorted_results:
print(f" {name:8s}: {avg:.3f} ms/parse")
fastest = sorted_results[0][1]
print(f"\n Le plus rapide: {sorted_results[0][0]} ({fastest:.3f} ms)")
if __name__ == "__main__":
main()