83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import time
|
|
|
|
from .engine import OutputSettings, RealtimeEngine
|
|
from .mapping_xml import load_mapping
|
|
from .models import PatternParams, SceneState
|
|
from .patterns import pattern_ids
|
|
from .renderer import FastRenderer
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Benchmark the Infinity_Vis_1 render core.")
|
|
parser.add_argument(
|
|
"--mapping",
|
|
type=Path,
|
|
default=Path(__file__).resolve().parents[2] / "sample_data" / "infinity_mirror_mapping_clean.xml",
|
|
help="Path to the XML mapping file.",
|
|
)
|
|
parser.add_argument("--frames", type=int, default=600, help="Frames per pattern.")
|
|
parser.add_argument("--pattern", type=str, default="", help="Benchmark a single pattern id.")
|
|
parser.add_argument(
|
|
"--mode",
|
|
type=str,
|
|
default="render",
|
|
choices=["render", "engine"],
|
|
help="Benchmark only the renderer or the new runtime engine loop.",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
mapping = load_mapping(args.mapping)
|
|
renderer = FastRenderer(mapping)
|
|
stats = renderer.stats()
|
|
|
|
patterns = [args.pattern] if args.pattern else pattern_ids()
|
|
print(f"Mapping: {mapping.name}")
|
|
print(f"Tiles: {stats.tile_count} | Controllers: {stats.controller_count} | LEDs: {stats.total_leds}")
|
|
|
|
for pattern_id in patterns:
|
|
scene = SceneState(pattern_id=pattern_id, params=PatternParams(), tempo_bpm=120.0)
|
|
if args.mode == "engine":
|
|
fps, preview_frames, changed_frames = _benchmark_engine(mapping, scene, max(1, args.frames))
|
|
print(
|
|
f"{pattern_id:16s} {fps:9.1f} engine fps "
|
|
f"| preview {preview_frames:4d} | changed controllers {changed_frames:4d}"
|
|
)
|
|
else:
|
|
fps = _benchmark_renderer(renderer, scene, max(1, args.frames))
|
|
print(f"{pattern_id:16s} {fps:9.1f} render fps")
|
|
|
|
|
|
def _benchmark_renderer(renderer: FastRenderer, scene: SceneState, frames: int) -> float:
|
|
start = time.perf_counter()
|
|
for frame_index in range(frames):
|
|
renderer.render(scene, timestamp=start + frame_index / 60.0)
|
|
elapsed = time.perf_counter() - start
|
|
return frames / elapsed if elapsed > 0 else 0.0
|
|
|
|
|
|
def _benchmark_engine(mapping, scene: SceneState, frames: int) -> tuple[float, int, int]:
|
|
engine = RealtimeEngine(
|
|
mapping,
|
|
scene=scene,
|
|
settings=OutputSettings(output_fps=60.0, preview_fps=12.0, delta_sending=True, keepalive_seconds=0.35),
|
|
)
|
|
start = time.perf_counter()
|
|
preview_frames = 0
|
|
changed_frames = 0
|
|
for frame_index in range(frames):
|
|
result = engine.tick(now=start + frame_index / 60.0)
|
|
if result.preview_snapshot is not None:
|
|
preview_frames += 1
|
|
changed_frames += len(result.changed_payloads)
|
|
elapsed = time.perf_counter() - start
|
|
fps = frames / elapsed if elapsed > 0 else 0.0
|
|
return fps, preview_frames, changed_frames
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|