Skip to content

Commit 8809f6b

Browse files
committed
Add benchmark script
Signed-off-by: Rafal Leszko <rafal@livepeer.org>
1 parent 7933116 commit 8809f6b

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

BENCHMARK.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Pipeline FPS Benchmark Results
2+
3+
Generated: 2025-11-17 13:05:37
4+
5+
**GPU:** NVIDIA GeForce RTX 5090
6+
7+
---
8+
9+
## Results
10+
11+
| Pipeline | Average FPS | Status |
12+
|----------|-------------|--------|
13+
| krea_realtime_video | 7.21 | ✓ Success |
14+
| longlive | 10.81 | ✓ Success |
15+
| streamdiffusionv2 | 15.40 | ✓ Success |

benchmark.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Script to run test.py for each pipeline and collect average FPS statistics.
4+
Results are stored in a Markdown file.
5+
"""
6+
7+
import subprocess
8+
import re
9+
import sys
10+
import os
11+
from pathlib import Path
12+
from datetime import datetime
13+
from typing import Dict, Optional
14+
15+
try:
16+
import torch
17+
except ImportError:
18+
torch = None
19+
20+
# Define pipelines with their test.py paths
21+
PIPELINES = {
22+
"longlive": "pipelines/longlive/test.py",
23+
"krea_realtime_video": "pipelines/krea_realtime_video/test.py",
24+
"streamdiffusionv2": "pipelines/streamdiffusionv2/test.py",
25+
}
26+
27+
OUTPUT_FILE = "BENCHMARK.md"
28+
29+
30+
def get_gpu_name() -> str:
31+
"""
32+
Get the GPU name using PyTorch or nvidia-smi.
33+
Returns 'Unknown' if GPU info cannot be retrieved.
34+
"""
35+
if torch is not None and torch.cuda.is_available():
36+
try:
37+
return torch.cuda.get_device_name(0)
38+
except Exception:
39+
pass
40+
41+
# Fallback to nvidia-smi
42+
try:
43+
result = subprocess.run(
44+
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
45+
capture_output=True,
46+
text=True,
47+
timeout=5,
48+
)
49+
if result.returncode == 0 and result.stdout.strip():
50+
return result.stdout.strip().split('\n')[0]
51+
except Exception:
52+
pass
53+
54+
return "Unknown"
55+
56+
57+
def extract_avg_fps(output: str) -> Optional[float]:
58+
"""
59+
Extract average FPS from test.py output.
60+
Looks for line like: "FPS - Avg: 12.34, Max: 15.67, Min: 10.12"
61+
"""
62+
# Pattern to match "FPS - Avg: X.XX"
63+
pattern = r"FPS - Avg:\s+([\d.]+)"
64+
match = re.search(pattern, output)
65+
if match:
66+
try:
67+
return float(match.group(1))
68+
except ValueError:
69+
return None
70+
return None
71+
72+
73+
def run_test(pipeline_name: str, test_path: str) -> Optional[float]:
74+
"""
75+
Run test.py for a pipeline and return the average FPS.
76+
Returns None if the test fails or FPS cannot be extracted.
77+
"""
78+
print(f"\n{'='*60}")
79+
print(f"Running test for pipeline: {pipeline_name}")
80+
print(f"Test file: {test_path}")
81+
print(f"{'='*60}\n")
82+
83+
test_file = Path(test_path)
84+
if not test_file.exists():
85+
print(f"ERROR: Test file not found: {test_path}")
86+
return None
87+
88+
try:
89+
# Run the test.py file as a module to handle relative imports correctly
90+
# The test files use relative imports (e.g., from .pipeline import ...)
91+
test_module = test_file.stem # 'test' without .py
92+
93+
# Run using python -m to handle imports correctly
94+
# Need to run from project root so imports work
95+
result = subprocess.run(
96+
[sys.executable, "-m", f"pipelines.{pipeline_name}.{test_module}"],
97+
cwd=Path.cwd(),
98+
capture_output=True,
99+
text=True,
100+
timeout=3600, # 1 hour timeout
101+
env={**os.environ, "PYTHONPATH": str(Path.cwd())},
102+
)
103+
104+
# Print stdout and stderr for debugging
105+
if result.stdout:
106+
print(result.stdout)
107+
if result.stderr:
108+
print("STDERR:", result.stderr, file=sys.stderr)
109+
110+
if result.returncode != 0:
111+
print(f"ERROR: Test failed with return code {result.returncode}")
112+
return None
113+
114+
# Extract average FPS from output
115+
avg_fps = extract_avg_fps(result.stdout)
116+
if avg_fps is None:
117+
# Try stderr as well
118+
avg_fps = extract_avg_fps(result.stderr)
119+
120+
if avg_fps is not None:
121+
print(f"\n✓ Successfully extracted average FPS: {avg_fps:.2f}")
122+
else:
123+
print(f"\n⚠ Warning: Could not extract average FPS from output")
124+
125+
return avg_fps
126+
127+
except subprocess.TimeoutExpired:
128+
print(f"ERROR: Test timed out after 1 hour")
129+
return None
130+
except Exception as e:
131+
print(f"ERROR: Exception while running test: {e}")
132+
return None
133+
134+
135+
def write_results_to_markdown(results: Dict[str, Optional[float]], output_file: str, gpu_name: str):
136+
"""
137+
Write FPS results to a Markdown file.
138+
"""
139+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
140+
141+
with open(output_file, "w") as f:
142+
f.write("# Pipeline FPS Benchmark Results\n\n")
143+
f.write(f"Generated: {timestamp}\n\n")
144+
f.write(f"**GPU:** {gpu_name}\n\n")
145+
f.write("---\n\n")
146+
f.write("## Results\n\n")
147+
f.write("| Pipeline | Average FPS | Status |\n")
148+
f.write("|----------|-------------|--------|\n")
149+
150+
for pipeline_name, avg_fps in sorted(results.items()):
151+
if avg_fps is not None:
152+
f.write(f"| {pipeline_name} | {avg_fps:.2f} | ✓ Success |\n")
153+
else:
154+
f.write(f"| {pipeline_name} | N/A | ✗ Failed/No Data |\n")
155+
156+
print(f"\n{'='*60}")
157+
print(f"Results written to: {output_file}")
158+
print(f"{'='*60}\n")
159+
160+
161+
def main():
162+
"""
163+
Main function to run all pipeline tests and collect results.
164+
"""
165+
print("Pipeline FPS Benchmark Runner")
166+
print("=" * 60)
167+
print(f"Testing {len(PIPELINES)} pipelines...")
168+
169+
# Get GPU name
170+
gpu_name = get_gpu_name()
171+
print(f"GPU: {gpu_name}\n")
172+
173+
results = {}
174+
175+
for pipeline_name, test_path in PIPELINES.items():
176+
avg_fps = run_test(pipeline_name, test_path)
177+
results[pipeline_name] = avg_fps
178+
179+
# Write results to Markdown file
180+
write_results_to_markdown(results, OUTPUT_FILE, gpu_name)
181+
182+
# Print summary
183+
print("\n" + "=" * 60)
184+
print("SUMMARY")
185+
print("=" * 60)
186+
for pipeline_name, avg_fps in sorted(results.items()):
187+
status = f"{avg_fps:.2f} FPS" if avg_fps is not None else "Failed/No Data"
188+
print(f" {pipeline_name:30s}: {status}")
189+
print("=" * 60)
190+
191+
192+
if __name__ == "__main__":
193+
main()

0 commit comments

Comments
 (0)