381 lines
12 KiB
Python
Executable File
381 lines
12 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Benchmark suite for 600 glyphs with 152 superpowers.
|
|
|
|
Tests:
|
|
1. Superpower loading performance
|
|
2. Assignment algorithm performance
|
|
3. Telemetry emission performance
|
|
4. Memory usage
|
|
5. Throughput under load
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
import json
|
|
from pathlib import Path
|
|
from typing import List, Dict
|
|
|
|
# Optional: memory profiler
|
|
try:
|
|
import memory_profiler
|
|
HAS_MEMORY_PROFILER = True
|
|
except ImportError:
|
|
HAS_MEMORY_PROFILER = False
|
|
|
|
sys.path.insert(0, str(Path.cwd()))
|
|
|
|
from glyphs.superpower_registry import load_all_superpowers, super_stats, get_superpower, calculate_boost
|
|
from glyphs.superpower_assigner import assign_superpowers, assign_all_glyphs, calculate_power_count
|
|
from glyphs.specialized_types import get_specialized_type, get_type_config
|
|
from integrations.fedmart.glyph_telemetry import emit_glyph_activation, GlyphActivationEvent
|
|
|
|
|
|
def benchmark_superpower_loading():
|
|
"""Benchmark 1: Superpower loading performance."""
|
|
print("\n=== Benchmark 1: Superpower Loading ===")
|
|
|
|
start = time.perf_counter()
|
|
load_all_superpowers()
|
|
load_time = time.perf_counter() - start
|
|
|
|
stats = super_stats()
|
|
|
|
print(f" Loaded {stats['total']} superpowers")
|
|
print(f" Load time: {load_time*1000:.2f}ms")
|
|
print(f" Throughput: {stats['total']/load_time:.0f} superpowers/sec")
|
|
|
|
return {
|
|
"load_time_ms": load_time * 1000,
|
|
"throughput": stats['total'] / load_time,
|
|
}
|
|
|
|
|
|
def benchmark_assignment_single():
|
|
"""Benchmark 2: Single glyph assignment performance."""
|
|
print("\n=== Benchmark 2: Single Glyph Assignment ===")
|
|
|
|
metrics = {
|
|
"power": 75,
|
|
"resonance": 70,
|
|
"stability": 65,
|
|
"connectivity": 80,
|
|
"affinity": 72,
|
|
}
|
|
|
|
# Warm up
|
|
for i in range(10):
|
|
assign_superpowers(f"G{i+1:03d}", metrics)
|
|
|
|
# Benchmark
|
|
iterations = 100
|
|
start = time.perf_counter()
|
|
|
|
for i in range(iterations):
|
|
glyph_id = f"G{(i % 600) + 1:03d}"
|
|
assign_superpowers(glyph_id, metrics)
|
|
|
|
elapsed = time.perf_counter() - start
|
|
per_assignment = elapsed / iterations * 1000
|
|
|
|
print(f" {iterations} assignments")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Per assignment: {per_assignment:.2f}ms")
|
|
print(f" Throughput: {iterations/elapsed:.0f} assignments/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"per_assignment_ms": per_assignment,
|
|
"throughput": iterations / elapsed,
|
|
}
|
|
|
|
|
|
def benchmark_assignment_all_glyphs():
|
|
"""Benchmark 3: All 600 glyphs assignment."""
|
|
print("\n=== Benchmark 3: All 600 Glyphs Assignment ===")
|
|
|
|
# Load glyphs
|
|
with open('/home/dave/superdave/glyphs/supercharged_glyphs.json') as f:
|
|
data = json.load(f)
|
|
|
|
glyphs = data.get("glyphs", [])
|
|
|
|
# Benchmark
|
|
start = time.perf_counter()
|
|
|
|
for glyph in glyphs:
|
|
glyph_id = glyph.get("id", "")
|
|
metrics = glyph.get("originalMetrics", {})
|
|
category = glyph.get("category", "")
|
|
|
|
# Re-assign to test performance
|
|
assign_superpowers(glyph_id, metrics, "", category)
|
|
|
|
elapsed = time.perf_counter() - start
|
|
per_glyph = elapsed / len(glyphs) * 1000
|
|
|
|
print(f" {len(glyphs)} glyphs")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Per glyph: {per_glyph:.2f}ms")
|
|
print(f" Throughput: {len(glyphs)/elapsed:.0f} glyphs/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"per_glyph_ms": per_glyph,
|
|
"throughput": len(glyphs) / elapsed,
|
|
}
|
|
|
|
|
|
def benchmark_telemetry_emission():
|
|
"""Benchmark 4: Telemetry emission performance."""
|
|
print("\n=== Benchmark 4: Telemetry Emission ===")
|
|
|
|
from integrations.fedmart.glyph_telemetry import get_adapter, GlyphActivationEvent
|
|
|
|
metrics = {
|
|
"power": 75,
|
|
"resonance": 70,
|
|
"stability": 65,
|
|
"connectivity": 80,
|
|
}
|
|
|
|
# Get adapter in local mode
|
|
adapter = get_adapter(local_mode=True)
|
|
|
|
# Benchmark local mode
|
|
iterations = 100
|
|
start = time.perf_counter()
|
|
|
|
for i in range(iterations):
|
|
glyph_id = f"G{(i % 600) + 1:03d}"
|
|
superpower_ids = [1, 2, 3, 4, 5]
|
|
|
|
event = GlyphActivationEvent(glyph_id, superpower_ids, "frost_steel_stabilizer", metrics)
|
|
adapter.emit_glyph_activation(event)
|
|
|
|
elapsed = time.perf_counter() - start
|
|
per_emit = elapsed / iterations * 1000
|
|
|
|
print(f" {iterations} emissions (local mode)")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Per emission: {per_emit:.2f}ms")
|
|
print(f" Throughput: {iterations/elapsed:.0f} emissions/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"per_emit_ms": per_emit,
|
|
"throughput": iterations / elapsed,
|
|
}
|
|
|
|
|
|
def benchmark_power_boost_calculation():
|
|
"""Benchmark 5: Power boost calculation."""
|
|
print("\n=== Benchmark 5: Power Boost Calculation ===")
|
|
|
|
# Benchmark
|
|
iterations = 1000
|
|
start = time.perf_counter()
|
|
|
|
for i in range(iterations):
|
|
superpower_ids = list(range(1, (i % 25) + 1))
|
|
calculate_boost(superpower_ids)
|
|
|
|
elapsed = time.perf_counter() - start
|
|
per_calc = elapsed / iterations * 1000
|
|
|
|
print(f" {iterations} calculations")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Per calculation: {per_calc:.2f}ms")
|
|
print(f" Throughput: {iterations/elapsed:.0f} calculations/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"per_calc_ms": per_calc,
|
|
"throughput": iterations / elapsed,
|
|
}
|
|
|
|
|
|
def benchmark_specialized_type_assignment():
|
|
"""Benchmark 6: Specialized type assignment."""
|
|
print("\n=== Benchmark 6: Specialized Type Assignment ===")
|
|
|
|
metrics = {
|
|
"power": 75,
|
|
"resonance": 70,
|
|
"stability": 65,
|
|
"connectivity": 80,
|
|
"affinity": 72,
|
|
}
|
|
|
|
# Benchmark
|
|
iterations = 600
|
|
start = time.perf_counter()
|
|
|
|
for i in range(iterations):
|
|
glyph_id = f"G{i+1:03d}"
|
|
get_specialized_type(glyph_id, metrics)
|
|
|
|
elapsed = time.perf_counter() - start
|
|
per_call = elapsed / iterations * 1000
|
|
|
|
print(f" {iterations} type assignments")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Per assignment: {per_call:.2f}ms")
|
|
print(f" Throughput: {iterations/elapsed:.0f} assignments/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"per_call_ms": per_call,
|
|
"throughput": iterations / elapsed,
|
|
}
|
|
|
|
|
|
def benchmark_memory_usage():
|
|
"""Benchmark 7: Memory usage."""
|
|
print("\n=== Benchmark 7: Memory Usage ===")
|
|
|
|
if not HAS_MEMORY_PROFILER:
|
|
print(" memory_profiler not installed, skipping detailed memory analysis")
|
|
# Estimate based on data size
|
|
import os
|
|
path = Path("/home/dave/superdave/glyphs/superpowers.json")
|
|
size_mb = path.stat().st_size / 1024 / 1024
|
|
print(f" Superpowers JSON size: {size_mb:.2f} MB")
|
|
print(f" Estimated memory: ~{size_mb*2:.2f} MB (parsed)")
|
|
return {
|
|
"peak_memory_mb": size_mb * 2,
|
|
"json_size_mb": size_mb,
|
|
}
|
|
|
|
# Get baseline
|
|
from memory_profiler import memory_usage
|
|
|
|
# Measure loading
|
|
def load_superpowers():
|
|
load_all_superpowers()
|
|
|
|
mem_usage = memory_usage(load_superpowers, interval=0.1, timeout=5)
|
|
peak_mem = max(mem_usage) - min(mem_usage)
|
|
|
|
print(f" Peak memory increase: {peak_mem:.2f} MB")
|
|
print(f" Superpowers in memory: {len(get_superpower(1))} bytes (sample)")
|
|
|
|
return {
|
|
"peak_memory_mb": peak_mem,
|
|
}
|
|
|
|
|
|
def benchmark_concurrent_load():
|
|
"""Benchmark 8: Concurrent load simulation."""
|
|
print("\n=== Benchmark 8: Concurrent Load Simulation ===")
|
|
|
|
import concurrent.futures
|
|
|
|
metrics = {
|
|
"power": 75,
|
|
"resonance": 70,
|
|
"stability": 65,
|
|
"connectivity": 80,
|
|
}
|
|
|
|
def assign_glyph(glyph_id):
|
|
return assign_superpowers(glyph_id, metrics)
|
|
|
|
# Concurrent assignment
|
|
start = time.perf_counter()
|
|
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
|
|
futures = [
|
|
executor.submit(assign_glyph, f"G{i+1:03d}")
|
|
for i in range(600)
|
|
]
|
|
results = [f.result() for f in futures]
|
|
|
|
elapsed = time.perf_counter() - start
|
|
|
|
print(f" 600 glyphs (4 workers)")
|
|
print(f" Total time: {elapsed*1000:.2f}ms")
|
|
print(f" Throughput: {600/elapsed:.0f} glyphs/sec")
|
|
|
|
return {
|
|
"total_time_ms": elapsed * 1000,
|
|
"throughput": 600 / elapsed,
|
|
}
|
|
|
|
|
|
def run_all_benchmarks():
|
|
"""Run all benchmarks and report results."""
|
|
print("=" * 70)
|
|
print("GLYPH SUPERPOWER BENCHMARK SUITE")
|
|
print("=" * 70)
|
|
|
|
benchmarks = [
|
|
("Superpower Loading", benchmark_superpower_loading),
|
|
("Single Assignment", benchmark_assignment_single),
|
|
("All Glyphs Assignment", benchmark_assignment_all_glyphs),
|
|
("Telemetry Emission", benchmark_telemetry_emission),
|
|
("Power Boost Calc", benchmark_power_boost_calculation),
|
|
("Specialized Type", benchmark_specialized_type_assignment),
|
|
("Memory Usage", benchmark_memory_usage),
|
|
("Concurrent Load", benchmark_concurrent_load),
|
|
]
|
|
|
|
results = {}
|
|
|
|
for name, bench_func in benchmarks:
|
|
try:
|
|
results[name] = bench_func()
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
results[name] = {"error": str(e)}
|
|
|
|
# Summary
|
|
print("\n" + "=" * 70)
|
|
print("BENCHMARK SUMMARY")
|
|
print("=" * 70)
|
|
|
|
print("\nPerformance Metrics:")
|
|
if "Superpower Loading" in results:
|
|
print(f" Loading: {results['Superpower Loading'].get('load_time_ms', 0):.2f}ms")
|
|
if "Single Assignment" in results:
|
|
print(f" Single Assignment: {results['Single Assignment'].get('per_assignment_ms', 0):.2f}ms")
|
|
if "All Glyphs Assignment" in results:
|
|
print(f" All Glyphs: {results['All Glyphs Assignment'].get('total_time_ms', 0):.2f}ms")
|
|
if "Telemetry Emission" in results:
|
|
print(f" Telemetry: {results['Telemetry Emission'].get('per_emit_ms', 0):.2f}ms")
|
|
if "Power Boost Calc" in results:
|
|
print(f" Boost Calc: {results['Power Boost Calc'].get('per_calc_ms', 0):.2f}ms")
|
|
if "Concurrent Load" in results:
|
|
print(f" Concurrent: {results['Concurrent Load'].get('total_time_ms', 0):.2f}ms")
|
|
|
|
print("\nThroughput:")
|
|
if "Superpower Loading" in results:
|
|
print(f" Loading: {results['Superpower Loading'].get('throughput', 0):.0f} superpowers/sec")
|
|
if "Single Assignment" in results:
|
|
print(f" Assignment: {results['Single Assignment'].get('throughput', 0):.0f} assignments/sec")
|
|
if "All Glyphs Assignment" in results:
|
|
print(f" All Glyphs: {results['All Glyphs Assignment'].get('throughput', 0):.0f} glyphs/sec")
|
|
if "Concurrent Load" in results:
|
|
print(f" Concurrent: {results['Concurrent Load'].get('throughput', 0):.0f} glyphs/sec (4 workers)")
|
|
|
|
if "Memory Usage" in results:
|
|
print(f"\nMemory:")
|
|
print(f" Peak increase: {results['Memory Usage'].get('peak_memory_mb', 0):.2f} MB")
|
|
|
|
print("\n" + "=" * 70)
|
|
print("✅ Benchmark complete")
|
|
print("=" * 70)
|
|
|
|
return results
|
|
|
|
|
|
if __name__ == "__main__":
|
|
results = run_all_benchmarks()
|
|
|
|
# Save results
|
|
output_path = Path("/home/dave/superdave/benchmark/benchmark_results.json")
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(output_path, 'w') as f:
|
|
json.dump(results, f, indent=2)
|
|
|
|
print(f"\nResults saved to {output_path}") |