Generate a summary report from benchmark results.
(results: list[BenchmarkResult], output_path: str = None)
| 851 | |
| 852 | |
| 853 | def generate_report(results: list[BenchmarkResult], output_path: str = None): |
| 854 | """Generate a summary report from benchmark results.""" |
| 855 | print("\n" + "=" * 70) |
| 856 | print("BENCHMARK REPORT") |
| 857 | print("=" * 70) |
| 858 | |
| 859 | for result in results: |
| 860 | print(f"\n{result.scenario}") |
| 861 | print("-" * 40) |
| 862 | print(f" Config: {json.dumps(result.config, indent=None)}") |
| 863 | print(f" Requests: {result.successful}/{result.total_requests} " |
| 864 | f"({result.failed} failed)") |
| 865 | print(f" Duration: {result.duration_sec}s") |
| 866 | print(f" Throughput: {result.requests_per_sec:.1f} req/s") |
| 867 | print(f" Latency (ms):") |
| 868 | print(f" min: {result.latency_ms.min:.2f}") |
| 869 | print(f" p50: {result.latency_ms.p50:.2f}") |
| 870 | print(f" p95: {result.latency_ms.p95:.2f}") |
| 871 | print(f" p99: {result.latency_ms.p99:.2f}") |
| 872 | print(f" max: {result.latency_ms.max:.2f}") |
| 873 | print(f" mean: {result.latency_ms.mean:.2f} " |
| 874 | f"(stddev: {result.latency_ms.stddev:.2f})") |
| 875 | |
| 876 | if result.errors: |
| 877 | print(f" Errors (first {len(result.errors)}):") |
| 878 | for err in result.errors[:3]: |
| 879 | print(f" - {err[:80]}") |
| 880 | |
| 881 | if output_path: |
| 882 | output_data = { |
| 883 | "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"), |
| 884 | "results": [r.to_dict() for r in results], |
| 885 | } |
| 886 | with open(output_path, 'w') as f: |
| 887 | json.dump(output_data, f, indent=2) |
| 888 | print(f"\nResults saved to: {output_path}") |
| 889 | |
| 890 | |
| 891 | def main(): |